diff options
author | JINMEI Tatuya <jinmei@isc.org> | 2010-09-28 04:16:01 +0200 |
---|---|---|
committer | JINMEI Tatuya <jinmei@isc.org> | 2010-09-28 04:16:01 +0200 |
commit | 0ab28241aa457eb968cf933e990db2d925568089 (patch) | |
tree | 7b4adf2d6b27b56a688753b1fdf992d4293cb191 | |
parent | - separated Rcode class declarations and definitions in different files (diff) | |
download | kea-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.cc | 7 | ||||
-rw-r--r-- | src/lib/dns/opcode.h | 132 | ||||
-rw-r--r-- | src/lib/dns/python/opcode_python.cc | 4 | ||||
-rw-r--r-- | src/lib/dns/python/rcode_python.cc | 433 | ||||
-rw-r--r-- | src/lib/dns/python/tests/opcode_python_test.py | 2 | ||||
-rw-r--r-- | src/lib/dns/python/tests/rcode_python_test.py | 137 | ||||
-rw-r--r-- | src/lib/dns/rcode.cc | 103 | ||||
-rw-r--r-- | src/lib/dns/rcode.h | 348 | ||||
-rw-r--r-- | src/lib/dns/tests/opcode_unittest.cc | 6 | ||||
-rw-r--r-- | src/lib/dns/tests/rcode_unittest.cc | 134 |
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()); +} +} |