Commit 0ab28241 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

provided documentation

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac351@3039 e5f2f494-b856-4b98-b285-d166d9295462
parent 7ad9d497
......@@ -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);
}
......
......@@ -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_;
......
......@@ -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);
}
......
// 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));