summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJINMEI Tatuya <jinmei@isc.org>2010-09-28 04:16:01 +0200
committerJINMEI Tatuya <jinmei@isc.org>2010-09-28 04:16:01 +0200
commit0ab28241aa457eb968cf933e990db2d925568089 (patch)
tree7b4adf2d6b27b56a688753b1fdf992d4293cb191
parent- separated Rcode class declarations and definitions in different files (diff)
downloadkea-0ab28241aa457eb968cf933e990db2d925568089.tar.xz
kea-0ab28241aa457eb968cf933e990db2d925568089.zip
provided documentation
git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac351@3039 e5f2f494-b856-4b98-b285-d166d9295462
-rw-r--r--src/lib/dns/opcode.cc7
-rw-r--r--src/lib/dns/opcode.h132
-rw-r--r--src/lib/dns/python/opcode_python.cc4
-rw-r--r--src/lib/dns/python/rcode_python.cc433
-rw-r--r--src/lib/dns/python/tests/opcode_python_test.py2
-rw-r--r--src/lib/dns/python/tests/rcode_python_test.py137
-rw-r--r--src/lib/dns/rcode.cc103
-rw-r--r--src/lib/dns/rcode.h348
-rw-r--r--src/lib/dns/tests/opcode_unittest.cc6
-rw-r--r--src/lib/dns/tests/rcode_unittest.cc134
10 files changed, 1274 insertions, 32 deletions
diff --git a/src/lib/dns/opcode.cc b/src/lib/dns/opcode.cc
index e868a11d39..814112387c 100644
--- a/src/lib/dns/opcode.cc
+++ b/src/lib/dns/opcode.cc
@@ -44,10 +44,13 @@ const char *opcodetext[] = {
"RESERVED14",
"RESERVED15"
};
+
+// OPCODEs are 4-bit values. So 15 is the highest code.
+const uint8_t MAX_OPCODE = 15;
}
-Opcode::Opcode(const uint16_t code) : code_(static_cast<CodeValue>(code)) {
- if (code > MAX_CODE) {
+Opcode::Opcode(const uint8_t code) : code_(static_cast<CodeValue>(code)) {
+ if (code > MAX_OPCODE) {
isc_throw(OutOfRange,
"DNS Opcode is too large to construct: " << code);
}
diff --git a/src/lib/dns/opcode.h b/src/lib/dns/opcode.h
index 878d1522e1..c5499c1b9f 100644
--- a/src/lib/dns/opcode.h
+++ b/src/lib/dns/opcode.h
@@ -29,62 +29,148 @@ namespace dns {
/// \brief The \c Opcode class objects represent standard OPCODEs
/// of the header section of DNS messages as defined in RFC1035.
///
-/// Note: since there are only 15 possible values, it may make more sense to
-/// simply define an enum type to represent these values.
-///
-/// Constant objects are defined for standard flags.
+/// This is a straightforward value class encapsulating the OPCODE code
+/// values. Since OPCODEs are 4-bit integers that are used in limited
+/// places and it's unlikely that new code values will be assigned, we could
+/// represent them as simple integers (via constant variables or enums).
+/// However, we define a separate class so that we can benefit from C++
+/// type safety as much as possible. For convenience we also provide
+/// an enum type for standard OPCDE values, but it is generally advisable
+/// to handle OPCODEs through this class. In fact, public interfaces of
+/// this library uses this class to pass or return OPCODEs instead of the
+/// bare code values.
class Opcode {
public:
+ /// Constants for standard OPCODE values.
enum CodeValue {
- QUERY_CODE = 0,
- IQUERY_CODE = 1,
- STATUS_CODE = 2,
- RESERVED3_CODE = 3,
- NOTIFY_CODE = 4,
- UPDATE_CODE = 5,
- RESERVED6_CODE = 6,
- RESERVED7_CODE = 7,
- RESERVED8_CODE = 8,
- RESERVED9_CODE = 9,
- RESERVED10_CODE = 10,
- RESERVED11_CODE = 11,
- RESERVED12_CODE = 12,
- RESERVED13_CODE = 13,
- RESERVED14_CODE = 14,
- RESERVED15_CODE = 15,
- MAX_CODE = 15
+ QUERY_CODE = 0, ///< 0: Standard query (RFC1035)
+ IQUERY_CODE = 1, ///< 1: Inverse query (RFC1035)
+ STATUS_CODE = 2, ///< 2: Server status request (RFC1035)
+ RESERVED3_CODE = 3, ///< 3: Reserved for future use (RFC1035)
+ NOTIFY_CODE = 4, ///< 4: Notify (RFC1996)
+ UPDATE_CODE = 5, ///< 5: Dynamic update (RFC2136)
+ RESERVED6_CODE = 6, ///< 6: Reserved for future use (RFC1035)
+ RESERVED7_CODE = 7, ///< 7: Reserved for future use (RFC1035)
+ RESERVED8_CODE = 8, ///< 8: Reserved for future use (RFC1035)
+ RESERVED9_CODE = 9, ///< 9: Reserved for future use (RFC1035)
+ RESERVED10_CODE = 10, ///< 10: Reserved for future use (RFC1035)
+ RESERVED11_CODE = 11, ///< 11: Reserved for future use (RFC1035)
+ RESERVED12_CODE = 12, ///< 12: Reserved for future use (RFC1035)
+ RESERVED13_CODE = 13, ///< 13: Reserved for future use (RFC1035)
+ RESERVED14_CODE = 14, ///< 14: Reserved for future use (RFC1035)
+ RESERVED15_CODE = 15 ///< 15: Reserved for future use (RFC1035)
};
- explicit Opcode(const uint16_t code);
+
+ /// \name Constructors and Destructor
+ ///
+ /// We use the default versions of destructor, copy constructor,
+ /// and assignment operator.
+ ///
+ /// The default constructor is hidden as a result of defining the other
+ /// constructors. This is intentional; we don't want to allow an
+ /// \c Opcode object to be constructed with an invalid state.
+ //@{
+ /// \brief Constructor from the code value.
+ ///
+ /// Since OPCODEs are 4-bit values, parameters larger than 15 are invalid.
+ /// If \c code is larger than 15 an exception of class \c isc::OutOfRange
+ /// will be thrown.
+ ///
+ /// \param code The underlying code value of the \c Opcode.
+ explicit Opcode(const uint8_t code);
+ //@}
+
+ /// \brief Returns the \c Opcode code value.
+ ///
+ /// This method never throws an exception.
+ ///
+ /// \return The underlying code value corresponding to the \c Opcode.
CodeValue getCode() const { return (code_); }
/// \brief Return true iff two Opcodes are equal.
+ ///
+ /// Two Opcodes are equal iff their type codes are equal.
+ ///
+ /// This method never throws an exception.
+ ///
+ /// \param other the \c Opcode object to compare against.
+ /// \return true if the two Opcodes are equal; otherwise false.
bool equals(const Opcode& other) const
{ return (code_ == other.code_); }
+ /// \brief Same as \c equals().
bool operator==(const Opcode& other) const { return (equals(other)); }
-
+
+ /// \brief Return true iff two Opcodes are not equal.
+ ///
+ /// This method never throws an exception.
+ ///
+ /// \param other the \c Opcode object to compare against.
+ /// \return true if the two Opcodes are not equal; otherwise false.
bool nequals(const Opcode& other) const
{ return (code_ != other.code_); }
+ /// \brief Same as \c nequals().
bool operator!=(const Opcode& other) const { return (nequals(other)); }
+ /// \brief Convert the \c Opcode to a string.
+ ///
+ /// This method returns a string representation of the "mnemonic' used
+ /// for the enum and constant objects. For example, the string for
+ /// code value 0 is "QUERY", etc.
+ ///
+ /// If resource allocation for the string fails, a corresponding standard
+ /// exception will be thrown.
+ ///
+ /// \return A string representation of the \c Opcode.
std::string toText() const;
+ /// A constant object for the QUERY Opcode.
static const Opcode& QUERY();
+
+ /// A constant object for the IQUERY Opcode.
static const Opcode& IQUERY();
+
+ /// A constant object for the STATUS Opcode.
static const Opcode& STATUS();
+
+ /// A constant object for a reserved (code 3) Opcode.
static const Opcode& RESERVED3();
+
+ /// A constant object for the NOTIFY Opcode.
static const Opcode& NOTIFY();
+
+ /// A constant object for the UPDATE Opcode.
static const Opcode& UPDATE();
+
+ /// A constant object for a reserved (code 6) Opcode.
static const Opcode& RESERVED6();
+
+ /// A constant object for a reserved (code 7) Opcode.
static const Opcode& RESERVED7();
+
+ /// A constant object for a reserved (code 8) Opcode.
static const Opcode& RESERVED8();
+
+ /// A constant object for a reserved (code 9) Opcode.
static const Opcode& RESERVED9();
+
+ /// A constant object for a reserved (code 10) Opcode.
static const Opcode& RESERVED10();
+
+ /// A constant object for a reserved (code 11) Opcode.
static const Opcode& RESERVED11();
+
+ /// A constant object for a reserved (code 12) Opcode.
static const Opcode& RESERVED12();
+
+ /// A constant object for a reserved (code 13) Opcode.
static const Opcode& RESERVED13();
+
+ /// A constant object for a reserved (code 14) Opcode.
static const Opcode& RESERVED14();
+
+ /// A constant object for a reserved (code 15) Opcode.
static const Opcode& RESERVED15();
private:
CodeValue code_;
diff --git a/src/lib/dns/python/opcode_python.cc b/src/lib/dns/python/opcode_python.cc
index e2d830305f..72b6d3d9c3 100644
--- a/src/lib/dns/python/opcode_python.cc
+++ b/src/lib/dns/python/opcode_python.cc
@@ -160,7 +160,7 @@ PyTypeObject opcode_type = {
int
Opcode_init(s_Opcode* const self, PyObject* args) {
uint16_t code = 0;
- if (PyArg_ParseTuple(args, "h", &code)) {
+ if (PyArg_ParseTuple(args, "b", &code)) {
try {
self->opcode = new Opcode(code);
self->static_code = false;
@@ -386,8 +386,6 @@ initModulePart_Opcode(PyObject* mod) {
Py_BuildValue("h", Opcode::RESERVED14_CODE));
addClassVariable(opcode_type, "RESERVED15_CODE",
Py_BuildValue("h", Opcode::RESERVED15_CODE));
- addClassVariable(opcode_type, "MAX_CODE",
- Py_BuildValue("h", Opcode::MAX_CODE));
return (true);
}
diff --git a/src/lib/dns/python/rcode_python.cc b/src/lib/dns/python/rcode_python.cc
new file mode 100644
index 0000000000..b2174ada5a
--- /dev/null
+++ b/src/lib/dns/python/rcode_python.cc
@@ -0,0 +1,433 @@
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/rcode.h>
+
+using namespace isc::dns;
+
+//
+// Declaration of the custom exceptions (None for this class)
+
+//
+// Definition of the classes
+//
+
+// For each class, we need a struct, a helper functions (init, destroy,
+// and static wrappers around the methods we export), a list of methods,
+// and a type description
+
+namespace {
+//
+// Rcode
+//
+
+// We added a helper variable static_code here
+// Since we can create Rcodes dynamically with Rcode(int), but also
+// use the static globals (Rcode::NOERROR() etc), we use this
+// variable to see if the code came from one of the latter, in which
+// case Rcode_destroy should not free it (the other option is to
+// allocate new Rcodes for every use of the static ones, but this
+// seems more efficient).
+class s_Rcode : public PyObject {
+public:
+ s_Rcode() : rcode(NULL), static_code(false) {}
+ const Rcode* rcode;
+ bool static_code;
+};
+
+int Rcode_init(s_Rcode* const self, PyObject* args);
+void Rcode_destroy(s_Rcode* const self);
+
+PyObject* Rcode_getCode(const s_Rcode* const self);
+PyObject* Rcode_getExtendedCode(const s_Rcode* const self);
+PyObject* Rcode_toText(const s_Rcode* const self);
+PyObject* Rcode_str(PyObject* const self);
+PyObject* Rcode_NOERROR(const s_Rcode* self);
+PyObject* Rcode_FORMERR(const s_Rcode* self);
+PyObject* Rcode_SERVFAIL(const s_Rcode* self);
+PyObject* Rcode_NXDOMAIN(const s_Rcode* self);
+PyObject* Rcode_NOTIMP(const s_Rcode* self);
+PyObject* Rcode_REFUSED(const s_Rcode* self);
+PyObject* Rcode_YXDOMAIN(const s_Rcode* self);
+PyObject* Rcode_YXRRSET(const s_Rcode* self);
+PyObject* Rcode_NXRRSET(const s_Rcode* self);
+PyObject* Rcode_NOTAUTH(const s_Rcode* self);
+PyObject* Rcode_NOTZONE(const s_Rcode* self);
+PyObject* Rcode_RESERVED11(const s_Rcode* self);
+PyObject* Rcode_RESERVED12(const s_Rcode* self);
+PyObject* Rcode_RESERVED13(const s_Rcode* self);
+PyObject* Rcode_RESERVED14(const s_Rcode* self);
+PyObject* Rcode_RESERVED15(const s_Rcode* self);
+PyObject* Rcode_BADVERS(const s_Rcode* self);
+PyObject* Rcode_richcmp(const s_Rcode* const self,
+ const s_Rcode* const other, int op);
+
+PyMethodDef Rcode_methods[] = {
+ { "get_code", reinterpret_cast<PyCFunction>(Rcode_getCode), METH_NOARGS,
+ "Returns the code value" },
+ { "get_extended_code",
+ reinterpret_cast<PyCFunction>(Rcode_getExtendedCode), METH_NOARGS,
+ "Returns the upper 8-bit part of the extended code value" },
+ { "to_text", reinterpret_cast<PyCFunction>(Rcode_toText), METH_NOARGS,
+ "Returns the text representation" },
+ { "NOERROR", reinterpret_cast<PyCFunction>(Rcode_NOERROR),
+ METH_NOARGS | METH_STATIC, "Creates a NOERROR Rcode" },
+ { "FORMERR", reinterpret_cast<PyCFunction>(Rcode_FORMERR),
+ METH_NOARGS | METH_STATIC, "Creates a FORMERR Rcode" },
+ { "SERVFAIL", reinterpret_cast<PyCFunction>(Rcode_SERVFAIL),
+ METH_NOARGS | METH_STATIC, "Creates a SERVFAIL Rcode" },
+ { "NXDOMAIN", reinterpret_cast<PyCFunction>(Rcode_NXDOMAIN),
+ METH_NOARGS | METH_STATIC, "Creates a NXDOMAIN Rcode" },
+ { "NOTIMP", reinterpret_cast<PyCFunction>(Rcode_NOTIMP),
+ METH_NOARGS | METH_STATIC, "Creates a NOTIMP Rcode" },
+ { "REFUSED", reinterpret_cast<PyCFunction>(Rcode_REFUSED),
+ METH_NOARGS | METH_STATIC, "Creates a REFUSED Rcode" },
+ { "YXDOMAIN", reinterpret_cast<PyCFunction>(Rcode_YXDOMAIN),
+ METH_NOARGS | METH_STATIC, "Creates a YXDOMAIN Rcode" },
+ { "YXRRSET", reinterpret_cast<PyCFunction>(Rcode_YXRRSET),
+ METH_NOARGS | METH_STATIC, "Creates a YYRRSET Rcode" },
+ { "NXRRSET", reinterpret_cast<PyCFunction>(Rcode_NXRRSET),
+ METH_NOARGS | METH_STATIC, "Creates a NXRRSET Rcode" },
+ { "NOTAUTH", reinterpret_cast<PyCFunction>(Rcode_NOTAUTH),
+ METH_NOARGS | METH_STATIC, "Creates a NOTAUTH Rcode" },
+ { "NOTZONE", reinterpret_cast<PyCFunction>(Rcode_NOTZONE),
+ METH_NOARGS | METH_STATIC, "Creates a NOTZONE Rcode" },
+ { "RESERVED11", reinterpret_cast<PyCFunction>(Rcode_RESERVED11),
+ METH_NOARGS | METH_STATIC, "Creates a RESERVED11 Rcode" },
+ { "RESERVED12", reinterpret_cast<PyCFunction>(Rcode_RESERVED12),
+ METH_NOARGS | METH_STATIC, "Creates a RESERVED12 Rcode" },
+ { "RESERVED13", reinterpret_cast<PyCFunction>(Rcode_RESERVED13),
+ METH_NOARGS | METH_STATIC, "Creates a RESERVED13 Rcode" },
+ { "RESERVED14", reinterpret_cast<PyCFunction>(Rcode_RESERVED14),
+ METH_NOARGS | METH_STATIC, "Creates a RESERVED14 Rcode" },
+ { "RESERVED15", reinterpret_cast<PyCFunction>(Rcode_RESERVED15),
+ METH_NOARGS | METH_STATIC, "Creates a RESERVED15 Rcode" },
+ { "BADVERS", reinterpret_cast<PyCFunction>(Rcode_BADVERS),
+ METH_NOARGS | METH_STATIC, "Creates a BADVERS Rcode" },
+ { NULL, NULL, 0, NULL }
+};
+
+PyTypeObject rcode_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "pydnspp.Rcode",
+ sizeof(s_Rcode), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)Rcode_destroy, // tp_dealloc
+ NULL, // tp_print
+ NULL, // tp_getattr
+ NULL, // tp_setattr
+ NULL, // tp_reserved
+ NULL, // tp_repr
+ NULL, // tp_as_number
+ NULL, // tp_as_sequence
+ NULL, // tp_as_mapping
+ NULL, // tp_hash
+ NULL, // tp_call
+ Rcode_str, // tp_str
+ NULL, // tp_getattro
+ NULL, // tp_setattro
+ NULL, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ "The Rcode class objects represent standard RCODEs"
+ "of the header section of DNS messages.",
+ NULL, // tp_traverse
+ NULL, // tp_clear
+ (richcmpfunc)Rcode_richcmp, // tp_richcompare
+ 0, // tp_weaklistoffset
+ NULL, // tp_iter
+ NULL, // tp_iternext
+ Rcode_methods, // tp_methods
+ NULL, // tp_members
+ NULL, // tp_getset
+ NULL, // tp_base
+ NULL, // tp_dict
+ NULL, // tp_descr_get
+ NULL, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)Rcode_init, // tp_init
+ NULL, // tp_alloc
+ PyType_GenericNew, // tp_new
+ NULL, // tp_free
+ NULL, // tp_is_gc
+ NULL, // tp_bases
+ NULL, // tp_mro
+ NULL, // tp_cache
+ NULL, // tp_subclasses
+ NULL, // tp_weaklist
+ NULL, // tp_del
+ 0 // tp_version_tag
+};
+
+int
+Rcode_init(s_Rcode* const self, PyObject* args) {
+ int code = 0;
+ int ext_code = 0;
+
+ if (PyArg_ParseTuple(args, "i", &code)) {
+ if (code < 0 || code > 0xffff) {
+ PyErr_SetString(PyExc_OverflowError, "Rcode out of range");
+ return (-1);
+ }
+ ext_code = -1;
+ } else if (PyArg_ParseTuple(args, "ii", &code, &ext_code)) {
+ if (code < 0 || code > 0xff || ext_code < 0 || ext_code > 0xff) {
+ PyErr_SetString(PyExc_OverflowError, "Rcode out of range");
+ return (-1);
+ }
+ } else {
+ PyErr_Clear();
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid arguments to Rcode constructor");
+ return (-1);
+ }
+ try {
+ if (ext_code == -1) {
+ self->rcode = new Rcode(code);
+ } else {
+ self->rcode = new Rcode(code, ext_code);
+ }
+ self->static_code = false;
+ } catch (const isc::OutOfRange& ex) {
+ PyErr_SetString(PyExc_OverflowError, ex.what());
+ return (-1);
+ } catch (...) {
+ PyErr_SetString(po_IscException, "Unexpected exception");
+ return (-1);
+ }
+ return (0);
+}
+
+void
+Rcode_destroy(s_Rcode* const self) {
+ // Depending on whether we created the rcode or are referring
+ // to a global one, we do or do not delete self->rcode here
+ if (!self->static_code) {
+ delete self->rcode;
+ }
+ self->rcode = NULL;
+ Py_TYPE(self)->tp_free(self);
+}
+
+PyObject*
+Rcode_getCode(const s_Rcode* const self) {
+ return (Py_BuildValue("I", self->rcode->getCode()));
+}
+
+PyObject*
+Rcode_getExtendedCode(const s_Rcode* const self) {
+ return (Py_BuildValue("I", self->rcode->getExtendedCode()));
+}
+
+PyObject*
+Rcode_toText(const s_Rcode* const self) {
+ return (Py_BuildValue("s", self->rcode->toText().c_str()));
+}
+
+PyObject*
+Rcode_str(PyObject* const self) {
+ // Simply call the to_text method we already defined
+ return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
+ const_cast<char*>("")));
+}
+
+PyObject*
+Rcode_createStatic(const Rcode& rcode) {
+ s_Rcode* ret = PyObject_New(s_Rcode, &rcode_type);
+ if (ret != NULL) {
+ ret->rcode = &rcode;
+ ret->static_code = true;
+ }
+ return (ret);
+}
+
+PyObject*
+Rcode_NOERROR(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::NOERROR()));
+}
+
+PyObject*
+Rcode_FORMERR(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::FORMERR()));
+}
+
+PyObject*
+Rcode_SERVFAIL(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::SERVFAIL()));
+}
+
+PyObject*
+Rcode_NXDOMAIN(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::NXDOMAIN()));
+}
+
+PyObject*
+Rcode_NOTIMP(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::NOTIMP()));
+}
+
+PyObject*
+Rcode_REFUSED(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::REFUSED()));
+}
+
+PyObject*
+Rcode_YXDOMAIN(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::YXDOMAIN()));
+}
+
+PyObject*
+Rcode_YXRRSET(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::YXRRSET()));
+}
+
+PyObject*
+Rcode_NXRRSET(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::NXRRSET()));
+}
+
+PyObject*
+Rcode_NOTAUTH(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::NOTAUTH()));
+}
+
+PyObject*
+Rcode_NOTZONE(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::NOTZONE()));
+}
+
+PyObject*
+Rcode_RESERVED11(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::RESERVED11()));
+}
+
+PyObject*
+Rcode_RESERVED12(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::RESERVED12()));
+}
+
+PyObject*
+Rcode_RESERVED13(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::RESERVED13()));
+}
+
+PyObject*
+Rcode_RESERVED14(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::RESERVED14()));
+}
+
+PyObject*
+Rcode_RESERVED15(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::RESERVED15()));
+}
+
+PyObject*
+Rcode_BADVERS(const s_Rcode* self UNUSED_PARAM) {
+ return (Rcode_createStatic(Rcode::BADVERS()));
+}
+
+PyObject*
+Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other,
+ const int op)
+{
+ bool c = false;
+
+ // Check for null and if the types match. If different type,
+ // simply return False
+ if (!other || (self->ob_type != other->ob_type)) {
+ Py_RETURN_FALSE;
+ }
+
+ // Only equals and not equals here, unorderable type
+ switch (op) {
+ case Py_LT:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
+ return (NULL);
+ case Py_LE:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
+ return (NULL);
+ case Py_EQ:
+ c = (*self->rcode == *other->rcode);
+ break;
+ case Py_NE:
+ c = (*self->rcode != *other->rcode);
+ break;
+ case Py_GT:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
+ return (NULL);
+ case Py_GE:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
+ return (NULL);
+ }
+ if (c)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_Rcode(PyObject* mod) {
+ // We initialize the static description object with PyType_Ready(),
+ // then add it to the module. This is not just a check! (leaving
+ // this out results in segmentation faults)
+ if (PyType_Ready(&rcode_type) < 0) {
+ return (false);
+ }
+ Py_INCREF(&rcode_type);
+ void* p = &rcode_type;
+ if (PyModule_AddObject(mod, "Rcode", static_cast<PyObject*>(p)) != 0) {
+ Py_DECREF(&rcode_type);
+ return (false);
+ }
+
+ addClassVariable(rcode_type, "NOERROR_CODE",
+ Py_BuildValue("h", Rcode::NOERROR_CODE));
+ addClassVariable(rcode_type, "FORMERR_CODE",
+ Py_BuildValue("h", Rcode::FORMERR_CODE));
+ addClassVariable(rcode_type, "SERVFAIL_CODE",
+ Py_BuildValue("h", Rcode::SERVFAIL_CODE));
+ addClassVariable(rcode_type, "NXDOMAIN_CODE",
+ Py_BuildValue("h", Rcode::NXDOMAIN_CODE));
+ addClassVariable(rcode_type, "NOTIMP_CODE",
+ Py_BuildValue("h", Rcode::NOTIMP_CODE));
+ addClassVariable(rcode_type, "REFUSED_CODE",
+ Py_BuildValue("h", Rcode::REFUSED_CODE));
+ addClassVariable(rcode_type, "YXDOMAIN_CODE",
+ Py_BuildValue("h", Rcode::YXDOMAIN_CODE));
+ addClassVariable(rcode_type, "YXRRSET_CODE",
+ Py_BuildValue("h", Rcode::YXRRSET_CODE));
+ addClassVariable(rcode_type, "NXRRSET_CODE",
+ Py_BuildValue("h", Rcode::NXRRSET_CODE));
+ addClassVariable(rcode_type, "NOTAUTH_CODE",
+ Py_BuildValue("h", Rcode::NOTAUTH_CODE));
+ addClassVariable(rcode_type, "NOTZONE_CODE",
+ Py_BuildValue("h", Rcode::NOTZONE_CODE));
+ addClassVariable(rcode_type, "RESERVED11_CODE",
+ Py_BuildValue("h", Rcode::RESERVED11_CODE));
+ addClassVariable(rcode_type, "RESERVED12_CODE",
+ Py_BuildValue("h", Rcode::RESERVED12_CODE));
+ addClassVariable(rcode_type, "RESERVED13_CODE",
+ Py_BuildValue("h", Rcode::RESERVED13_CODE));
+ addClassVariable(rcode_type, "RESERVED14_CODE",
+ Py_BuildValue("h", Rcode::RESERVED14_CODE));
+ addClassVariable(rcode_type, "RESERVED15_CODE",
+ Py_BuildValue("h", Rcode::RESERVED15_CODE));
+ addClassVariable(rcode_type, "BADVERS_CODE",
+ Py_BuildValue("h", Rcode::BADVERS_CODE));
+
+ return (true);
+}
+} // end of unnamed namespace
diff --git a/src/lib/dns/python/tests/opcode_python_test.py b/src/lib/dns/python/tests/opcode_python_test.py
index 2a51d6b084..84f449fc90 100644
--- a/src/lib/dns/python/tests/opcode_python_test.py
+++ b/src/lib/dns/python/tests/opcode_python_test.py
@@ -24,7 +24,7 @@ class OpcodeTest(unittest.TestCase):
def test_init(self):
self.assertRaises(TypeError, Opcode, "wrong")
self.assertEqual(Rcode(0).get_code(), 0)
- self.assertEqual(Rcode(Opcode.MAX_CODE).get_code(), 15)
+ self.assertEqual(Rcode(Opcode.RESERVED15_CODE).get_code(), 15)
self.assertRaises(OverflowError, Opcode, 16)
def test_constants(self):
diff --git a/src/lib/dns/python/tests/rcode_python_test.py b/src/lib/dns/python/tests/rcode_python_test.py
new file mode 100644
index 0000000000..3577f84b5c
--- /dev/null
+++ b/src/lib/dns/python/tests/rcode_python_test.py
@@ -0,0 +1,137 @@
+# Copyright (C) 2010 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Tests for the rcode part of the pydnspp module
+#
+
+import unittest
+from pydnspp import *
+
+class RcodeTest(unittest.TestCase):
+ def test_init(self):
+ self.assertRaises(TypeError, Rcode, "wrong")
+ self.assertRaises(OverflowError, Rcode, 65536)
+ self.assertEqual(Rcode(0).get_code(), 0)
+
+ self.assertEqual(0, Rcode(0).get_code())
+ self.assertEqual(0xfff, Rcode(0xfff).get_code()) # possible max code
+
+ # should fail on attempt of construction with an out of range code
+ self.assertRaises(OverflowError, Rcode, 0x1000)
+ self.assertRaises(OverflowError, Rcode, 0xffff)
+
+ # constructor with a pair of code portions
+ self.assertEqual(3, Rcode(Rcode.NXDOMAIN_CODE, 0).get_code())
+ self.assertEqual(Rcode.BADVERS_CODE, Rcode(0, 1).get_code())
+ self.assertEqual(0xfff, Rcode(0xf, 0xff).get_code())
+ self.assertRaises(OverflowError, Rcode, 0x10, 0xff)
+
+ def test_constants(self):
+ self.assertEqual(Rcode.NOERROR_CODE, Rcode(0).get_code())
+ self.assertEqual(Rcode.FORMERR_CODE, Rcode(1).get_code())
+ self.assertEqual(Rcode.NOTIMP_CODE, Rcode(4).get_code())
+ self.assertEqual(Rcode.REFUSED_CODE, Rcode(5).get_code())
+ self.assertEqual(Rcode.RESERVED15_CODE, Rcode(15).get_code())
+ self.assertEqual(Rcode.BADVERS_CODE, Rcode(16).get_code())
+
+ self.assertEqual(Rcode.NOERROR_CODE, Rcode.NOERROR().get_code())
+ self.assertEqual(Rcode.FORMERR_CODE, Rcode.FORMERR().get_code())
+ self.assertEqual(Rcode.NOTIMP_CODE, Rcode.NOTIMP().get_code())
+ self.assertEqual(Rcode.REFUSED_CODE, Rcode.REFUSED().get_code())
+ self.assertEqual(Rcode.RESERVED15_CODE, Rcode.RESERVED15().get_code())
+ self.assertEqual(Rcode.BADVERS_CODE, Rcode.BADVERS().get_code())
+
+ def test_get_code(self):
+ self.assertEqual(0, Rcode.NOERROR().get_code())
+ self.assertEqual(1, Rcode.FORMERR().get_code())
+ self.assertEqual(2, Rcode.SERVFAIL().get_code())
+ self.assertEqual(3, Rcode.NXDOMAIN().get_code())
+ self.assertEqual(4, Rcode.NOTIMP().get_code())
+ self.assertEqual(5, Rcode.REFUSED().get_code())
+ self.assertEqual(6, Rcode.YXDOMAIN().get_code())
+ self.assertEqual(7, Rcode.YXRRSET().get_code())
+ self.assertEqual(8, Rcode.NXRRSET().get_code())
+ self.assertEqual(9, Rcode.NOTAUTH().get_code())
+ self.assertEqual(10, Rcode.NOTZONE().get_code())
+ self.assertEqual(11, Rcode.RESERVED11().get_code())
+ self.assertEqual(12, Rcode.RESERVED12().get_code())
+ self.assertEqual(13, Rcode.RESERVED13().get_code())
+ self.assertEqual(14, Rcode.RESERVED14().get_code())
+ self.assertEqual(15, Rcode.RESERVED15().get_code())
+ self.assertEqual(16, Rcode.BADVERS().get_code())
+
+ def test_get_extended_code(self):
+ self.assertEqual(0, Rcode.NOERROR().get_extended_code())
+ self.assertEqual(0, Rcode.YXRRSET().get_extended_code())
+ self.assertEqual(1, Rcode.BADVERS().get_extended_code())
+ self.assertEqual(0xab, Rcode(0xabf).get_extended_code())
+ self.assertEqual(0xff, Rcode(0xfff).get_extended_code())
+
+ def test_to_text(self):
+ self.assertEqual("NOERROR", Rcode(0).to_text())
+ self.assertEqual("NOERROR", str(Rcode(0)))
+ self.assertEqual("FORMERR", Rcode(1).to_text())
+ self.assertEqual("SERVFAIL", Rcode(2).to_text())
+ self.assertEqual("NXDOMAIN", Rcode(3).to_text())
+ self.assertEqual("NOTIMP", Rcode(4).to_text())
+ self.assertEqual("REFUSED", Rcode(5).to_text())
+ self.assertEqual("YXDOMAIN", Rcode(6).to_text())
+ self.assertEqual("YXRRSET", Rcode(7).to_text())
+ self.assertEqual("NXRRSET", Rcode(8).to_text())
+ self.assertEqual("NOTAUTH", Rcode(9).to_text())
+ self.assertEqual("NOTZONE", Rcode(10).to_text())
+ self.assertEqual("RESERVED11", Rcode(11).to_text())
+ self.assertEqual("RESERVED12", Rcode(12).to_text())
+ self.assertEqual("RESERVED13", Rcode(13).to_text())
+ self.assertEqual("RESERVED14", Rcode(14).to_text())
+ self.assertEqual("RESERVED15", Rcode(15).to_text())
+ self.assertEqual("BADVERS", Rcode(16).to_text())
+
+ self.assertEqual("17", Rcode(Rcode.BADVERS().get_code() + 1).to_text())
+ self.assertEqual("4095", Rcode(0xfff).to_text())
+
+ def test_richcmp(self):
+ r1 = Rcode.NOERROR()
+ r2 = Rcode.FORMERR()
+ r3 = Rcode.FORMERR()
+ self.assertTrue(r2 == r3)
+ self.assertTrue(r1 != r2)
+ self.assertFalse(r1 == r2)
+ self.assertFalse(r1 != 1)
+ # can't use assertRaises here...
+ try:
+ r1 < r2
+ self.fail("operation that should have raised an error unexpectedly succeeded")
+ except Exception as err:
+ self.assertEqual(TypeError, type(err))
+ try:
+ r1 <= r2
+ self.fail("operation that should have raised an error unexpectedly succeeded")
+ except Exception as err:
+ self.assertEqual(TypeError, type(err))
+ try:
+ r1 > r2
+ self.fail("operation that should have raised an error unexpectedly succeeded")
+ except Exception as err:
+ self.assertEqual(TypeError, type(err))
+ try:
+ r1 >= r2
+ self.fail("operation that should have raised an error unexpectedly succeeded")
+ except Exception as err:
+ self.assertEqual(TypeError, type(err))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/lib/dns/rcode.cc b/src/lib/dns/rcode.cc
new file mode 100644
index 0000000000..c02ab6a557
--- /dev/null
+++ b/src/lib/dns/rcode.cc
@@ -0,0 +1,103 @@
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <string>
+#include <sstream>
+#include <ostream>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+
+using namespace std;
+
+namespace isc {
+namespace dns {
+namespace {
+// This diagram shows the wire-format representation of the 12-bit extended
+// form RCODEs and its relationship with implementation specific parameters.
+//
+// 0 3 11 15
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |UNUSED | EXTENDED-RCODE | RCODE |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// <= EXTRCODE_SHIFT (4 bits)
+const unsigned int EXTRCODE_SHIFT = 4;
+const unsigned int RCODE_MASK = 0x000f;
+
+
+// EDNS-extended RCODEs are 12-bit unsigned integers. 0xfff is the highest.
+const uint16_t MAX_RCODE = 0xfff;
+
+const char* const rcodetext[] = {
+ "NOERROR",
+ "FORMERR",
+ "SERVFAIL",
+ "NXDOMAIN",
+ "NOTIMP",
+ "REFUSED",
+ "YXDOMAIN",
+ "YXRRSET",
+ "NXRRSET",
+ "NOTAUTH",
+ "NOTZONE",
+ "RESERVED11",
+ "RESERVED12",
+ "RESERVED13",
+ "RESERVED14",
+ "RESERVED15",
+ "BADVERS"
+};
+}
+
+Rcode::Rcode(const uint16_t code) : code_(code) {
+ if (code_ > MAX_RCODE) {
+ isc_throw(OutOfRange, "Rcode is too large to construct");
+ }
+}
+
+Rcode::Rcode(const uint8_t code, const uint8_t extended_code) :
+ code_((extended_code << EXTRCODE_SHIFT) | (code & RCODE_MASK))
+{
+ if (code > RCODE_MASK) {
+ isc_throw(OutOfRange,
+ "Base Rcode is too large to construct: "
+ << static_cast<unsigned int>(code));
+ }
+}
+
+uint8_t
+Rcode::getExtendedCode() const {
+ return (code_ >> EXTRCODE_SHIFT);
+}
+
+string
+Rcode::toText() const {
+ if (code_ < sizeof(rcodetext) / sizeof (const char*)) {
+ return (rcodetext[code_]);
+ }
+
+ ostringstream oss;
+ oss << code_;
+ return (oss.str());
+}
+
+ostream&
+operator<<(std::ostream& os, const Rcode& rcode) {
+ return (os << rcode.toText());
+}
+}
+}
diff --git a/src/lib/dns/rcode.h b/src/lib/dns/rcode.h
new file mode 100644
index 0000000000..8b88b1b3ef
--- /dev/null
+++ b/src/lib/dns/rcode.h
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include <stdint.h>
+
+#include <ostream>
+
+#ifndef __RCODE_H
+#define __RCODE_H 1
+
+namespace isc {
+namespace dns {
+
+/// \brief DNS Response Codes (RCODEs) class.
+///
+/// The \c Rcode class objects represent standard Response Codes
+/// (RCODEs) of the header section of DNS messages, and extended response
+/// codes as defined in the EDNS specification.
+///
+/// Originally RCODEs were defined as 4-bit integers (RFC1035), and then
+/// extended to 12 bits as part of the %EDNS specification (RFC2671).
+/// This API uses the 12-bit version of the definition from the beginning;
+/// applications don't have to aware of the original definition except when
+/// dealing with the wire-format representation of the %EDNS OPT RR
+/// (which is rare).
+///
+/// Like the \c Opcode class, Rcodes could be represented as bare integers,
+/// but we define a separate class to benefit from C++ type safety.
+///
+/// For convenience we also provide
+/// an enum type for pre-defined RCODE values, but it is generally advisable
+/// to handle RCODEs through this class. In fact, public interfaces of
+/// this library uses this class to pass or return RCODEs instead of the
+/// bare code values.
+class Rcode {
+public:
+ /// Constants for pre-defined RCODE values.
+ enum CodeValue {
+ NOERROR_CODE = 0, ///< 0: No error (RFC1035)
+ FORMERR_CODE = 1, ///< 1: Format error (RFC1035)
+ SERVFAIL_CODE = 2, ///< 2: Server failure (RFC1035)
+ NXDOMAIN_CODE = 3, ///< 3: Name Error (RFC1035)
+ NOTIMP_CODE = 4, ///< 4: Not Implemented (RFC1035)
+ REFUSED_CODE = 5, ///< 5: Refused (RFC1035)
+ YXDOMAIN_CODE = 6, ///< 6: Name unexpectedly exists (RFC2136)
+ YXRRSET_CODE = 7, ///< 7: RRset unexpectedly exists (RFC2136)
+ NXRRSET_CODE = 8, ///< 8: RRset should exist but not (RFC2136)
+ NOTAUTH_CODE = 9, ///< 9: Server isn't authoritative (RFC2136)
+ NOTZONE_CODE = 10, ///< 10: Name is not within the zone (RFC2136)
+ RESERVED11_CODE = 11, ///< 11: Reserved for future use (RFC1035)
+ RESERVED12_CODE = 12, ///< 12: Reserved for future use (RFC1035)
+ RESERVED13_CODE = 13, ///< 13: Reserved for future use (RFC1035)
+ RESERVED14_CODE = 14, ///< 14: Reserved for future use (RFC1035)
+ RESERVED15_CODE = 15, ///< 15: Reserved for future use (RFC1035)
+ BADVERS_CODE = 16 ///< 16: EDNS version not implemented (RFC2671)
+ };
+
+ /// \name Constructors and Destructor
+ ///
+ /// We use the default versions of destructor, copy constructor,
+ /// and assignment operator.
+ ///
+ /// The default constructor is hidden as a result of defining the other
+ /// constructors. This is intentional; we don't want to allow an
+ /// \c Rcode object to be constructed with an invalid state.
+ //@{
+ /// \brief Constructor from the code value.
+ ///
+ /// Since RCODEs are 12-bit values, parameters larger than 0xfff are
+ /// invalid.
+ /// If \c code is larger than 0xfff an exception of class
+ /// \c isc::OutOfRange will be thrown.
+ ///
+ /// \param code The underlying 12-bit code value of the \c Rcode.
+ explicit Rcode(const uint16_t code);
+
+ /// \brief Constructor from a pair of base and extended parts of code.
+ ///
+ /// This constructor takes two parameters, one for the lower 4 bits of
+ /// the code value, the other for the upper 8 bits, and combines them
+ /// to build a complete 12-bit code value.
+ ///
+ /// The first parameter, \c code, is the lower 4 bits, and therefore must
+ /// not exceed 15. Otherwise, an exception of class
+ /// \c isc::OutOfRange will be thrown.
+ ///
+ /// This version of constructor is provided specifically for constructing
+ /// an Rcode from a DNS header and an %EDNS OPT RR. Normal applications
+ /// won't have to use this constructor.
+ ///
+ /// \param code The lower 4 bits of the underlying code value.
+ /// \param extended_code The upper 8 bits of the underlying code value.
+ Rcode(const uint8_t code, const uint8_t extended_code);
+ //@}
+
+ /// \brief Returns the \c Rcode code value.
+ ///
+ /// This method never throws an exception.
+ ///
+ /// \return The underlying code value corresponding to the \c Rcode.
+ uint16_t getCode() const { return (code_); }
+
+ /// \brief Returns the upper 8-bit of the \c Rcode code value.
+ ///
+ /// Normal applications won't have to use this method. This is provided
+ /// in case the upper 8 bits are necessary for the EDNS protocol
+ /// processing.
+ ///
+ /// This method never throws an exception.
+ ///
+ /// \return The upper 8-bit of the underlying code value.
+ uint8_t getExtendedCode() const;
+
+ /// \brief Return true iff two Rcodes are equal.
+ ///
+ /// Two Rcodes are equal iff their type codes are equal.
+ ///
+ /// This method never throws an exception.
+ ///
+ /// \param other the \c Rcode object to compare against.
+ /// \return true if the two Rcodes are equal; otherwise false.
+ bool equals(const Rcode& other) const
+ { return (code_ == other.code_); }
+
+ /// \brief Same as \c equals().
+ bool operator==(const Rcode& other) const { return (equals(other)); }
+
+ /// \brief Return true iff two Rcodes are not equal.
+ ///
+ /// This method never throws an exception.
+ ///
+ /// \param other the \c Rcode object to compare against.
+ /// \return true if the two Rcodes are not equal; otherwise false.
+ bool nequals(const Rcode& other) const
+ { return (code_ != other.code_); }
+
+ /// \brief Same as \c nequals().
+ bool operator!=(const Rcode& other) const { return (nequals(other)); }
+
+ /// \brief Convert the \c Rcode to a string.
+ ///
+ /// For pre-defined code values (see Rcode::CodeValue),
+ /// this method returns a string representation of the "mnemonic' used
+ /// for the enum and constant objects. For example, the string for
+ /// code value 0 is "NOERROR", etc.
+ /// For other code values it returns a string representation of the decimal
+ /// number of the value, e.g. "32", "100", etc.
+ ///
+ /// If resource allocation for the string fails, a corresponding standard
+ /// exception will be thrown.
+ ///
+ /// \return A string representation of the \c Rcode.
+ std::string toText() const;
+
+ /// A constant object for the NOERROR Rcode (see \c Rcode::NOERROR_CODE).
+ static const Rcode& NOERROR();
+
+ /// A constant object for the FORMERR Rcode (see \c Rcode::FORMERR_CODE).
+ static const Rcode& FORMERR();
+
+ /// A constant object for the SERVFAIL Rcode (see \c Rcode::SERVFAIL_CODE).
+ static const Rcode& SERVFAIL();
+
+ /// A constant object for the NXDOMAIN Rcode (see \c Rcode::NXDOMAIN_CODE).
+ static const Rcode& NXDOMAIN();
+
+ /// A constant object for the NOTIMP Rcode (see \c Rcode::NOTIMP_CODE).
+ static const Rcode& NOTIMP();
+
+ /// A constant object for the REFUSED Rcode (see \c Rcode::REFUSED_CODE).
+ static const Rcode& REFUSED();
+
+ /// A constant object for the YXDOMAIN Rcode (see \c Rcode::YXDOMAIN_CODE).
+ static const Rcode& YXDOMAIN();
+
+ /// A constant object for the YXRRSET Rcode (see \c Rcode::YXRRSET_CODE).
+ static const Rcode& YXRRSET();
+
+ /// A constant object for the NXRRSET Rcode (see \c Rcode::NXRRSET_CODE).
+ static const Rcode& NXRRSET();
+
+ /// A constant object for the NOTAUTH Rcode (see \c Rcode::NOTAUTH_CODE).
+ static const Rcode& NOTAUTH();
+
+ /// A constant object for the NOTZONE Rcode (see \c Rcode::NOTZONE_CODE).
+ static const Rcode& NOTZONE();
+
+ /// A constant object for a reserved (code 11) Rcode.
+ /// (see \c Rcode::RESERVED11_CODE).
+ static const Rcode& RESERVED11();
+
+ /// A constant object for a reserved (code 12) Rcode.
+ /// (see \c Rcode::RESERVED12_CODE).
+ static const Rcode& RESERVED12();
+
+ /// A constant object for a reserved (code 13) Rcode.
+ /// (see \c Rcode::RESERVED13_CODE).
+ static const Rcode& RESERVED13();
+
+ /// A constant object for a reserved (code 14) Rcode.
+ /// (see \c Rcode::RESERVED14_CODE).
+ static const Rcode& RESERVED14();
+
+ /// A constant object for a reserved (code 15) Rcode.
+ /// (see \c Rcode::RESERVED15_CODE).
+ static const Rcode& RESERVED15();
+
+ /// A constant object for the BADVERS Rcode (see \c Rcode::BADVERS_CODE).
+ static const Rcode& BADVERS();
+private:
+ uint16_t code_;
+};
+
+inline const Rcode&
+Rcode::NOERROR() {
+ static Rcode c(0);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::FORMERR() {
+ static Rcode c(1);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::SERVFAIL() {
+ static Rcode c(2);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::NXDOMAIN() {
+ static Rcode c(3);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::NOTIMP() {
+ static Rcode c(4);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::REFUSED() {
+ static Rcode c(5);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::YXDOMAIN() {
+ static Rcode c(6);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::YXRRSET() {
+ static Rcode c(7);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::NXRRSET() {
+ static Rcode c(8);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::NOTAUTH() {
+ static Rcode c(9);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::NOTZONE() {
+ static Rcode c(10);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::RESERVED11() {
+ static Rcode c(11);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::RESERVED12() {
+ static Rcode c(12);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::RESERVED13() {
+ static Rcode c(13);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::RESERVED14() {
+ static Rcode c(14);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::RESERVED15() {
+ static Rcode c(15);
+ return (c);
+}
+
+inline const Rcode&
+Rcode::BADVERS() {
+ static Rcode c(16);
+ return (c);
+}
+
+/// \brief Insert the \c Rcode as a string into stream.
+///
+/// This method convert \c rcode into a string and inserts it into the
+/// output stream \c os.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param rcode A reference to an \c Rcode object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const Rcode& rcode);
+}
+}
+#endif // RCODE_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/tests/opcode_unittest.cc b/src/lib/dns/tests/opcode_unittest.cc
index bd1f495fbb..1cf8af1b2e 100644
--- a/src/lib/dns/tests/opcode_unittest.cc
+++ b/src/lib/dns/tests/opcode_unittest.cc
@@ -30,7 +30,7 @@ namespace {
TEST(OpcodeTest, construct) {
// This test also tests getCode()
EXPECT_EQ(0, Opcode(0).getCode());
- EXPECT_EQ(15, Opcode(Opcode::MAX_CODE).getCode());
+ EXPECT_EQ(15, Opcode(Opcode::RESERVED15_CODE).getCode());
EXPECT_THROW(Opcode(16), isc::OutOfRange);
}
@@ -76,7 +76,7 @@ TEST(OpcodeTest, nequal) {
TEST(OpcodeTest, toText) {
vector<const char*> expects;
- expects.resize(Opcode::MAX_CODE);
+ expects.resize(Opcode::RESERVED15_CODE + 1);
expects[Opcode::QUERY_CODE] = "QUERY";
expects[Opcode::IQUERY_CODE] = "IQUERY";
expects[Opcode::STATUS_CODE] = "STATUS";
@@ -94,7 +94,7 @@ TEST(OpcodeTest, toText) {
expects[Opcode::RESERVED14_CODE] = "RESERVED14";
expects[Opcode::RESERVED15_CODE] = "RESERVED15";
- for (unsigned int i = 0; i < Opcode::MAX_CODE; ++i) {
+ for (unsigned int i = 0; i <= Opcode::RESERVED15_CODE; ++i) {
EXPECT_EQ(expects.at(i), Opcode(i).toText());
}
}
diff --git a/src/lib/dns/tests/rcode_unittest.cc b/src/lib/dns/tests/rcode_unittest.cc
new file mode 100644
index 0000000000..4ccb7b0412
--- /dev/null
+++ b/src/lib/dns/tests/rcode_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <vector>
+#include <sstream>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::dns;
+
+namespace {
+TEST(RcodeTest, constructFromCode) {
+ // Normal cases. This test also tests getCode()
+ EXPECT_EQ(0, Rcode(0).getCode());
+ EXPECT_EQ(0xfff, Rcode(0xfff).getCode()); // possible max code
+
+ // should fail on attempt of construction with an out of range code
+ EXPECT_THROW(Rcode(0x1000), isc::OutOfRange);
+ EXPECT_THROW(Rcode(0xffff), isc::OutOfRange);
+}
+
+TEST(RcodeTest, constructFromCodePair) {
+ EXPECT_EQ(3, Rcode(Rcode::NXDOMAIN_CODE, 0).getCode());
+ EXPECT_EQ(Rcode::BADVERS_CODE, Rcode(0, 1).getCode());
+ EXPECT_EQ(0xfff, Rcode(0xf, 0xff).getCode());
+ EXPECT_THROW(Rcode(0x10, 0xff), isc::OutOfRange);
+}
+
+TEST(RcodeTest, getExtendedCode) {
+ EXPECT_EQ(0, Rcode::NOERROR().getExtendedCode());
+ EXPECT_EQ(0, Rcode::YXRRSET().getExtendedCode());
+ EXPECT_EQ(1, Rcode::BADVERS().getExtendedCode());
+ EXPECT_EQ(0xab, Rcode(0xabf).getExtendedCode());
+ EXPECT_EQ(0xff, Rcode(0xfff).getExtendedCode());
+}
+
+TEST(RcodeTest, constants) {
+ // We'll only test arbitrarily chosen subsets of the codes.
+ // This class is quite simple, so it should be suffice.
+
+ EXPECT_EQ(Rcode::NOERROR_CODE, Rcode(0).getCode());
+ EXPECT_EQ(Rcode::FORMERR_CODE, Rcode(1).getCode());
+ EXPECT_EQ(Rcode::NOTIMP_CODE, Rcode(4).getCode());
+ EXPECT_EQ(Rcode::REFUSED_CODE, Rcode(5).getCode());
+ EXPECT_EQ(Rcode::RESERVED15_CODE, Rcode(15).getCode());
+ EXPECT_EQ(Rcode::BADVERS_CODE, Rcode(16).getCode());
+
+ EXPECT_EQ(Rcode::NOERROR_CODE, Rcode::NOERROR().getCode());
+ EXPECT_EQ(Rcode::FORMERR_CODE, Rcode::FORMERR().getCode());
+ EXPECT_EQ(Rcode::NOTIMP_CODE, Rcode::NOTIMP().getCode());
+ EXPECT_EQ(Rcode::REFUSED_CODE, Rcode::REFUSED().getCode());
+ EXPECT_EQ(Rcode::RESERVED15_CODE, Rcode::RESERVED15().getCode());
+ EXPECT_EQ(Rcode::BADVERS_CODE, Rcode::BADVERS().getCode());
+}
+
+TEST(RcodeTest, equal) {
+ EXPECT_TRUE(Rcode::NOERROR() == Rcode(Rcode::NOERROR_CODE));
+ EXPECT_TRUE(Rcode::NOERROR().equals(Rcode(Rcode::NOERROR_CODE)));
+ EXPECT_TRUE(Rcode::FORMERR() == Rcode(Rcode::FORMERR_CODE));
+ EXPECT_TRUE(Rcode::FORMERR().equals(Rcode(Rcode::FORMERR_CODE)));
+ EXPECT_TRUE(Rcode::NOTIMP() == Rcode(Rcode::NOTIMP_CODE));
+ EXPECT_TRUE(Rcode::NOTIMP().equals(Rcode(Rcode::NOTIMP_CODE)));
+ EXPECT_TRUE(Rcode::REFUSED() == Rcode(Rcode::REFUSED_CODE));
+ EXPECT_TRUE(Rcode::REFUSED().equals(Rcode(Rcode::REFUSED_CODE)));
+ EXPECT_TRUE(Rcode::RESERVED15() == Rcode(Rcode::RESERVED15()));
+ EXPECT_TRUE(Rcode::RESERVED15().equals(Rcode(Rcode::RESERVED15())));
+ EXPECT_TRUE(Rcode::BADVERS() == Rcode(Rcode::BADVERS_CODE));
+ EXPECT_TRUE(Rcode::BADVERS().equals(Rcode(Rcode::BADVERS_CODE)));
+}
+
+TEST(RcodeTest, nequal) {
+ EXPECT_TRUE(Rcode::NOERROR() != Rcode::FORMERR());
+ EXPECT_TRUE(Rcode::NOERROR().nequals(Rcode::FORMERR()));
+ EXPECT_TRUE(Rcode::NOTIMP() != Rcode(1));
+ EXPECT_TRUE(Rcode::NOTIMP().nequals(Rcode(1)));
+ EXPECT_TRUE(Rcode(10) != Rcode(11));
+ EXPECT_TRUE(Rcode(10).nequals(Rcode(11)));
+}
+
+TEST(RcodeTest, toText) {
+ vector<const char*> expects;
+ expects.resize(Rcode::BADVERS_CODE + 1);
+ expects[Rcode::NOERROR_CODE] = "NOERROR";
+ expects[Rcode::FORMERR_CODE] = "FORMERR";
+ expects[Rcode::SERVFAIL_CODE] = "SERVFAIL";
+ expects[Rcode::NXDOMAIN_CODE] = "NXDOMAIN";
+ expects[Rcode::NOTIMP_CODE] = "NOTIMP";
+ expects[Rcode::REFUSED_CODE] = "REFUSED";
+ expects[Rcode::YXDOMAIN_CODE] = "YXDOMAIN";
+ expects[Rcode::YXRRSET_CODE] = "YXRRSET";
+ expects[Rcode::NXRRSET_CODE] = "NXRRSET";
+ expects[Rcode::NOTAUTH_CODE] = "NOTAUTH";
+ expects[Rcode::NOTZONE_CODE] = "NOTZONE";
+ expects[Rcode::RESERVED11_CODE] = "RESERVED11";
+ expects[Rcode::RESERVED12_CODE] = "RESERVED12";
+ expects[Rcode::RESERVED13_CODE] = "RESERVED13";
+ expects[Rcode::RESERVED14_CODE] = "RESERVED14";
+ expects[Rcode::RESERVED15_CODE] = "RESERVED15";
+ expects[Rcode::BADVERS_CODE] = "BADVERS";
+
+ for (unsigned int i = 0; i <= Rcode::BADVERS_CODE; ++i) {
+ EXPECT_EQ(expects.at(i), Rcode(i).toText());
+ }
+
+ // Non well-known Rcodes
+ EXPECT_EQ("17", Rcode(Rcode::BADVERS().getCode() + 1).toText());
+ EXPECT_EQ("4095", Rcode(Rcode(0xfff)).toText());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST(RcodeTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << Rcode::SERVFAIL();
+ EXPECT_EQ(Rcode::SERVFAIL().toText(), oss.str());
+}
+}