[svn] commit: r973 - in /trunk: ./ doc/ src/bin/parkinglot/ src/lib/dns/cpp/ src/lib/dns/cpp/rdata/ src/lib/dns/cpp/rdata/generic/ src/lib/dns/cpp/testdata/ src/lib/dns/cpp/tests/ src/lib/dns/cpp/tests/testdata/

BIND 10 source code commits bind10-changes at lists.isc.org
Thu Feb 25 22:50:58 UTC 2010


Author: jinmei
Date: Thu Feb 25 22:50:58 2010
New Revision: 973

Log:
merged the jinmei-dnsrdata2 branch into trunk

Added:
    trunk/src/bin/parkinglot/   (props changed)
      - copied from r972, branches/jinmei-dnsrdata2/src/bin/parkinglot/
    trunk/src/lib/dns/cpp/tests/   (props changed)
      - copied from r972, branches/jinmei-dnsrdata2/src/lib/dns/cpp/tests/
    trunk/src/lib/dns/cpp/tests/testdata/question_fromWire
      - copied unchanged from r971, trunk/src/lib/dns/cpp/testdata/question_fromWire
    trunk/src/lib/dns/cpp/tests/testdata/question_toWire1
      - copied unchanged from r971, trunk/src/lib/dns/cpp/testdata/question_toWire1
    trunk/src/lib/dns/cpp/tests/testdata/question_toWire2
      - copied unchanged from r971, trunk/src/lib/dns/cpp/testdata/question_toWire2
Removed:
    trunk/src/lib/dns/cpp/base64_unittest.cc
    trunk/src/lib/dns/cpp/buffer_unittest.cc
    trunk/src/lib/dns/cpp/message_unittest.cc
    trunk/src/lib/dns/cpp/messagerenderer_unittest.cc
    trunk/src/lib/dns/cpp/name_unittest.cc
    trunk/src/lib/dns/cpp/question_unittest.cc
    trunk/src/lib/dns/cpp/rdata_unittest.cc
    trunk/src/lib/dns/cpp/rrclass_unittest.cc
    trunk/src/lib/dns/cpp/rrparamregistry_unittest.cc
    trunk/src/lib/dns/cpp/rrset_unittest.cc
    trunk/src/lib/dns/cpp/rrttl_unittest.cc
    trunk/src/lib/dns/cpp/rrtype_unittest.cc
    trunk/src/lib/dns/cpp/run_unittests.cc
    trunk/src/lib/dns/cpp/testdata/question_fromWire
    trunk/src/lib/dns/cpp/testdata/question_toWire1
    trunk/src/lib/dns/cpp/testdata/question_toWire2
    trunk/src/lib/dns/cpp/unittest_util.cc
    trunk/src/lib/dns/cpp/unittest_util.h
Modified:
    trunk/   (props changed)
    trunk/configure.ac
    trunk/doc/Doxyfile
    trunk/src/lib/dns/cpp/   (props changed)
    trunk/src/lib/dns/cpp/Makefile.am
    trunk/src/lib/dns/cpp/gen-rdatacode.py.in   (contents, props changed)
    trunk/src/lib/dns/cpp/rdata.cc
    trunk/src/lib/dns/cpp/rdata.h
    trunk/src/lib/dns/cpp/rdata/generic/rrsig_46.cc   (props changed)
    trunk/src/lib/dns/cpp/rdata/generic/txt_16.h
    trunk/src/lib/dns/cpp/rdata/template.h
    trunk/src/lib/dns/cpp/rrparamregistry-placeholder.cc   (contents, props changed)
    trunk/src/lib/dns/cpp/rrparamregistry.h

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Thu Feb 25 22:50:58 2010
@@ -165,6 +165,7 @@
                  src/lib/config/python/isc/config/Makefile
                  src/lib/dns/Makefile
                  src/lib/dns/cpp/Makefile
+                 src/lib/dns/cpp/tests/Makefile
                  src/lib/exceptions/cpp/Makefile
                  src/lib/exceptions/Makefile
                  src/lib/auth/Makefile

Modified: trunk/doc/Doxyfile
==============================================================================
--- trunk/doc/Doxyfile (original)
+++ trunk/doc/Doxyfile Thu Feb 25 22:50:58 2010
@@ -611,7 +611,7 @@
 # against the file with absolute path, so to exclude all test directories
 # for example use the pattern */test/*
 
