Parcourir la source

provided documentation

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac351@3039 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya il y a 14 ans
Parent
commit
0ab28241aa

+ 5 - 2
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);
     }

+ 109 - 23
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_;

+ 1 - 3
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);
 }

+ 433 - 0
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

+ 1 - 1
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):

+ 137 - 0
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()

+ 103 - 0
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());
+}
+}
+}

+ 348 - 0
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: 

+ 3 - 3
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());
     }
 }

+ 134 - 0
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());
+}
+}