-EXCLUDE_PATTERNS       = *unittest*.h
+EXCLUDE_PATTERNS       = */*-placeholder.* */cpp/*.py
 
 # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
 # (namespaces, classes, functions, etc.) that should be excluded from the

Modified: trunk/src/lib/dns/cpp/Makefile.am
==============================================================================
--- trunk/src/lib/dns/cpp/Makefile.am (original)
+++ trunk/src/lib/dns/cpp/Makefile.am Thu Feb 25 22:50:58 2010
@@ -1,3 +1,5 @@
+SUBDIRS = . tests
+
 AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/ext
 
 CLEANFILES = *.gcno *.gcda
@@ -23,27 +25,3 @@
 rrparamregistry.cc: rrparamregistry-placeholder.cc
 rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
 	./gen-rdatacode.py
-
-TESTS =
-if HAVE_GTEST
-TESTS += run_unittests
-run_unittests_SOURCES = unittest_util.h unittest_util.cc
-run_unittests_SOURCES += buffer_unittest.cc name_unittest.cc
-run_unittests_SOURCES += messagerenderer_unittest.cc
-run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
-run_unittests_SOURCES += rrttl_unittest.cc
-run_unittests_SOURCES += rdata_unittest.cc
-run_unittests_SOURCES += rrset_unittest.cc
-run_unittests_SOURCES += rrsetlist_unittest.cc
-run_unittests_SOURCES += question_unittest.cc
-run_unittests_SOURCES += rrparamregistry_unittest.cc
-run_unittests_SOURCES += message_unittest.cc
-run_unittests_SOURCES += base64_unittest.cc
-run_unittests_SOURCES += run_unittests.cc
-run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
-run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-run_unittests_LDADD = .libs/libdns.a $(GTEST_LDADD)
-run_unittests_LDADD +=  $(top_builddir)/src/lib/exceptions/cpp/.libs/libexceptions.a
-endif
-
-noinst_PROGRAMS = $(TESTS)

Modified: trunk/src/lib/dns/cpp/gen-rdatacode.py.in
==============================================================================
--- trunk/src/lib/dns/cpp/gen-rdatacode.py.in (original)
+++ trunk/src/lib/dns/cpp/gen-rdatacode.py.in Thu Feb 25 22:50:58 2010
@@ -22,6 +22,7 @@
 """
 
 import os
+from os.path import getmtime
 import re
 import sys
 
@@ -30,13 +31,16 @@
 typecode2txt = {}
 typeandclass = []
 generic_code = 65536            # something larger than any code value
-class_declarations = ''
+rdata_declarations = ''
 class_definitions = ''
+classdir_mtime = 0
+rdatadef_mtime = 0
+rdatahdr_mtime = 0
 copyright_file = '@top_srcdir@' + os.sep + 'COPYING'
 
 def import_classdef(class_txt, file):
+    content = ''
     rdata_source = open(file, 'r')
-    content = ''
     for line in rdata_source.readlines():
         if re.match('// BEGIN_ISC_NAMESPACE', line):
             content += 'namespace isc {\n'
@@ -59,6 +63,9 @@
     return content
 
 def import_classheader(class_txt, type_txt, type_code, file):
+    type_utxt = type_txt.upper()
+    class_utxt = class_txt.upper()
+
     # for each CLASS_n/TYPE_m.h
     rdata_header = open(file, 'r')
     content = ''
@@ -125,12 +132,19 @@
 '''
     return copyright_txt
 
-if __name__ == "__main__":
-    copyright_txt = import_copyright()
+def import_definitions(classcode2txt, typecode2txt, typeandclass):
+    global rdata_declarations
+    global class_definitions
+    global classdir_mtime
+    global rdatadef_mtime
+    global rdatahdr_mtime
+
     for dir in list(os.listdir('@srcdir@/rdata')):
         classdir = '@srcdir@/rdata' + os.sep + dir
         m = re_typecode.match(dir)
         if os.path.isdir(classdir) and (m != None or dir == 'generic'):
+            if classdir_mtime < getmtime(classdir):
+                classdir_mtime = getmtime(classdir)
             if dir == 'generic':
                 class_txt = 'generic'
                 class_code = generic_code
@@ -145,15 +159,16 @@
                 if m != None:
                     type_txt = m.group(1)
                     type_code = m.group(2)
-                    type_utxt = type_txt.upper()
-                    class_utxt = class_txt.upper()
-
                     if not type_code in typecode2txt:
                         typecode2txt[type_code] = type_txt
                     if re.search('\cc$', file):
+                        if rdatadef_mtime < getmtime(file):
+                            rdatadef_mtime = getmtime(file)
                         class_definitions += import_classdef(class_txt, file)
                     elif re.search('\h$', file):
-                        class_declarations += import_classheader(class_txt,
+                        if rdatahdr_mtime < getmtime(file):
+                            rdatahdr_mtime = getmtime(file)
+                        rdata_declarations += import_classheader(class_txt,
                                                                  type_txt,
                                                                  type_code,
                                                                  file)
@@ -163,78 +178,89 @@
                         if class_txt == 'generic':
                             typeandclass.append((type_txt, int(type_code),
                                                  (class_txt, 'in'), 1))
-    rdata_deffile = open('@srcdir@/rdataclass.cc', 'w')
+
+def need_generate(file, mtime):
+    '''Check if we need to generate the specified file.
+
+    To avoid unnecessary compilation, we skip (re)generating the file when
+    the file already exists and newer than the base file.
+    '''
+    if os.path.exists(file) and getmtime(file) > mtime:
+        return False
+    return True
+
+def generate_rdatadef(file, copyright_txt, basemtime):
+    if not need_generate(file, basemtime):
+        print('skip generating ' + file);
+        return
+    rdata_deffile = open(file, 'w')
     rdata_deffile.write(copyright_txt)
     rdata_deffile.write(class_definitions)
     rdata_deffile.close()
 
-    class_declarations += '''
+def generate_rdatahdr(file, copyright_txt, declarations, basemtime):
+    if not need_generate(file, basemtime):
+        print('skip generating ' + file);
+        return
+    declarations += '''
 // Local Variables:
 // mode: c++
 // End:
 '''
-    rdata_header = open('@srcdir@/rdataclass.h', 'w')
+    rdata_header = open(file, 'w')
     rdata_header.write(copyright_txt)
-    rdata_header.write(class_declarations)
+    rdata_header.write(declarations)
     rdata_header.close()
-    
+
+def generate_typeclasscode(fileprefix, basemtime, code2txt, type_or_class):
+    placeholder = fileprefix + '-placeholder.h'
+    outputfile = fileprefix + '.h'
+    upper_key = type_or_class.upper() # TYPE or CLASS
+    lower_key = 'rr' + type_or_class.lower() # rrtype or rrclass
+    cap_key = type_or_class           # Type or Class
+
+    if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
+        print('skip generating ' + outputfile)
+        return
+
     declarationtxt = ''
     deftxt = ''
-    for code in typecode2txt.keys():
-        # for rrtype.h
-        rrtype = typecode2txt[code].upper()
-        declarationtxt += ' ' * 4 + 'static const RRType& ' + rrtype + '();\n'
-        deftxt += '''inline const RRType&
-RRType::''' + rrtype + '''()
+    for code in code2txt.keys():
+        codetxt = code2txt[code].upper()
+        declarationtxt += ' ' * 4 + 'static const RR' + cap_key + '& ' + codetxt + '();\n'
+        deftxt += '''inline const RR''' + cap_key + '''&
+RR''' + cap_key + '''::''' + codetxt + '''()
 {
-    static RRType rrtype(''' + code + ''');
-    return (rrtype);
+    static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code + ''');
+    return (''' + lower_key + ''');
 }\n
 '''
-    rrtype_header_temp = open('@srcdir@/rrtype-placeholder.h', 'r')
-    rrtype_header_out = open('@srcdir@/rrtype.h', 'w')
-    rrtype_header_out.write(copyright_txt)
-    for line in rrtype_header_temp.readlines():
-        rrtype_header_out.write(line)
-        if re.match('\s+// BEGIN_WELL_KNOWN_TYPE_DECLARATIONS$', line):
-            rrtype_header_out.write(declarationtxt)
-        if re.match('// BEGIN_WELL_KNOWN_TYPE_DEFINITIONS$', line):
-            rrtype_header_out.write('\n' + deftxt)
-    rrtype_header_out.close()
-    rrtype_header_temp.close()
-
-    declarationtxt = ''
-    deftxt = ''
-    for code in classcode2txt.keys():
-        # for rrclass.h
-        rrclass = classcode2txt[code].upper()
-        declarationtxt += ' ' * 4 + 'static const RRClass& ' + rrclass + '();\n'
-        deftxt += '''inline const RRClass&
-RRClass::''' + rrclass + '''()
-{
-    static RRClass rrclass(''' + code + ''');
-    return (rrclass);
-}\n
-'''
-
-    rrclass_header_temp = open('@srcdir@/rrclass-placeholder.h', 'r')
-    rrclass_header_out = open('@srcdir@/rrclass.h', 'w')
-    rrclass_header_out.write(copyright_txt)
-    for line in rrclass_header_temp.readlines():
-        rrclass_header_out.write(line)
-        if re.match('\s+// BEGIN_WELL_KNOWN_CLASS_DECLARATIONS$', line):
-            rrclass_header_out.write(declarationtxt)
-        if re.match('// BEGIN_WELL_KNOWN_CLASS_DEFINITIONS$', line):
-            rrclass_header_out.write('\n' + deftxt)
-    rrclass_header_out.close()
-    rrclass_header_temp.close()
+    header_temp = open(placeholder, 'r')
+    header_out = open(outputfile, 'w')
+    header_out.write(copyright_txt)
+    for line in header_temp.readlines():
+        header_out.write(line)
+        if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key + '_DECLARATIONS$', line):
+            header_out.write(declarationtxt)
+        if re.match('// BEGIN_WELL_KNOWN_' + upper_key + '_DEFINITIONS$', line):
+            header_out.write('\n' + deftxt)
+    header_out.close()
+    header_temp.close()
+
+def generate_rrparam(fileprefix, basemtime):
+    placeholder = fileprefix + '-placeholder.cc'
+    outputfile = fileprefix + '.cc'
+    if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
+        print('skip generating ' + outputfile)
+        return
 
     # sort by class, then by type
     typeandclassparams = ''
     typeandclass.sort(key = lambda x: (x[3], x[1]))
     for param in typeandclass:
-        # for rdata.cc
-        # each param is a tuple of (type_txt, type_code, class_tuple, class_code)
+        # for rrparamregistry.cc
+        # each param is a tuple of (type_txt, type_code, class_tuple,
+        #                           class_code)
         (type_txt, type_code, class_tuple, class_code) = param
         type_utxt = type_txt.upper()
         class_txt = class_tuple[0]
@@ -252,8 +278,8 @@
             typeandclassparams += ', RdataFactoryPtr(new RdataFactory<'
             typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
 
-    rrparam_temp = open('@srcdir@/rrparamregistry-placeholder.cc', 'r')
-    rrparam_out = open('@srcdir@/rrparamregistry.cc', 'w')
+    rrparam_temp = open(placeholder, 'r')
+    rrparam_out = open(outputfile, 'w')
     rrparam_out.write(copyright_txt)
     for line in rrparam_temp.readlines():
         rrparam_out.write(line)
@@ -261,3 +287,22 @@
             rrparam_out.write(typeandclassparams)
     rrparam_temp.close()
     rrparam_out.close()
+
+if __name__ == "__main__":
+    try:
+        copyright_txt = import_copyright()
+        import_definitions(classcode2txt, typecode2txt, typeandclass)
+        generate_rdatadef('@srcdir@/rdataclass.cc', copyright_txt,
+                          rdatadef_mtime)
+        generate_rdatahdr('@srcdir@/rdataclass.h', copyright_txt,
+                          rdata_declarations, rdatahdr_mtime)
+        generate_typeclasscode('@srcdir@/rrtype',
+                               max(rdatadef_mtime, rdatahdr_mtime),
+                               typecode2txt, 'Type')
+        generate_typeclasscode('@srcdir@/rrclass', classdir_mtime,
+                               classcode2txt, 'Class')
+        generate_rrparam('@srcdir@/rrparamregistry', rdatahdr_mtime)
+    except:
+        sys.stderr.write('Code generation failed due to exception: %s\n' %
+                         sys.exc_info()[1])
+        exit(1)

Modified: trunk/src/lib/dns/cpp/rdata.cc
==============================================================================
--- trunk/src/lib/dns/cpp/rdata.cc (original)
+++ trunk/src/lib/dns/cpp/rdata.cc Thu Feb 25 22:50:58 2010
@@ -14,16 +14,20 @@
 
 // $Id$
 
+#include <algorithm>
 #include <cctype>
 #include <string>
+#include <sstream>
+#include <iomanip>
+#include <ios>
+#include <ostream>
+#include <vector>
 
 #include <stdint.h>
 #include <string.h>
 
 #include <boost/lexical_cast.hpp>
 #include <boost/shared_ptr.hpp>
-
-#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards
 
 #include "buffer.h"
 #include "name.h"
@@ -53,6 +57,10 @@
 createRdata(const RRType& rrtype, const RRClass& rrclass,
             InputBuffer& buffer, size_t len)
 {
+    if (len > MAX_RDLENGTH) {
+        dns_throw(InvalidRdataLength, "RDLENGTH too large");
+    }
+
     size_t old_pos = buffer.getPosition();
 
     RdataPtr rdata =
@@ -78,14 +86,14 @@
 {
     size_t len1 = n1.getLength();
     size_t len2 = n2.getLength();
-    size_t cmplen = (len1 < len2) ? len1 : len2;
+    size_t cmplen = min(len1, len2);
 
     for (size_t i = 0; i < cmplen; ++i) {
         uint8_t c1 = tolower(n1.at(i));
         uint8_t c2 = tolower(n2.at(i));
         if (c1 < c2) {
             return (-1);
-        } else if (c2 > c1) {
+        } else if (c1 > c2) {
             return (1);
         }
     }
@@ -94,62 +102,181 @@
 }
 
 namespace generic {
-Generic::Generic(InputBuffer& buffer, size_t rdata_len) :
-    data_(rdata_len)
-{
-    buffer.readData(&data_[0], rdata_len);
-    data_.resize(rdata_len);
+struct GenericImpl {
+    GenericImpl(const vector<uint8_t>& data) : data_(data) {}
+    vector<uint8_t> data_;
+};
+
+Generic::Generic(InputBuffer& buffer, size_t rdata_len)
+{
+    if (rdata_len > MAX_RDLENGTH) {
+        dns_throw(InvalidRdataLength, "RDLENGTH too large");
+    }
+
+    vector<uint8_t> data(rdata_len);
+    buffer.readData(&data[0], rdata_len);
+    data.resize(rdata_len);
+
+    impl_ = new GenericImpl(data);
 }
 
 Generic::Generic(const string& rdata_string)
 {
-    // parse the \# n xx xx... format (TBD)
+    istringstream iss(rdata_string);
+    string unknown_mark;
+    iss >> unknown_mark;
+    if (unknown_mark != "\\#") {
+        dns_throw(InvalidRdataText,
+                  "Missing the special token (\\#) for generic RDATA encoding");
+    }
+
+    // RDLENGTH: read into a string so that we can easily reject invalid tokens
+    string rdlen_txt;
+    iss >> rdlen_txt;
+    istringstream iss_rdlen(rdlen_txt);
+    int32_t rdlen;
+    iss_rdlen >> rdlen;
+    if (iss_rdlen.rdstate() != ios::eofbit) {
+        dns_throw(InvalidRdataText,
+                  "Invalid representation for a generic RDLENGTH");
+    }
+    if (rdlen < 0 || rdlen > 0xffff) {
+        dns_throw(InvalidRdataLength, "RDATA length is out of range");
+    }
+    iss >> ws;                  // skip any white spaces
+
+    // Hexadecimal encoding of RDATA: each segment must consist of an even
+    // number of hex digits.
+    vector<uint8_t> data;
+    while (!iss.eof() && data.size() < rdlen) {
+        // extract two characters, which should compose a single byte of data.
+        char buf[2];
+        iss.read(buf, sizeof(buf));
+        if ((iss.rdstate() & (ios::badbit | ios::failbit)) != 0) {
+            dns_throw(InvalidRdataText,
+                      "Invalid hex encoding of generic RDATA");
+        }
+
+        // convert it to a single byte integer as a hex digit.
+        istringstream iss_byte(string(buf, sizeof(buf)));
+        unsigned int ch;
+        iss_byte >> hex >> ch;
+        if (iss_byte.rdstate() != ios::eofbit) {
+            dns_throw(InvalidRdataText,
+                      "Invalid hex encoding of generic RDATA");
+        }
+        data.push_back(ch);
+        iss >> ws;              // skip spaces
+    }
+
+    if (!iss.eof()) {
+        dns_throw(InvalidRdataLength,
+                  "RDLENGTH is too small for generic RDATA");
+    }
+
+    if (data.size() != rdlen) {
+        dns_throw(InvalidRdataLength,
+                  "Generic RDATA code doesn't match RDLENGTH");
+    }
+
+    impl_ = new GenericImpl(data);
+}
+
+Generic::~Generic()
+{
+    delete impl_;
+}
+
+Generic::Generic(const Generic& source) :
+    impl_(new GenericImpl(*source.impl_))
+{}
+
+Generic&
+Generic::operator=(const Generic& source)
+{
+    if (impl_ == source.impl_) {
+        return (*this);
+    }
+
+    GenericImpl* newimpl = new GenericImpl(*source.impl_);
+    delete impl_;
+    impl_ = newimpl;
+
+    return (*this);
+}
+
+namespace {
+class UnknownRdataDumper {
+public:
+    UnknownRdataDumper(ostringstream& oss) : oss_(&oss) {}
+    void operator()(const unsigned char d)
+    {
+        *oss_ << setw(2) << static_cast<unsigned int>(d);
+    }
+private:
+    ostringstream* oss_;
+};
 }
 
 string
 Generic::toText() const
 {
-    // return rdata in the \# n xx xx format (TBD)
-    dns_throw(InvalidRdataText, "Not implemented yet");
+    ostringstream oss;
+
+    oss << "\\# " << impl_->data_.size() << " ";
+    oss.fill('0');
+    oss << right << hex;
+    for_each(impl_->data_.begin(), impl_->data_.end(), UnknownRdataDumper(oss));
+
+    return (oss.str());
 }
 
 void
 Generic::toWire(OutputBuffer& buffer) const
 {
-    buffer.writeData(&data_[0], data_.size());
+    buffer.writeData(&impl_->data_[0], impl_->data_.size());
 }
 
 void
 Generic::toWire(MessageRenderer& renderer) const
 {
-    renderer.writeData(&data_[0], data_.size());
-}
-
-int
-Generic::compare(const Rdata& other) const
-{
-    const Generic& other_rdata = dynamic_cast<const Generic&>(other);
-
-    size_t this_len = data_.size();
-    size_t other_len = other_rdata.data_.size();
+    renderer.writeData(&impl_->data_[0], impl_->data_.size());
+}
+
+namespace {
+inline int
+compare_internal(const GenericImpl& lhs, const GenericImpl& rhs)
+{
+    size_t this_len = lhs.data_.size();
+    size_t other_len = rhs.data_.size();
     size_t len = (this_len < other_len) ? this_len : other_len;
     int cmp;
 
-    if ((cmp = memcmp(&data_[0], &other_rdata.data_[0], len)) != 0) {
+    if ((cmp = memcmp(&lhs.data_[0], &rhs.data_[0], len))
+        != 0) {
         return (cmp);
     } else {
         return ((this_len == other_len) ? 0 :
                 (this_len < other_len) ? -1 : 1);
     }
 }
-
+}
+
+int
+Generic::compare(const Rdata& other) const
+{
+    const Generic& other_rdata = dynamic_cast<const Generic&>(other);
+
+    return (compare_internal(*impl_, *other_rdata.impl_));
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Generic& rdata)
+{
+    return (os << rdata.toText());
+}
 } // end of namespace generic
 
-namespace in {
-} // end of namespace in
-
-namespace ch {
-} // end of namespace ch
 } // end of namespace rdata
 }
 }

Modified: trunk/src/lib/dns/cpp/rdata.h
==============================================================================
--- trunk/src/lib/dns/cpp/rdata.h (original)
+++ trunk/src/lib/dns/cpp/rdata.h Thu Feb 25 22:50:58 2010
@@ -21,8 +21,6 @@
 
 #include <boost/shared_ptr.hpp>
 
-#include "name.h"
-
 namespace isc {
 namespace dns {
 class InputBuffer;
@@ -55,7 +53,9 @@
 };
 
 ///
-/// \brief A standard DNS module exception that is thrown if ...TBD
+/// \brief A standard DNS module exception that is thrown if RDATA parser
+/// parser encounters a character-string (as defined in RFC1035) exceeding
+/// the maximum allowable length (\c MAX_CHARSTRING_LEN).
 ///
 class CharStringTooLong : public Exception {
 public:
@@ -63,89 +63,403 @@
         isc::Exception(file, line, what) {}
 };
 
+// Forward declaration to define RdataPtr.
 class Rdata;
+
+///
+/// The \c RdataPtr type is a pointer-like type, pointing to an
+/// object of some concrete derived class of \c Rdata.
+///
 typedef boost::shared_ptr<Rdata> RdataPtr;
 typedef boost::shared_ptr<const Rdata> ConstRdataPtr;
 
-/// Abstract RDATA class
+/// \brief Possible maximum length of RDATA, which is the maximum unsigned
+/// 16 bit value.
+const size_t MAX_RDLENGTH = 65535;
+
+/// \brief The maximum allowable length of character-string containing in
+/// RDATA as defined in RFC1035, not including the 1-byte length field.
+const unsigned int MAX_CHARSTRING_LEN = 255;
+
+/// \brief The \c Rdata class is an abstract base class that provides
+/// a set of common interfaces to manipulate concrete RDATA objects.
+///
+/// Generally, a separate derived class directly inherited from the base
+/// \c Rdata class is defined for each well known RDATA.
+/// Each of such classes will define the common logic based on the
+/// corresponding protocol standard.
+///
+/// Since some types of RRs are class specific and the corresponding RDATA
+/// may have different semantics (e.g. type A for class IN and type A for
+/// class CH have different representations and semantics), we separate
+/// \c Rdata derived classes for such RR types in different namespaces.
+/// The namespace of types specific to a class is named the lower-cased class
+/// name; for example, RDATA of class IN-specific types are defined in the
+/// \c in namespace, and RDATA of class CH-specific types are defined in
+/// the \c ch namespace, and so on.
+/// The derived classes are named using the RR type name (upper cased) such as
+/// \c A or \c AAAA.
+/// Thus RDATA of type A RR for class IN and CH are defined as \c in::A and
+/// \c ch::A, respectively.
+/// Many other RR types are class independent; the derived \c Rdata classes
+/// for such RR types are defined in the \c generic namespace.  Examples are
+/// \c generic::NS and \c generic::SOA.
+///
+/// If applications need to refer to these derived classes, it is generally
+/// recommended to prepend at least some part of the namespace because the
+/// same class name can be used in different namespaces.
+/// So, instead of doing
+/// \code using namespace isc::dns::rdata::in;
+/// A& rdata_type_a; \endcode
+/// it is advisable to prepend at least \c in from the namespace:
+/// \code using namespace isc::dns::rdata;
+/// in::A& rdata_type_a; \endcode
+///
+/// In many cases, however, an application doesn't have to care about such
+/// derived classes.
+/// For instance, to parse an incoming DNS message an application wouldn't
+/// have to perform type specific operation unless the application is
+/// specifically concerned about a particular type.
+/// So, this API generally handles \c Rdata in a polymorphic way through
+/// a pointer or reference to this base abstract class.
 class Rdata {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are intentionally
+    /// defined as private.  Concrete classes should generally specialize their
+    /// own versions of these methods.
+    //@{
 protected:
+    /// The default constructor.
+    ///
+    /// This is intentionally defined as \c protected as this base class should
+    /// never be instantiated (except as part of a derived class).  In many
+    /// cases, the derived class wouldn't define a public default constructor
+    /// either, because an \c Rdata object without concrete data isn't
+    /// meaningful.
     Rdata() {}
 private:
-    /// Copy constructor is intentionally private.  Concrete classes should
-    /// generally specialize their own versions of copy constructor.
     Rdata(const Rdata& source);
     void operator=(const Rdata& source);
 public:
+    /// The destructor.
     virtual ~Rdata() {};
-
-    ///
-    /// \name Getter Methods
-    //
-    // need generic method for getting n-th field? c.f. ldns
-    // e.g. string getField(int n);
+    //@}
+
+    ///
+    /// \name Converter methods
     ///
     //@{
-    // It's not yet clear if we really need to contain the RR type (and/or
-    // RR class) in RDATA.
-    //virtual const RRType& getType() const = 0;
-    //@}
-
-    ///
-    /// \name Converter methods
-    ///
-    //@{
+    /// \brief Convert an \c Rdata to a string.
+    ///
+    /// This method returns a \c std::string object representing the \c Rdata.
+    ///
+    /// This is a pure virtual method without the definition; the actual
+    /// representation is specific to each derived concrete class and
+    /// should be explicitly defined in the derived class.
+    ///
+    /// \return A string representation of \c Rdata.
     virtual std::string toText() const = 0;
+    /// \brief Render the \c Rdata in the wire format into a buffer.
+    ///
+    /// This is a pure virtual method without the definition; the actual
+    /// conversion is specific to each derived concrete class and
+    /// should be explicitly defined in the derived class.
+    ///
+    /// \param buffer An output buffer to store the wire data.
     virtual void toWire(OutputBuffer& buffer) const = 0;
+    /// \brief Render the \c Rdata in the wire format into a
+    /// \c MessageRenderer object.
+    ///
+    /// This is a pure virtual method without the definition; the actual
+    /// conversion is specific to each derived concrete class and
+    /// should be explicitly defined in the derived class.
+    ///
+    /// \param renderer DNS message rendering context that encapsulates the
+    /// output buffer in which the \c Rdata is to be stored.
     virtual void toWire(MessageRenderer& renderer) const = 0;
     //@}
 
-    /// Note about implementation choice: the current implementation relies on
-    /// dynamic_cast to ensure that the \c other is the same concrete Rdata
-    /// class as \c this object.  Alternatively, we could first convert the
-    /// data into wire-format and compare the pair as opaque data.  This would
-    /// be more polymorphic, but might involve significant overhead, especially
-    /// for a large size of RDATA.
+    ///
+    /// \name Comparison method
+    ///
+    //@{
+    /// \brief Compare two instances of \c Rdata.
+    ///
+    /// This method compares \c this and the \c other Rdata objects
+    /// in terms of the DNSSEC sorting order as defined in RFC4034, and returns
+    /// the result as an integer.
+    ///
+    /// This is a pure virtual method without the definition; the actual
+    /// comparison logic is specific to each derived concrete class and
+    /// should be explicitly defined in the derived class.
+    ///
+    /// Specific implementations of this method must confirm that \c this
+    /// and the \c other are objects of the same concrete derived class of
+    /// \c Rdata.  This is normally done by \c dynamic_cast in the
+    /// implementation.  It also means if the assumption isn't met
+    /// an exception of class \c std::bad_cast will be thrown.
+    ///
+    /// Here is an implementation choice: instead of relying on
+    /// \c dynamic_cast, we could first convert the data into wire-format
+    /// and compare the pair as opaque data.  This would be more polymorphic,
+    /// but might involve significant overhead, especially for a large size
+    /// of RDATA.
+    ///
+    /// \param other the right-hand operand to compare against.
+    /// \return < 0 if \c this would be sorted before \c other.
+    /// \return 0 if \c this is identical to \c other in terms of sorting order.
+    /// \return > 0 if \c this would be sorted after \c other.
     virtual int compare(const Rdata& other) const = 0;
-
-    // not yet:
-    // methods specific derived classes: throw an exception by default
-    //virtual Address& getAddress() = 0;
-    //virtual Name& getName() = 0;
-
-    // polymorphic copy constructor (XXX should revisit it)
-    //virtual Rdata* copy() const = 0;
+    //@}
 };
 
 namespace generic {
+
+/// \brief The \c GenericImpl class is the actual implementation of the
+/// \c generic::Generic class.
+///
+/// The implementation is hidden from applications.  This approach requires
+/// dynamic memory allocation on construction, copy, or assignment, but
+/// we believe it should be acceptable as "unknown" RDATA should be pretty
+/// rare.
+struct GenericImpl;
+
+/// \brief The \c generic::Generic class represents generic "unknown" RDATA.
+///
+/// This class is used as a placeholder for all non well-known type of RDATA.
+/// By definition, the stored data is regarded as opaque binary without
+/// assuming any structure.
 class Generic : public Rdata {
 public:
+    ///
+    /// \name Constructors, Assignment Operator and Destructor.
+    ///
+    //@{
+    /// \brief Constructor from a string.
+    ///
+    /// This method constructs a \c generic::Generic object from a textual
+    /// representation as defined in RFC3597.
+    ///
+    /// If \c rdata_string isn't a valid textual representation of this type
+    /// of RDATA, an exception of class \c InvalidRdataText or
+    /// \c InvalidRdataLength will be thrown.
+    /// If resource allocation to store the data fails, a corresponding standard
+    /// exception will be thrown.
+    ///
+    /// \param rdata_string A string of textual representation of generic
+    /// RDATA.
     explicit Generic(const std::string& rdata_string);
-    explicit Generic(InputBuffer& buffer, size_t rdata_len);
+    ///
+    /// \brief Constructor from wire-format data.
+    ///
+    /// The \c buffer parameter normally stores a complete DNS message
+    /// containing the generic RDATA to be constructed.
+    /// The current read position of the buffer points to the head of the
+    /// data.
+    ///
+    /// This method reads \c rdata_len bytes from the \c buffer, and internally
+    /// stores the data as an opaque byte sequence.
+    ///
+    /// \c rdata_len must not exceed \c MAX_RDLENGTH; otherwise, an exception
+    /// of class \c InvalidRdataLength will be thrown.
+    /// If resource allocation to hold the data fails, a corresponding standard
+    /// exception will be thrown; if the \c buffer doesn't contain \c rdata_len
+    /// bytes of unread data, an exception of class \c InvalidBufferPosition
+    /// will be thrown.
+    ///
+    /// \param buffer A reference to an \c InputBuffer object storing the
+    /// \c Rdata to parse.
+    /// \param rdata_len The length in buffer of the \c Rdata.  In bytes.
+    Generic(InputBuffer& buffer, size_t rdata_len);
+    ///
+    /// \brief The destructor.
+    virtual ~Generic();
+    ///
+    /// \brief The copy constructor.
+    ///
+    /// If resource allocation to copy the data fails, a corresponding standard
+    /// exception will be thrown.
+    ///
+    /// \param source A reference to a \c generic::Generic object to copy from.
+    Generic(const Generic& source);
+    ///
+    /// \brief The assignment operator.
+    ///
+    /// If resource allocation to copy the data fails, a corresponding standard
+    /// exception will be thrown.
+    ///
+    /// \param source A reference to a \c generic::Generic object to copy from.
+    Generic& operator=(const Generic& source);
+    //@}
+    ///
+    /// \name Converter methods
+    ///
+    //@{
+    /// \brief Convert an \c generic::Generic object to a string.
+    ///
+    /// This method converts a generic "unknown" RDATA object into a textual
+    /// representation of such unknown data as defined in RFC3597.
+    ///
+    /// If resource allocation to copy the data fails, a corresponding standard
+    /// exception will be thrown.
+    ///
+    /// \return A string representation of \c generic::Generic.
     virtual std::string toText() const;
+    ///
+    /// \brief Render the \c generic::Generic in the wire format into a buffer.
+    ///
+    /// This will require \c rdata_len bytes of remaining capacity in the
+    /// \c buffer.  If this is not the case and resource allocation for the
+    /// necessary memory space fails, a corresponding standard exception will
+    /// be thrown.
+    ///
+    /// \param buffer An output buffer to store the wire data.
     virtual void toWire(OutputBuffer& buffer) const;
+    /// \brief Render the \c generic::Generic in the wire format into a
+    /// \c MessageRenderer object.
+    ///
+    /// This will require \c rdata_len bytes of remaining capacity in the
+    /// \c buffer.  If this is not the case and resource allocation for the
+    /// necessary memory space fails, a corresponding standard exception will
+    /// be thrown.
+    ///
+    /// \param renderer DNS message rendering context that encapsulates the
+    /// output buffer in which the \c Generic object is to be stored.
     virtual void toWire(MessageRenderer& renderer) const;
-    ///
-    /// Note: the comparison is RR type/class agnostic: this method doesn't
-    /// check whether the two Rdata objects to compare are of the comparable
-    /// RR type/class.  The caller must ensure this condition.
-    ///
+    //@}
+    ///
+    /// \name Comparison method
+    ///
+    //@{
+    /// \brief Compare two instances of \c generic::Generic objects.
+    ///
+    /// As defined in RFC4034, this method simply compares the wire-format
+    /// representations of the two objects as left-justified unsigned octet
+    /// sequences.
+    ///
+    /// The object referenced by \c other must have been instantiated as
+    /// a c generic::Generic class object; otherwise, an exception of class
+    /// \c std::bad_cast will be thrown.
+    /// Note that the comparison is RR type/class agnostic: this method doesn't
+    /// check whether the two \c Rdata objects to compare are of the comparable
+    /// RR type/class.  For example, \c this object may come from an \c RRset
+    /// of \c RRType x, and the \c other may come from a different \c RRset
+    /// of \c RRType y (where x != y).  This situation would be considered a
+    /// bug, but this method cannot detect this type of error.
+    /// The caller must ensure this condition.
+    ///
+    /// \param other the right-hand operand to compare against.
+    /// \return < 0 if \c this would be sorted before \c other.
+    /// \return 0 if \c this is identical to \c other in terms of sorting order.
+    /// \return > 0 if \c this would be sorted after \c other.
     virtual int compare(const Rdata& other) const;
+    //@}
 private:
-    std::vector<uint8_t> data_;
+    GenericImpl* impl_;
 };
+
+///
+/// \brief Insert the name as a string into stream.
+///
+/// This method convert the \c rdata into a string and inserts it into the
+/// output stream \c os.
+///
+/// This function overloads the global \c operator<< to behave as described in
+/// \c ostream::operator<< but applied to \c generic::Generic Rdata objects.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param rdata The \c Generic 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 Generic& rdata);
 } // end of namespace "generic"
 
-///
-/// Non class-member functions related to Rdata
-///
-/// TBD: document them
+//
+// Non class-member functions related to Rdata
+//
+
+///
+/// \name Parameterized Polymorphic RDATA Factories
+///
+/// This set of global functions provide a unified interface to create an
+/// \c Rdata object in a parameterized polymorphic way,
+/// that is, these functions take a pair of \c RRType and \c RRClass
+/// objects and data specific to that pair, and create an object of
+/// the corresponding concrete derived class of \c Rdata.
+///
+/// These will be useful when parsing/constructing a DNS message or
+/// parsing a master file, where information for a specific type of RDATA
+/// is given but the resulting object, once created, should better be used
+/// in a polymorphic way.
+///
+/// For example, if a master file parser encounters an NS RR
+/// \verbatim example.com. 3600 IN NS ns.example.com.\endverbatim
+/// it stores the text fragments "IN", "NS", and "ns.example.com." in
+/// \c std::string objects \c class_txt, \c type_txt, and \c nsname_txt,
+/// respectively, then it would create a new \c RdataPtr object as follows:
+/// \code RdataPtr rdata = createRdata(RRType(type_txt), RRClass(class_txt),
+///                              nsname_txt); \endcode
+/// On success, \c rdata will point to an object of the \c generic::NS class
+/// that internally holds a domain name of "ns.example.com."
+///
+/// Internally, these functions uses the corresponding
+/// \c RRParamRegistry::createRdata methods of the \c RRParamRegistry.
+/// See also the description on these methods for related notes.
+//@{
+/// \brief Create RDATA of a given pair of RR type and class from a string.
+///
+/// This method creates from a string an \c Rdata object of the given pair
+/// of RR type and class.
+///
+/// \param rrtype An \c RRType object specifying the type/class pair.
+/// \param rrclass An \c RRClass object specifying the type/class pair.
+/// \param rdata_string A string of textual representation of the \c Rdata.
+/// \return An \c RdataPtr object pointing to the created \c Rdata
+/// object.
 RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                      const std::string& rdata_string);
+/// \brief Create RDATA of a given pair of RR type and class from
+/// wire-format data.
+///
+/// This method creates from wire-format binary data an \c Rdata object
+/// of the given pair of RR type and class.
+///
+/// \c len must not exceed the protocol defined maximum value, \c MAX_RDLENGTH;
+/// otherwise, an exception of class \c InvalidRdataLength will be thrown.
+///
+/// In some cases, the length of the RDATA is determined without the
+/// information of \c len.  For example, the RDATA length of an IN/A RR
+/// must always be 4.  If \c len is not equal to the actual length in such
+/// cases, an exception of class InvalidRdataLength will be thrown.
+///
+/// \param rrtype An \c RRType object specifying the type/class pair.
+/// \param rrclass An \c RRClass object specifying the type/class pair.
+/// \param buffer A reference to an \c InputBuffer object storing the
+/// \c Rdata to parse.
+/// \param len The length in buffer of the \c Rdata.  In bytes.
+/// \return An \c RdataPtr object pointing to the created \c Rdata
+/// object.
 RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                      InputBuffer& buffer, size_t len);
+/// \brief Create RDATA of a given pair of RR type and class, copying
+/// of another RDATA of same kind.
+///
+/// This method creates an \c Rdata object of the given pair of
+/// RR type and class, copying the  content of the given \c Rdata,
+/// \c source.
+///
+/// \param rrtype An \c RRType object specifying the type/class pair.
+/// \param rrclass An \c RRClass object specifying the type/class pair.
+/// \param source A reference to an \c Rdata object whose content
+/// is to be copied to the created \c Rdata object.
+/// \return An \c RdataPtr object pointing to the created
+/// \c Rdata object.
 RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                      const Rdata& source);
+//@}
 
 ///
 /// \brief Gives relative ordering of two names in terms of DNSSEC RDATA
@@ -165,6 +479,9 @@
 /// This function is publicly open, however, for the convenience of
 /// external developers who want to implement new or experimental RR types.
 ///
+/// This function never throws an exception as long as the given names are
+/// valid \c Name objects.
+///
 /// Additional note about applicability: In fact, BIND9's similar function,
 /// \c dns_name_rdatacompare(), is only used in rdata implementations and
 /// for testing purposes.
@@ -174,8 +491,7 @@
 /// \return 0 if \c n1 is identical to \c n2 in terms of sorting order.
 /// \return 1 if \c n1 would be sorted after \c n2.
 ///
-int
-compareNames(const Name& n1, const Name& n2);
+int compareNames(const Name& n1, const Name& n2);
 
 } // end of namespace "rdata"
 }

Modified: trunk/src/lib/dns/cpp/rdata/generic/txt_16.h
==============================================================================
--- trunk/src/lib/dns/cpp/rdata/generic/txt_16.h (original)
+++ trunk/src/lib/dns/cpp/rdata/generic/txt_16.h Thu Feb 25 22:50:58 2010
@@ -37,7 +37,6 @@
 private:
     /// Note: this is a prototype version; we may reconsider
     /// this representation later.
-    static const unsigned int MAX_CHARSTRING_LEN = 255;
     std::vector<std::vector<uint8_t> > string_list_;
 };
 

Modified: trunk/src/lib/dns/cpp/rdata/template.h
==============================================================================
--- trunk/src/lib/dns/cpp/rdata/template.h (original)
+++ trunk/src/lib/dns/cpp/rdata/template.h Thu Feb 25 22:50:58 2010
@@ -37,10 +37,15 @@
 // "RR-type specific members" space (please make them private).  In addition,
 // you may want to define some specific member functions, either public or
 // private (or, though unlikely for a leaf class, protected).
+//
+// Note: do not remove the comment lines beginning with "BEGIN_" and "END_".
+// These are markers used by a script for auto-generating build-able source
+// files.
 
 class MyType : public Rdata {
 public:
     // BEGIN_COMMON_MEMBERS
+    // Do not remove the BEGIN_xxx and END_xxx comment lines.
     // END_COMMON_MEMBERS
 private:
     // RR-type specific members are here.

Modified: trunk/src/lib/dns/cpp/rrparamregistry-placeholder.cc
==============================================================================
--- trunk/src/lib/dns/cpp/rrparamregistry-placeholder.cc (original)
+++ trunk/src/lib/dns/cpp/rrparamregistry-placeholder.cc Thu Feb 25 22:50:58 2010
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// $Id: rrparamregistry.cc 530 2010-01-26 22:15:42Z jinmei $
+// $Id$
 
 #include <cassert>
 #include <algorithm>
@@ -72,22 +72,43 @@
 
     /// magic constants
     static const unsigned int MAX_CODE = 0xffff;
-    static const string UNKNOWN_PREFIX;
-    static const size_t UNKNOWN_PREFIXLEN;
-    static const string UNKNOWN_MAX;
-    static const size_t UNKNOWN_MAXLEN;
+    static const string& UNKNOWN_PREFIX();
+    static size_t UNKNOWN_PREFIXLEN();
+    static const string& UNKNOWN_MAX();
+    static size_t UNKNOWN_MAXLEN();
 };
 
 typedef shared_ptr<RRTypeParam> RRTypeParamPtr;
 typedef map<string, RRTypeParamPtr, CIStringLess> StrRRTypeMap;
 typedef map<uint16_t, RRTypeParamPtr> CodeRRTypeMap;
 
-const string RRTypeParam::UNKNOWN_PREFIX = "TYPE";
-const size_t RRTypeParam::UNKNOWN_PREFIXLEN =
-    RRTypeParam::UNKNOWN_PREFIX.size();
-const string RRTypeParam::UNKNOWN_MAX = "TYPE65535";
-const size_t RRTypeParam::UNKNOWN_MAXLEN =
-    RRTypeParam::UNKNOWN_MAX.size();
+inline const string&
+RRTypeParam::UNKNOWN_PREFIX()
+{
+    static const string p("TYPE");
+    return (p);
+}
+
+inline size_t
+RRTypeParam::UNKNOWN_PREFIXLEN()
+{
+    static size_t plen = UNKNOWN_PREFIX().size();
+    return (plen);
+}
+
+inline const string&
+RRTypeParam::UNKNOWN_MAX()
+{
+    static const string p("TYPE65535");
+    return (p);
+}
+
+inline size_t
+RRTypeParam::UNKNOWN_MAXLEN()
+{
+    static size_t plen = UNKNOWN_MAX().size();
+    return (plen);
+}
 
 struct RRClassParam {
     RRClassParam(const string& code_string, uint16_t code) :
@@ -97,23 +118,44 @@
 
     /// magic constants
     static const unsigned int MAX_CODE = 0xffff;
-    static const string UNKNOWN_PREFIX;
-    static const size_t UNKNOWN_PREFIXLEN;
-    static const string UNKNOWN_MAX;
-    static const size_t UNKNOWN_MAXLEN;
+    static const string& UNKNOWN_PREFIX();
+    static size_t UNKNOWN_PREFIXLEN();
+    static const string& UNKNOWN_MAX();
+    static size_t UNKNOWN_MAXLEN();
 };
 
 typedef shared_ptr<RRClassParam> RRClassParamPtr;
 typedef map<string, RRClassParamPtr, CIStringLess> StrRRClassMap;
 typedef map<uint16_t, RRClassParamPtr> CodeRRClassMap;
 
-const string RRClassParam::UNKNOWN_PREFIX = "CLASS";
-const size_t RRClassParam::UNKNOWN_PREFIXLEN =
-    RRClassParam::UNKNOWN_PREFIX.size();
-const string RRClassParam::UNKNOWN_MAX = "CLASS65535";
-const size_t RRClassParam::UNKNOWN_MAXLEN =
-    RRClassParam::UNKNOWN_MAX.size();
-}
+inline const string&
+RRClassParam::UNKNOWN_PREFIX()
+{
+    static const string p("CLASS");
+    return (p);
+}
+
+inline size_t
+RRClassParam::UNKNOWN_PREFIXLEN()
+{
+    static size_t plen = UNKNOWN_PREFIX().size();
+    return (plen);
+}
+
+inline const string&
+RRClassParam::UNKNOWN_MAX()
+{
+    static const string p("CLASS65535");
+    return (p);
+}
+
+inline size_t
+RRClassParam::UNKNOWN_MAXLEN()
+{
+    static size_t plen = UNKNOWN_MAX().size();
+    return (plen);
+}
+} // end of anonymous namespace
 
 /// Note: the element ordering in the type/class pair is intentional.
 /// The standard library will perform inequality comparison (i.e, '<')
@@ -132,17 +174,17 @@
 public:
     virtual RdataPtr create(const string& rdata_str) const
     {
-        return (shared_ptr<T>(new T(rdata_str)));
+        return (RdataPtr(new T(rdata_str)));
     }
 
     virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const
     {
-        return (shared_ptr<T>(new T(buffer, rdata_len)));
+        return (RdataPtr(new T(buffer, rdata_len)));
     }
 
     virtual RdataPtr create(const Rdata& source) const
     {
-        return (shared_ptr<T>(new T(dynamic_cast<const T&>(source))));
+        return (RdataPtr(new T(dynamic_cast<const T&>(source))));
     }
 };
 
@@ -171,7 +213,6 @@
     impl_ = new RRParamRegistryImpl;
 
     // set up parameters for well-known RRs
-    // XXX: this should eventually be more automatic.
     try {
         // BEGIN_WELL_KNOWN_PARAMS
         // END_WELL_KNOWN_PARAMS
@@ -244,6 +285,33 @@
     }
 }
 
+bool
+RRParamRegistry::removeRdataFactory(const RRType& rrtype,
+                                    const RRClass& rrclass)
+{
+    RdataFactoryMap::iterator found =
+        impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
+    if (found != impl_->rdata_factories.end()) {
+        impl_->rdata_factories.erase(found);
+        return (true);
+    }
+
+    return (false);
+}
+
+bool
+RRParamRegistry::removeRdataFactory(const RRType& rrtype)
+{
+    GenericRdataFactoryMap::iterator found =
+        impl_->genericrdata_factories.find(rrtype);
+    if (found != impl_->genericrdata_factories.end()) {
+        impl_->genericrdata_factories.erase(found);
+        return (true);
+    }
+
+    return (false);
+}
+
 namespace {
 ///
 /// These are helper functions to implement case-insensitive string comparison.
@@ -338,12 +406,13 @@
     }
 
     size_t l = code_str.size();
-    if (l > PT::UNKNOWN_PREFIXLEN &&
-        l <= PT::UNKNOWN_MAXLEN &&
-        caseStringEqual(code_str, PT::UNKNOWN_PREFIX, PT::UNKNOWN_PREFIXLEN)) {
+    if (l > PT::UNKNOWN_PREFIXLEN() &&
+        l <= PT::UNKNOWN_MAXLEN() &&
+        caseStringEqual(code_str, PT::UNKNOWN_PREFIX(),
+                        PT::UNKNOWN_PREFIXLEN())) {
         unsigned int code;
-        istringstream iss(code_str.substr(PT::UNKNOWN_PREFIXLEN,
-                                           l - PT::UNKNOWN_PREFIXLEN));
+        istringstream iss(code_str.substr(PT::UNKNOWN_PREFIXLEN(),
+                                          l - PT::UNKNOWN_PREFIXLEN()));
         iss >> dec >> code;
         if (iss.rdstate() == ios::eofbit && code <= PT::MAX_CODE) {
             return (code);
@@ -365,7 +434,7 @@
 
     ostringstream ss;
     ss << code;
-    return (PT::UNKNOWN_PREFIX + ss.str());
+    return (PT::UNKNOWN_PREFIX() + ss.str());
 }
 }
 
@@ -444,7 +513,7 @@
         return (genfound->second->create(rdata_string));
     }
 
-    dns_throw(InvalidRdataText, "Unrecognized Rdata type to create from text");
+    return (RdataPtr(new generic::Generic(rdata_string)));
 }
 
 RdataPtr
@@ -463,7 +532,6 @@
         return (genfound->second->create(buffer, rdata_len));
     }
 
-    // construct an "unknown" type of RDATA
     return (RdataPtr(new generic::Generic(buffer, rdata_len)));
 }
 
@@ -483,7 +551,8 @@
         return (genfound->second->create(source));
     }
 
-    dns_throw(InvalidRdataText, "TBD");
-}
-}
-}
+    return (RdataPtr(new rdata::generic::Generic(
+                         dynamic_cast<const generic::Generic&>(source))));
+}
+}
+}

Modified: trunk/src/lib/dns/cpp/rrparamregistry.h
==============================================================================
--- trunk/src/lib/dns/cpp/rrparamregistry.h (original)
+++ trunk/src/lib/dns/cpp/rrparamregistry.h Thu Feb 25 22:50:58 2010
@@ -52,26 +52,79 @@
         isc::Exception(file, line, what) {}
 };
 
-class InvalidRdataText : public Exception {
-public:
-    InvalidRdataText(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
 namespace rdata {
+/// \brief The \c AbstractRdataFactory class is an abstract base class to
+/// encapsulate a set of Rdata factory methods in a polymorphic way.
+///
+/// An external developers who want to introduce a new or experimental RR type
+/// are expected to define a corresponding derived class of \c
+/// AbstractRdataFactory and register it via \c RRParamRegistry.
+///
+/// For other users of this API normally do not have to care about this class
+/// or its derived classes; this class is generally intended to be used
+/// as an internal utility of the API implementation.
 class AbstractRdataFactory {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    //@{
 protected:
+    /// The default constructor
+    ///
+    /// This is intentionally defined as \c protected as this base class should
+    /// never be instantiated (except as part of a derived class).
     AbstractRdataFactory() {}
 public:
+    /// The destructor.
     virtual ~AbstractRdataFactory() {};
-
-    // Factory methods for polymorphic creation:
+    //@}
+
+    ///
+    /// \name Factory methods for polymorphic creation.
+    ///
+    //@{
+    ///
+    /// \brief Create RDATA from a string.
+    ///
+    /// This method creates from a string an \c Rdata object of specific class
+    /// corresponding to the specific derived class of \c AbstractRdataFactory.
+    ///
+    /// \param rdata_str A string of textual representation of the \c Rdata.
+    /// \return An \c RdataPtr object pointing to the created \c Rdata object.
     virtual RdataPtr create(const std::string& rdata_str) const = 0;
+    ///
+    /// \brief Create RDATA from wire-format data.
+    ///
+    /// This method creates from wire-format binary data an \c Rdata object
+    /// of specific class corresponding to the specific derived class of
+    /// \c AbstractRdataFactory.
+    ///
+    /// \param buffer A reference to an \c InputBuffer object storing the
+    /// \c Rdata to parse.
+    /// \param rdata_len The length in buffer of the \c Rdata.  In bytes.
+    /// \return An \c RdataPtr object pointing to the created \c Rdata object.
     virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const = 0;
+    ///
+    /// \brief Create RDATA from another \c Rdata object of the same type.
+    ///
+    /// This method creates an \c Rdata object of specific class corresponding
+    /// to the specific derived class of \c AbstractRdataFactory, copying the
+    /// content of the given \c Rdata, \c source.
+    ///
+    /// \c source must be an object of the concrete derived class corresponding
+    /// to the specific derived class of \c AbstractRdataFactory;
+    /// otherwise, an exception of class \c std::bad_cast will be thrown.
+    ///
+    /// \param source A reference to an \c Rdata object whose content is to
+    /// be copied to the created \c Rdata object.
+    /// \return An \c RdataPtr object pointing to the created \c Rdata object.
     virtual RdataPtr create(const rdata::Rdata& source) const = 0;
+    //@}
 };
-///
-/// TBD: describe it
+
+///
+/// The \c RdataFactoryPtr type is a pointer-like type, pointing to an
+/// object of some concrete derived class of \c AbstractRdataFactory.
 ///
 typedef boost::shared_ptr<AbstractRdataFactory> RdataFactoryPtr;
 } // end of namespace rdata
@@ -158,7 +211,7 @@
     /// representations.
     ///
     /// Regarding the mappings between textual representations and integer
-    /// codes, this methods behaves in the same way as \c addType() and
+    /// codes, this method behaves in the same way as \c addType() and
     /// \c addClass().  That is, it ignores any overriding attempt as
     /// long as the mapping is the same; otherwise the corresponding exception
     /// will be thrown.
@@ -168,18 +221,25 @@
     /// stored in the registry; if this method throws an exception the
     /// registry will remain in the state before this method is called.
     ///
-    /// Note: this method will be extended to support more parameters in a
-    /// near future version.
-    ///
     /// \param type_string The textual representation of the RR type.
     /// \param type_code The integer code of the RR type.
     /// \param class_string The textual representation of the RR class.
     /// \param class_code The integer code of the RR class.
+    /// \param rdata_factory An \c RdataFactoryPtr object pointing to a
+    /// concrete RDATA factory.
     void add(const std::string& type_string, uint16_t type_code,
              const std::string& class_string, uint16_t class_code,
              rdata::RdataFactoryPtr rdata_factory);
 
-    /// TBD
+    /// \brief Add a set of parameters for a class-independent RR type.
+    ///
+    /// This method behaves as exactly same as the other \c add method except
+    /// that it handles class-independent types (such as NS, CNAME, or SOA).
+    ///
+    /// \param type_string The textual representation of the RR type.
+    /// \param type_code The integer code of the RR type.
+    /// \param rdata_factory An \c RdataFactoryPtr object pointing to a
+    /// concrete RDATA factory.
     void add(const std::string& type_string, uint16_t type_code,
              rdata::RdataFactoryPtr rdata_factory);
 
@@ -219,7 +279,7 @@
     /// exist in the registry.  If not, this method simply ignores the attempt
     /// and returns \c false.
     ///
-    /// This method never throw an exception.
+    /// This method never throws an exception.
     ///
     /// \param type_code The integer code of the RR type.
     /// \return \c true if mappings for the specified RR type exists and is
@@ -251,7 +311,8 @@
     ///
     /// \param class_string The textual representation of the RR class.
     /// \param class_code The integer code of the RR class.
-    /// \return
+    /// \return \c true if a new mapping is added to the repository; \c false
+    /// if the same mapping is already registered.
     bool addClass(const std::string& class_string, uint16_t class_code);
 
     /// \brief Remove mappings between RR class code and textual representation
@@ -261,11 +322,43 @@
     /// exist in the registry.  If not, this method simply ignores the attempt
     /// and returns \c false.
     ///
-    /// This method never throw an exception.
+    /// This method never throws an exception.
     ///
     /// \param class_code The integer code of the RR class.
-    /// \return
+    /// \return \c true if mappings for the specified RR type exists and is
+    /// removed; \c false if no such mapping is in the registry.
     bool removeClass(uint16_t class_code);
+
+    /// \brief Remove registered RDATA factory for the given pair of \c RRType
+    /// and \c RRClass.
+    ///
+    /// This method can safely be called whether or not the specified factory
+    /// object exist in the registry.  If not, this method simply ignores the
+    /// attempt and returns \c false.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \param rrclass An \c RRClass object specifying the type/class pair.
+    /// \return \c true if a factory object for the specified RR type/class
+    /// pair exists and is removed; \c false if no such object is in the
+    /// registry.
+    bool removeRdataFactory(const RRType& rrtype, const RRClass& rrclass);
+
+    /// \brief Remove registered RDATA factory for the given pair of \c RRType
+    /// and \c RRClass.
+    ///
+    /// This method can safely be called whether or not the specified factory
+    /// object exist in the registry.  If not, this method simply ignores the
+    /// attempt and returns \c false.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \return \c true if a factory object for the specified RR type/class
+    /// pair exists and is removed; \c false if no such object is in the
+    /// registry.
+    bool removeRdataFactory(const RRType& rrtype);
     //@}
 
     ///
@@ -338,14 +431,72 @@
     ///
     /// \name RDATA Factories
     ///
+    /// This set of methods provide a unified interface to create an
+    /// \c rdata::Rdata object in a parameterized polymorphic way,
+    /// that is, these methods take a pair of \c RRType and \c RRClass
+    /// objects and data specific to that pair, and create an object of
+    /// the corresponding concrete derived class of \c rdata::Rdata.
+    ///
+    /// These methods first search the \c RRParamRegistry for a factory
+    /// method (a member of a concrete derived class of
+    /// \c AbstractRdataFactory) for the given RR type and class pair.
+    /// If the search fails, they then search for a factory method for
+    /// the given type ignoring the class, in case a RRClass independent
+    /// factory method is registered.
+    /// If it still fails, these methods assume the RDATA is of an "unknown"
+    /// type, and creates a new object by calling a constructor of the
+    /// \c rdata::generic::Generic class.
+    ///
     //@{
-    /// \brief TBD
+    /// \brief Create RDATA of a given pair of RR type and class from a string.
+    ///
+    /// This method creates from a string an \c Rdata object of the given pair
+    /// of RR type and class.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \param rrclass An \c RRClass object specifying the type/class pair.
+    /// \param rdata_string A string of textual representation of the \c Rdata.
+    /// \return An \c rdata::RdataPtr object pointing to the created \c Rdata
+    /// object.
     rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                 const std::string& rdata_string);
-    /// \brief TBD
+    /// \brief Create RDATA of a given pair of RR type and class from
+    /// wire-format data.
+    ///
+    /// This method creates from wire-format binary data an \c Rdata object
+    /// of the given pair of RR type and class.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \param rrclass An \c RRClass object specifying the type/class pair.
+    /// \param buffer A reference to an \c InputBuffer object storing the
+    /// \c Rdata to parse.
+    /// \param len The length in buffer of the \c Rdata.  In bytes.
+    /// \return An \c rdata::RdataPtr object pointing to the created \c Rdata
+    /// object.
     rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                 InputBuffer& buffer, size_t len);
-    /// \brief Polymorphic copy constructor (detailed TBD)
+    /// \brief Create RDATA of a given pair of RR type and class, copying
+    /// of another RDATA of same kind.
+    ///
+    /// This method creates an \c Rdata object of the given pair of
+    /// RR type and class, copying the  content of the given \c Rdata,
+    /// \c source.
+    ///
+    /// \c source must be an object of the concrete derived class of
+    /// \c rdata::Rdata for the given pair of RR type and class;
+    /// otherwise, an exception of class \c std::bad_cast will be thrown.
+    /// In case the \c RRParamRegistry doesn't have a factory method for
+    /// the given pair and it is assumed to be of an "unknown" type,
+    /// \c source must reference an object of class
+    /// \c rdata::generic::Generic; otherwise, an exception of class
+    /// \c std::bad_cast will be thrown.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \param rrclass An \c RRClass object specifying the type/class pair.
+    /// \param source A reference to an \c rdata::Rdata object whose content
+    /// is to be copied to the created \c rdata::Rdata object.
+    /// \return An \c rdata::RdataPtr object pointing to the created
+    /// \c rdata::Rdata object.
     rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                 const rdata::Rdata& source);
     //@}




More information about the bind10-changes mailing list