diff --git a/ChangeLog b/ChangeLog index d6cf8104a27972f3cd94a11378e55c88cb57cf72..705967350ed39e027c7b17adf5b0bab95ed32490 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,28 @@ -219. [bug] feng +223. [bug] feng If ip address or port isn't usable for name server, name server process won't exist and give end user chance to reconfigure them. (Trac #775, git 572ac2cf62e18f7eb69d670b890e2a3443bfd6e7) +222. [bug] jerry + src/lib/zonemgr: Fix a bug that xfrin not checking for new copy of + zone on startup. Imposes some random jitters to avoid many zones + need to do refresh at the same time. + (Trac #387, svn 9140fab9bab5f6502bd15d391fd51ac078b0b89b) + +221. [func]* jerry + src/lib/util: Create C++ utility library. + (Trac #749, git 084d1285d038d31067f8cdbb058d626acf03566d) + +220. [func] stephen + Added the 'badpacket' program for testing; it sends a set of + (potentially) bad packets to a nameserver and prints the responses. + (Trac #703, git 1b666838b6c0fe265522b30971e878d9f0d21fde) + +219. [func] ocean + src/lib: move some dns related code out of asiolink library to + asiodns library + (Trac #751, git 262ac6c6fc61224d54705ed4c700dadb606fcb1c) + 218. [func] jinmei src/lib/dns: added support for RP RDATA. (Trac #806, git 4e47d5f6b692c63c907af6681a75024450884a88) diff --git a/configure.ac b/configure.ac index 8e16d3b904784859cdba56ed7fc92e67923204bc..81df4765dc8d85f2ea7c830f0e70d46fb22fe449 100644 --- a/configure.ac +++ b/configure.ac @@ -612,6 +612,7 @@ AC_CONFIG_FILES([Makefile src/bin/bindctl/Makefile src/bin/bindctl/tests/Makefile src/bin/cfgmgr/Makefile + src/bin/cfgmgr/plugins/Makefile src/bin/cfgmgr/tests/Makefile src/bin/host/Makefile src/bin/loadzone/Makefile @@ -644,6 +645,8 @@ AC_CONFIG_FILES([Makefile src/lib/Makefile src/lib/asiolink/Makefile src/lib/asiolink/tests/Makefile + src/lib/asiodns/Makefile + src/lib/asiodns/tests/Makefile src/lib/bench/Makefile src/lib/bench/example/Makefile src/lib/bench/tests/Makefile @@ -669,11 +672,17 @@ AC_CONFIG_FILES([Makefile src/lib/config/Makefile src/lib/config/tests/Makefile src/lib/config/tests/testdata/Makefile + src/lib/util/Makefile + src/lib/util/io/Makefile + src/lib/util/io/tests/Makefile + src/lib/util/unittests/Makefile + src/lib/util/tests/Makefile src/lib/dns/Makefile src/lib/dns/tests/Makefile src/lib/dns/tests/testdata/Makefile src/lib/dns/python/Makefile src/lib/dns/python/tests/Makefile + src/lib/dns/benchmarks/Makefile src/lib/exceptions/Makefile src/lib/exceptions/tests/Makefile src/lib/datasrc/Makefile @@ -694,10 +703,9 @@ AC_CONFIG_FILES([Makefile src/lib/server_common/tests/Makefile tests/Makefile tests/system/Makefile - src/lib/util/Makefile - src/lib/util/io/Makefile - src/lib/util/io/tests/Makefile - src/lib/util/unittests/Makefile + tests/tools/Makefile + tests/tools/badpacket/Makefile + tests/tools/badpacket/tests/Makefile ]) AC_OUTPUT([doc/version.ent src/bin/cfgmgr/b10-cfgmgr.py diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am index dfe23eeef59bec612fac88e7f920f4374e91619a..56dc348f2185d50f61e24598546f927105ba62c0 100644 --- a/src/bin/auth/Makefile.am +++ b/src/bin/auth/Makefile.am @@ -49,6 +49,7 @@ b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la b10_auth_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.la b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la +b10_auth_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la b10_auth_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc index 9a49cc737c279828247c2daffd5fde892057b252..a863ef3d74343cc9ac72c998989c76c004f84595 100644 --- a/src/bin/auth/auth_srv.cc +++ b/src/bin/auth/auth_srv.cc @@ -31,7 +31,8 @@ #include -#include +#include + #include #include #include @@ -63,12 +64,14 @@ using namespace isc; using namespace isc::cc; using namespace isc::datasrc; using namespace isc::dns; +using namespace isc::util; using namespace isc::auth; using namespace isc::dns::rdata; using namespace isc::data; using namespace isc::config; using namespace isc::xfr; -using namespace asiolink; +using namespace isc::asiolink; +using namespace isc::asiodns; using namespace isc::server_common::portconfig; class AuthSrvImpl { @@ -766,6 +769,6 @@ AuthSrv::setListenAddresses(const AddressList& addresses) { } void -AuthSrv::setDNSService(asiolink::DNSService& dnss) { +AuthSrv::setDNSService(isc::asiodns::DNSService& dnss) { dnss_ = &dnss; } diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h index 8a6d52231565ad0fa4a60212a864084e3f6d2d62..88f00c1a14b85707138b2abc8cdae927332b761a 100644 --- a/src/bin/auth/auth_srv.h +++ b/src/bin/auth/auth_srv.h @@ -24,13 +24,13 @@ #include #include #include -#include +#include +#include +#include +#include #include #include -#include -#include -#include #include #include @@ -116,10 +116,10 @@ public: /// \param server Pointer to the \c DNSServer /// /// \throw isc::Unexpected Protocol type of \a message is unexpected - void processMessage(const asiolink::IOMessage& io_message, + void processMessage(const isc::asiolink::IOMessage& io_message, isc::dns::MessagePtr message, - isc::dns::OutputBufferPtr buffer, - asiolink::DNSServer* server); + isc::util::OutputBufferPtr buffer, + isc::asiodns::DNSServer* server); /// \brief Set verbose flag /// @@ -202,16 +202,16 @@ public: void setConfigSession(isc::config::ModuleCCSession* config_session); /// \brief Return this object's ASIO IO Service queue - asiolink::IOService& getIOService(); + isc::asiolink::IOService& getIOService(); /// \brief Return pointer to the DNS Lookup callback function - asiolink::DNSLookup* getDNSLookupProvider() const { return (dns_lookup_); } + isc::asiodns::DNSLookup* getDNSLookupProvider() const { return (dns_lookup_); } /// \brief Return pointer to the DNS Answer callback function - asiolink::DNSAnswer* getDNSAnswerProvider() const { return (dns_answer_); } + isc::asiodns::DNSAnswer* getDNSAnswerProvider() const { return (dns_answer_); } /// \brief Return pointer to the Checkin callback function - asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); } + isc::asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); } /// \brief Set or update the size (number of slots) of hot spot cache. /// @@ -372,15 +372,15 @@ public: const; /// \brief Assign an ASIO DNS Service queue to this Auth object - void setDNSService(asiolink::DNSService& dnss); + void setDNSService(isc::asiodns::DNSService& dnss); private: AuthSrvImpl* impl_; - asiolink::SimpleCallback* checkin_; - asiolink::DNSLookup* dns_lookup_; - asiolink::DNSAnswer* dns_answer_; - asiolink::DNSService* dnss_; + isc::asiolink::SimpleCallback* checkin_; + isc::asiodns::DNSLookup* dns_lookup_; + isc::asiodns::DNSAnswer* dns_answer_; + isc::asiodns::DNSService* dnss_; }; #endif // __AUTH_SRV_H diff --git a/src/bin/auth/benchmarks/Makefile.am b/src/bin/auth/benchmarks/Makefile.am index c7de8d42d03591cd72a6396a37ef67c8f04dd2a3..a569147c2ca7f8ed073500b921479058e41b163b 100644 --- a/src/bin/auth/benchmarks/Makefile.am +++ b/src/bin/auth/benchmarks/Makefile.am @@ -22,6 +22,7 @@ query_bench_LDADD += $(top_builddir)/src/lib/cc/libcc.la query_bench_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la query_bench_LDADD += $(top_builddir)/src/lib/log/liblog.la query_bench_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la +query_bench_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la query_bench_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la query_bench_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la query_bench_LDADD += $(SQLITE_LIBS) diff --git a/src/bin/auth/benchmarks/query_bench.cc b/src/bin/auth/benchmarks/query_bench.cc index 86d98135af5126cd5383de7aa9c4c8a71324c638..ba2e7b274a9264557ae2660220c0f7d3323fe1a4 100644 --- a/src/bin/auth/benchmarks/query_bench.cc +++ b/src/bin/auth/benchmarks/query_bench.cc @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include @@ -36,6 +36,7 @@ #include #include +#include #include using namespace std; @@ -43,9 +44,11 @@ using namespace isc; using namespace isc::data; using namespace isc::auth; using namespace isc::dns; +using namespace isc::util; using namespace isc::xfr; using namespace isc::bench; -using namespace asiolink; +using namespace isc::asiodns; +using namespace isc::asiolink; namespace { // Commonly used constant: diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc index 77e7df44c33d967b5523e3eb7c777546f1f444ff..480c2f7f1fcaa25761e6fdaae8c7522da8ac1db8 100644 --- a/src/bin/auth/main.cc +++ b/src/bin/auth/main.cc @@ -27,7 +27,8 @@ #include -#include +#include + #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #include #include @@ -51,8 +53,10 @@ using namespace isc::data; using namespace isc::cc; using namespace isc::config; using namespace isc::dns; +using namespace isc::util; using namespace isc::xfr; -using namespace asiolink; +using namespace isc::asiolink; +using namespace isc::asiodns; namespace { diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am index 882f7fdf3b9b520283da05200c5e5dac6a0be762..026dde3c5c43bf20c7ddedc7c8afcfa8c3aaff8f 100644 --- a/src/bin/auth/tests/Makefile.am +++ b/src/bin/auth/tests/Makefile.am @@ -45,6 +45,7 @@ run_unittests_LDADD += $(SQLITE_LIBS) run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la +run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc index 379342e0466c6715e2b63092bce0f31e26603263..a77f7e63ad9208c713d14e48cf70bbff5e699d71 100644 --- a/src/bin/auth/tests/auth_srv_unittest.cc +++ b/src/bin/auth/tests/auth_srv_unittest.cc @@ -41,10 +41,12 @@ using namespace std; using namespace isc::cc; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; using namespace isc::data; using namespace isc::xfr; -using namespace asiolink; +using namespace isc::asiodns; +using namespace isc::asiolink; using namespace isc::testutils; using namespace isc::server_common::portconfig; using isc::UnitTestUtil; diff --git a/src/bin/auth/tests/command_unittest.cc b/src/bin/auth/tests/command_unittest.cc index dd1f6ebcc6a0aaa518d3082168dcf88b8a3f4baa..3fdd08601ef4699e192d5575adcaec98e984436a 100644 --- a/src/bin/auth/tests/command_unittest.cc +++ b/src/bin/auth/tests/command_unittest.cc @@ -99,7 +99,7 @@ AuthConmmandTest::stopServer() { } TEST_F(AuthConmmandTest, shutdown) { - asiolink::IntervalTimer itimer(server.getIOService()); + isc::asiolink::IntervalTimer itimer(server.getIOService()); itimer.setup(boost::bind(&AuthConmmandTest::stopServer, this), 1); server.getIOService().run(); EXPECT_EQ(0, rcode); diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc index 9c94e25f650593d22b0512212d95a692bfc607a1..7658b84ee77fb8f4df59fb1fe2ff8c1b2b0c6d7b 100644 --- a/src/bin/auth/tests/config_unittest.cc +++ b/src/bin/auth/tests/config_unittest.cc @@ -35,7 +35,8 @@ using namespace isc::dns; using namespace isc::data; using namespace isc::datasrc; -using namespace asiolink; +using namespace isc::asiodns; +using namespace isc::asiolink; namespace { class AuthConfigTest : public ::testing::Test { diff --git a/src/bin/bind10/bind10.8 b/src/bin/bind10/bind10.8 index b275f2dcedb415c998f6d944c12c949f9a4d66fd..d5ab9053b3b64933515ec703abeeafa82b113444 100644 --- a/src/bin/bind10/bind10.8 +++ b/src/bin/bind10/bind10.8 @@ -2,12 +2,12 @@ .\" Title: bind10 .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: February 22, 2011 +.\" Date: March 31, 2011 .\" Manual: BIND10 .\" Source: BIND10 .\" Language: English .\" -.TH "BIND10" "8" "February 22, 2011" "BIND10" "BIND10" +.TH "BIND10" "8" "March 31, 2011" "BIND10" "BIND10" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- @@ -22,7 +22,7 @@ bind10 \- BIND 10 boss process .SH "SYNOPSIS" .HP \w'\fBbind10\fR\ 'u -\fBbind10\fR [\fB\-m\ \fR\fB\fIfile\fR\fR] [\fB\-n\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-\-msgq\-socket\-file\ \fR\fB\fIfile\fR\fR] [\fB\-\-no\-cache\fR] [\fB\-\-user\ \fR\fB\fIuser\fR\fR] [\fB\-\-pretty\-name\ \fR\fB\fIname\fR\fR] [\fB\-\-brittle\fR] [\fB\-\-verbose\fR] +\fBbind10\fR [\fB\-c\ \fR\fB\fIconfig\-filename\fR\fR] [\fB\-m\ \fR\fB\fIfile\fR\fR] [\fB\-n\fR] [\fB\-p\ \fR\fB\fIdata_path\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-\-brittle\fR] [\fB\-\-cmdctl\-port\fR\ \fIport\fR] [\fB\-\-config\-file\fR\ \fIconfig\-filename\fR] [\fB\-\-data\-path\fR\ \fIdirectory\fR] [\fB\-\-msgq\-socket\-file\ \fR\fB\fIfile\fR\fR] [\fB\-\-no\-cache\fR] [\fB\-\-pid\-file\fR\ \fIfilename\fR] [\fB\-\-pretty\-name\ \fR\fB\fIname\fR\fR] [\fB\-\-user\ \fR\fB\fIuser\fR\fR] [\fB\-\-verbose\fR] .SH "DESCRIPTION" .PP The @@ -32,6 +32,34 @@ daemon starts up other BIND 10 required daemons\&. It handles restarting of exit .PP The arguments are as follows: .PP +\fB\-\-brittle\fR +.RS 4 +Shutdown if any of the child processes of +\fBbind10\fR +exit\&. This is intended to help developers debug the server, and should not be used in production\&. +.RE +.PP +\fB\-c\fR \fIconfig\-filename\fR, \fB\-\-config\-file\fR \fIconfig\-filename\fR +.RS 4 +The configuration filename to use\&. Can be either absolute or relative to data path\&. In case it is absolute, value of data path is not considered\&. +.sp +Defaults to b10\-config\&.db\&. +.RE +.PP +\fB\-\-cmdctl\-port\fR \fIport\fR +.RS 4 +The +\fBb10\-cmdctl\fR +daemon will listen on this port\&. (See +b10\-cmdctl(8) +for the default\&.) +.RE +.PP +\fB\-p\fR \fIdirectory\fR, \fB\-\-data\-path\fR \fIdirectory\fR +.RS 4 +The path where BIND 10 programs look for various data files\&. Currently only b10\-cfgmgr uses it to locate the configuration file, but the usage might be extended for other programs and other types of files\&. +.RE +.PP \fB\-m\fR \fIfile\fR, \fB\-\-msgq\-socket\-file\fR \fIfile\fR .RS 4 The UNIX domain socket file for the @@ -57,6 +85,13 @@ to run as\&. must be initially ran as the root user to use this option\&. The default is to run as the current user\&. .RE .PP +\fB\-\-pid\-file\fR \fIfilename\fR +.RS 4 +If defined, the PID of the +\fBbind10\fR +is stored in this file\&. This is used for testing purposes\&. +.RE +.PP \fB\-\-pretty\-name \fR\fB\fIname\fR\fR .RS 4 The name this process should have in tools like @@ -66,14 +101,6 @@ or \fBbind10\fR\&. .RE .PP -\fB\-\-brittle\fR -.RS 4 -Shutdown if any of the child processes of -\fBbind10\fR -exit\&. This is intended to help developers debug the server, and should -not be used in production. -.RE -.PP \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Display more about what is going on for diff --git a/src/bin/bind10/bind10.xml b/src/bin/bind10/bind10.xml index 6331503a7a72e68eeca5624f2cfd88ba2a52430b..1128264ece257cb5d2d5e42d9e7c5d33c3a371d7 100644 --- a/src/bin/bind10/bind10.xml +++ b/src/bin/bind10/bind10.xml @@ -20,7 +20,7 @@ - February 22, 2011 + March 31, 2011 @@ -44,16 +44,21 @@ bind10 + + - - + + port + config-filename + directory - + filename + @@ -82,9 +87,24 @@ The arguments are as follows: + + + + + + + + Shutdown if any of the child processes of + bind10 exit. This is intended to + help developers debug the server, and should not be + used in production. + + + + - config-filename, + config-filename, config-filename @@ -97,8 +117,22 @@ - data-path, - data-path + port + + + The b10-cmdctl daemon will listen + on this port. + (See + b10-cmdctl8 + for the default.) + + + + + + + directory, + directory The path where BIND 10 programs look for various data files. @@ -134,7 +168,6 @@ user, name - The username for bind10 to run as. @@ -144,6 +177,16 @@ + + filename + + If defined, the PID of the bind10 is stored + in this file. + This is used for testing purposes. + + + + diff --git a/src/bin/cfgmgr/Makefile.am b/src/bin/cfgmgr/Makefile.am index a41448b4032715e030e1e2d7b57f859bccc884a4..fc0ed4a0c5f164e9364173e92367c1311556e37c 100644 --- a/src/bin/cfgmgr/Makefile.am +++ b/src/bin/cfgmgr/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . tests +SUBDIRS = . plugins tests pkglibexecdir = $(libexecdir)/@PACKAGE@ diff --git a/src/bin/cfgmgr/b10-cfgmgr.py.in b/src/bin/cfgmgr/b10-cfgmgr.py.in index 535558234480008e8186142dc4b73f576b3cbc1a..607a6dcd2945f0208d2ae4a8c49878034537333a 100755 --- a/src/bin/cfgmgr/b10-cfgmgr.py.in +++ b/src/bin/cfgmgr/b10-cfgmgr.py.in @@ -23,6 +23,8 @@ import isc.util.process import signal import os from optparse import OptionParser +import glob +import os.path isc.util.process.rename() @@ -39,9 +41,11 @@ if "B10_FROM_SOURCE" in os.environ: DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"] else: DATA_PATH = os.environ["B10_FROM_SOURCE"] + PLUGIN_PATH = [DATA_PATH + '/src/bin/cfgmgr/plugins'] else: PREFIX = "@prefix@" DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX) + PLUGIN_PATHS = ["@prefix@/share/@PACKAGE@/config_plugins"] DEFAULT_CONFIG_FILE = "b10-config.db" cm = None @@ -65,6 +69,28 @@ def signal_handler(signal, frame): if cm: cm.running = False +def load_plugins(path, cm): + """Load all python files in the given path and treat them as plugins.""" + # Find the python files + plugins = glob.glob(path + os.sep + '*.py') + # Search this directory first, but leave the others there for the imports + # of the modules + sys.path.insert(0, path) + try: + for plugin in plugins: + # Generate the name of the plugin + filename = os.path.basename(plugin) + name = filename[:-3] + # Load it + module = __import__(name) + # Ask it to provide the spec and checking function + (spec, check_func) = module.load() + # And insert it into the manager + cm.set_virtual_module(spec, check_func) + finally: + # Restore the search path + sys.path = sys.path[1:] + def main(): options = parse_options() global cm @@ -73,6 +99,8 @@ def main(): signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) cm.read_config() + for ppath in PLUGIN_PATHS: + load_plugins(ppath, cm) cm.notify_boss() cm.run() except SessionError as se: diff --git a/src/bin/cfgmgr/plugins/Makefile.am b/src/bin/cfgmgr/plugins/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..952fde6edc296ea6c3e76475c22b77a668db6047 --- /dev/null +++ b/src/bin/cfgmgr/plugins/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = README diff --git a/src/bin/cfgmgr/plugins/README b/src/bin/cfgmgr/plugins/README new file mode 100644 index 0000000000000000000000000000000000000000..27fb0c00257563b433f9469500b23ef5ee07661e --- /dev/null +++ b/src/bin/cfgmgr/plugins/README @@ -0,0 +1,34 @@ +How to write a configuration plugin +=================================== + +The plugins are used to describe configuration modules that have no hosting +process. Therefore there's no process to provide their specification and to +check them for correctness. So the plugin takes this responsibility. + +Each plugin is a python file installed into the +`@prefix@/share/@PACKAGE@/config_plugins` directory (usually +`/usr/share/bind10/config_plugins`). It is loaded automatically at startup. + +The entrypoint of a plugin is function called `load()`. It should return a +tuple, first value should be the module specification (usually instance of +`isc.config.module_spec.ModuleSpec`, loaded by `module_spec_from_file()`). + +The second value is a callable object. It will be called whenever the +configuration of module needs to be checked. The only parameter will be the new +config (as python dictionary). To accept the new configuration, return None. If +you return a string, it is taken as an error message. If you raise an +exception, the config is rejected as well, however it is not considered a +graceful rejection, but a failure of the module. + +So, this is how a plugin could look like: + + from isc.config.module_spec import module_spec_from_file + + def check(config): + if config['bogosity'] > 1: + return "Too bogus to live with" + else: + return None + + def load(): + return (module_spec_from_file('module_spec.spec'), check) diff --git a/src/bin/cfgmgr/tests/Makefile.am b/src/bin/cfgmgr/tests/Makefile.am index 16e6223e2c0f18ed1c9cdb14dce683a3f7500bba..68666e6a3b120b8b9a5963da4fad1de3e79cb3aa 100644 --- a/src/bin/cfgmgr/tests/Makefile.am +++ b/src/bin/cfgmgr/tests/Makefile.am @@ -1,7 +1,7 @@ PYCOVERAGE_RUN = @PYCOVERAGE_RUN@ PYTESTS = b10-cfgmgr_test.py -EXTRA_DIST = $(PYTESTS) +EXTRA_DIST = $(PYTESTS) testdata/plugins/testplugin.py # test using command-line arguments, so use check-local target instead of TESTS check-local: @@ -12,6 +12,7 @@ if ENABLE_PYTHON_COVERAGE endif for pytest in $(PYTESTS) ; do \ echo Running test: $$pytest ; \ + env TESTDATA_PATH=$(abs_srcdir)/testdata \ env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr \ $(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \ done diff --git a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in index 037a106c9ef569d155f499478df85d574fb9f347..37cd0f50c19cb6169217f240e27e0292bc85b8b6 100644 --- a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in +++ b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in @@ -30,6 +30,7 @@ class MyConfigManager: self.run_called = False self.write_config_called = False self.running = True + self.virtual_modules = [] def read_config(self): self.read_config_called = True @@ -43,6 +44,24 @@ class MyConfigManager: def write_config(self): self.write_config_called = True + def set_virtual_module(self, spec, function): + self.virtual_modules.append((spec, function)) + +class TestPlugins(unittest.TestCase): + def test_load_plugins(self): + """Test we can successfully find and load the mock plugin.""" + # Let it load the plugin + b = __import__("b10-cfgmgr") + # The parameters aren't important for this test + cm = MyConfigManager(None, None) + b.load_plugins(os.environ['TESTDATA_PATH'] + os.sep + 'plugins', cm) + # Check exactly one plugin was loaded and the right data were fed into + # the cm + self.assertEqual(len(cm.virtual_modules), 1) + (spec, check) = cm.virtual_modules[0] + self.assertEqual(spec.get_module_name(), "mock_config_plugin") + self.assertEqual(check(None), "Mock config plugin") + class TestConfigManagerStartup(unittest.TestCase): def test_cfgmgr(self): # some creative module use; @@ -50,13 +69,24 @@ class TestConfigManagerStartup(unittest.TestCase): # this also gives us the chance to override the imported # module ConfigManager in it. b = __import__("b10-cfgmgr") + orig_load = b.load_plugins + b.PLUGIN_PATHS = ["/plugin/path"] + self.loaded_plugins = False + def load_plugins(path, cm): + # Check it's called with proper arguments + self.assertEqual(path, "/plugin/path") + self.assertTrue(isinstance(cm, MyConfigManager)) + self.loaded_plugins = True + b.load_plugins = load_plugins b.ConfigManager = MyConfigManager b.main() + b.load_plugins = orig_load self.assertTrue(b.cm.read_config_called) self.assertTrue(b.cm.notify_boss_called) self.assertTrue(b.cm.run_called) + self.assertTrue(self.loaded_plugins) # if there are no changes, config is not written self.assertFalse(b.cm.write_config_called) @@ -81,6 +111,7 @@ class TestConfigManagerStartup(unittest.TestCase): os.environ["B10_FROM_SOURCE"] = tmp_env_var b = __import__("b10-cfgmgr", globals(), locals()) + b.PLUGIN_PATH = [] # It's enough to test plugins in one test b.ConfigManager = MyConfigManager self.assertEqual(tmp_env_var, b.DATA_PATH) diff --git a/src/bin/cfgmgr/tests/testdata/plugins/testplugin.py b/src/bin/cfgmgr/tests/testdata/plugins/testplugin.py new file mode 100644 index 0000000000000000000000000000000000000000..a50eefe164e35ba07f3cff2602739d748bc3d112 --- /dev/null +++ b/src/bin/cfgmgr/tests/testdata/plugins/testplugin.py @@ -0,0 +1,34 @@ +# Copyright (C) 2011 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. + +# A test plugin. It does mostly nothing, just provides a function we can +# recognize from the test. However, it looks like a real plugin, with the +# (almost) correct interface, even when it's not used. + +class MockSpec: + """Mock spec, contains no data, it can only provide it's name. + It'll not really be used for anything.""" + def get_module_name(self): + return "mock_config_plugin" + +def mock_check_config(config): + """Mock function to check config. Does nothing, only returns + an "error" string to indicate it's this one.""" + return "Mock config plugin" + +def load(): + """When a plugin is loaded, this is called to provide the spec and + checking function.""" + return (MockSpec(), mock_check_config) diff --git a/src/bin/host/host.cc b/src/bin/host/host.cc index c513b5af1b0d713bb272ba02fdb77e424897ce8e..973509e956b83583e81771e6b6e32384a4b9e01a 100644 --- a/src/bin/host/host.cc +++ b/src/bin/host/host.cc @@ -24,7 +24,8 @@ #include #include -#include +#include + #include #include #include @@ -37,6 +38,7 @@ using namespace std; using namespace isc::dns; +using namespace isc::util; namespace { char* dns_type = NULL; // not set, so A, AAAA, MX diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am index 54e15bd8dc66d8c1185974b09d723e661a6def60..094e3ad6c7cd4bedce820a95e6223c2175cf5825 100644 --- a/src/bin/resolver/Makefile.am +++ b/src/bin/resolver/Makefile.am @@ -4,6 +4,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cc -I$(top_builddir)/src/lib/cc +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiodns +AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiodns AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiolink AM_CPPFLAGS += $(BOOST_INCLUDES) @@ -45,6 +47,7 @@ b10_resolver_LDADD = $(top_builddir)/src/lib/dns/libdns++.la b10_resolver_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la b10_resolver_LDADD += $(top_builddir)/src/lib/cc/libcc.la b10_resolver_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la +b10_resolver_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la b10_resolver_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la b10_resolver_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la b10_resolver_LDADD += $(top_builddir)/src/lib/log/liblog.la diff --git a/src/bin/resolver/main.cc b/src/bin/resolver/main.cc index 092ec541240a8ba11971ce469d6fe40a83130ac3..5103bf998419017aa7cd09246ad313fe5c4c07af 100644 --- a/src/bin/resolver/main.cc +++ b/src/bin/resolver/main.cc @@ -27,11 +27,12 @@ #include +#include #include #include -#include +#include #include #include #include @@ -58,7 +59,8 @@ using namespace isc::cc; using namespace isc::config; using namespace isc::data; using isc::log::dlog; -using namespace asiolink; +using namespace isc::asiodns; +using namespace isc::asiolink; namespace { diff --git a/src/bin/resolver/resolver.cc b/src/bin/resolver/resolver.cc index 232207693a94def3d04ca89d32c935d6de4b33ff..591e214ace5c9aad8cc3a0110e0071aa7cfe770d 100644 --- a/src/bin/resolver/resolver.cc +++ b/src/bin/resolver/resolver.cc @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -29,9 +30,10 @@ #include +#include + #include #include -#include #include #include #include @@ -50,11 +52,13 @@ using namespace std; using namespace isc; +using namespace isc::util; using namespace isc::dns; using namespace isc::data; using namespace isc::config; using isc::log::dlog; -using namespace asiolink; +using namespace isc::asiodns; +using namespace isc::asiolink; using namespace isc::server_common::portconfig; class ResolverImpl { @@ -295,7 +299,7 @@ public: edns_response->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE); answer_message->setEDNS(edns_response); } - + if (io_message.getSocket().getProtocol() == IPPROTO_UDP) { if (edns) { renderer.setLengthLimit(edns->getUDPSize()); @@ -345,7 +349,7 @@ Resolver::~Resolver() { } void -Resolver::setDNSService(asiolink::DNSService& dnss) { +Resolver::setDNSService(isc::asiodns::DNSService& dnss) { dnss_ = &dnss; } diff --git a/src/bin/resolver/resolver.h b/src/bin/resolver/resolver.h index 8f07ff708763c54eb70c013afffef00016c1029a..2890dd3f9a27cc8e9ffa02052a6a49f1bafef08e 100644 --- a/src/bin/resolver/resolver.h +++ b/src/bin/resolver/resolver.h @@ -22,14 +22,14 @@ #include #include #include -#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include #include #include @@ -82,11 +82,11 @@ public: /// shall return to the client /// \param buffer Pointer to an \c OutputBuffer for the resposne /// \param server Pointer to the \c DNSServer - void processMessage(const asiolink::IOMessage& io_message, + void processMessage(const isc::asiolink::IOMessage& io_message, isc::dns::MessagePtr query_message, isc::dns::MessagePtr answer_message, - isc::dns::OutputBufferPtr buffer, - asiolink::DNSServer* server); + isc::util::OutputBufferPtr buffer, + isc::asiodns::DNSServer* server); /// \brief Set and get the config session isc::config::ModuleCCSession* getConfigSession() const; @@ -96,16 +96,16 @@ public: isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config); /// \brief Assign an ASIO IO Service queue to this Resolver object - void setDNSService(asiolink::DNSService& dnss); - + void setDNSService(isc::asiodns::DNSService& dnss); + /// \brief Assign a NameserverAddressStore to this Resolver object void setNameserverAddressStore(isc::nsas::NameserverAddressStore &nsas); - + /// \brief Assign a cache to this Resolver object void setCache(isc::cache::ResolverCache& cache); /// \brief Return this object's ASIO IO Service queue - asiolink::DNSService& getDNSService() const { return (*dnss_); } + isc::asiodns::DNSService& getDNSService() const { return (*dnss_); } /// \brief Returns this object's NSAS isc::nsas::NameserverAddressStore& getNameserverAddressStore() const { @@ -116,15 +116,15 @@ public: isc::cache::ResolverCache& getResolverCache() const { return *cache_; }; - + /// \brief Return pointer to the DNS Lookup callback function - asiolink::DNSLookup* getDNSLookupProvider() { return (dns_lookup_); } + isc::asiodns::DNSLookup* getDNSLookupProvider() { return (dns_lookup_); } /// \brief Return pointer to the DNS Answer callback function - asiolink::DNSAnswer* getDNSAnswerProvider() { return (dns_answer_); } + isc::asiodns::DNSAnswer* getDNSAnswerProvider() { return (dns_answer_); } /// \brief Return pointer to the Checkin callback function - asiolink::SimpleCallback* getCheckinProvider() { return (checkin_); } + isc::asiolink::SimpleCallback* getCheckinProvider() { return (checkin_); } /** * \brief Tell the Resolver that is has already been configured @@ -238,10 +238,10 @@ public: private: ResolverImpl* impl_; - asiolink::DNSService* dnss_; - asiolink::SimpleCallback* checkin_; - asiolink::DNSLookup* dns_lookup_; - asiolink::DNSAnswer* dns_answer_; + isc::asiodns::DNSService* dnss_; + isc::asiolink::SimpleCallback* checkin_; + isc::asiodns::DNSLookup* dns_lookup_; + isc::asiodns::DNSAnswer* dns_answer_; isc::nsas::NameserverAddressStore* nsas_; isc::cache::ResolverCache* cache_; // This value is initally false, and will be set to true @@ -252,6 +252,6 @@ private: #endif // __RESOLVER_H -// Local Variables: +// Local Variables: // mode: c++ -// End: +// End: diff --git a/src/bin/resolver/response_scrubber.cc b/src/bin/resolver/response_scrubber.cc index 060a8b1a92b4ea397eb95b228327ea7f72244bb9..93bd8084a3e58769f05d78423f77160b17a02d00 100644 --- a/src/bin/resolver/response_scrubber.cc +++ b/src/bin/resolver/response_scrubber.cc @@ -26,7 +26,7 @@ using namespace std; // Compare addresses etc. ResponseScrubber::Category ResponseScrubber::addressCheck( - const asiolink::IOEndpoint& to, const asiolink::IOEndpoint& from) + const isc::asiolink::IOEndpoint& to, const isc::asiolink::IOEndpoint& from) { if (from.getProtocol() == to.getProtocol()) { if (from.getAddress() == to.getAddress()) { diff --git a/src/bin/resolver/response_scrubber.h b/src/bin/resolver/response_scrubber.h index 680aa5ab41c03ea986c7792de4176ee66eda5021..c59ac15f309e2987161d7215d467a920a6f58c5c 100644 --- a/src/bin/resolver/response_scrubber.h +++ b/src/bin/resolver/response_scrubber.h @@ -282,8 +282,8 @@ public: /// /// \return SUCCESS if the two endpoints match, otherwise an error status /// indicating what was incorrect. - static Category addressCheck(const asiolink::IOEndpoint& to, - const asiolink::IOEndpoint& from); + static Category addressCheck(const isc::asiolink::IOEndpoint& to, + const isc::asiolink::IOEndpoint& from); /// \brief Check QID /// diff --git a/src/bin/resolver/tests/Makefile.am b/src/bin/resolver/tests/Makefile.am index b85c22384c02b00cba89c4db90f4da5c7ed89281..444358b44d415eca8131305889836a288e06f36d 100644 --- a/src/bin/resolver/tests/Makefile.am +++ b/src/bin/resolver/tests/Makefile.am @@ -31,6 +31,7 @@ run_unittests_LDADD += $(SQLITE_LIBS) run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la +run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la diff --git a/src/bin/resolver/tests/resolver_config_unittest.cc b/src/bin/resolver/tests/resolver_config_unittest.cc index c1ff8535050411e8220dfd7c8ff4248783c9eac1..70e856d1e14b9cbbe462bffcebee3ef500ce0f67 100644 --- a/src/bin/resolver/tests/resolver_config_unittest.cc +++ b/src/bin/resolver/tests/resolver_config_unittest.cc @@ -20,6 +20,7 @@ #include +#include #include #include @@ -31,7 +32,8 @@ using namespace std; using namespace isc::data; using namespace isc::testutils; -using namespace asiolink; +using namespace isc::asiodns; +using namespace isc::asiolink; using isc::UnitTestUtil; namespace { diff --git a/src/bin/resolver/tests/response_scrubber_unittest.cc b/src/bin/resolver/tests/response_scrubber_unittest.cc index 1dc66395eff1eba05a5f8cba575cd94fd0e7a8ab..eff559883746ae825902957c8de801b54b2f70b9 100644 --- a/src/bin/resolver/tests/response_scrubber_unittest.cc +++ b/src/bin/resolver/tests/response_scrubber_unittest.cc @@ -41,6 +41,7 @@ // Class for endpoint checks. The family of the endpoint is set in the // constructor; the address family by the string provided for the address. +namespace isc { namespace asiolink { class GenericEndpoint : public IOEndpoint { @@ -73,13 +74,14 @@ private: short protocol_; // Protocol of the endpoint }; } +} using namespace asio::ip; using namespace isc::dns; using namespace rdata; using namespace isc::dns::rdata::generic; using namespace isc::dns::rdata::in; -using namespace asiolink; +using namespace isc::asiolink; // Test class diff --git a/src/bin/xfrin/tests/Makefile.am b/src/bin/xfrin/tests/Makefile.am index 755d76e1957a5785d44401bff7a8229819a372f9..dfa771474ff13443cd8a9d43ee57c157f294f46d 100644 --- a/src/bin/xfrin/tests/Makefile.am +++ b/src/bin/xfrin/tests/Makefile.am @@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS) # required by loadable python modules. LIBRARY_PATH_PLACEHOLDER = if SET_ENV_LIBRARY_PATH -LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH) +LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH) endif # test using command-line arguments, so use check-local target instead of TESTS diff --git a/src/bin/xfrout/tests/Makefile.am b/src/bin/xfrout/tests/Makefile.am index 76c59778d7a9a2af95e2367509fe00e733176fbf..1ec3c064d953d1b6be524f501f57cceaad0b62ba 100644 --- a/src/bin/xfrout/tests/Makefile.am +++ b/src/bin/xfrout/tests/Makefile.am @@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS) # required by loadable python modules. LIBRARY_PATH_PLACEHOLDER = if SET_ENV_LIBRARY_PATH -LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$$$(ENV_LIBRARY_PATH) +LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$$$(ENV_LIBRARY_PATH) endif # test using command-line arguments, so use check-local target instead of TESTS diff --git a/src/bin/zonemgr/tests/zonemgr_test.py b/src/bin/zonemgr/tests/zonemgr_test.py index 2e9f685726034888d566a2b73cc3eff22851b798..c6d151db17eb15a9fd6e62a36523131acef3ab7d 100644 --- a/src/bin/zonemgr/tests/zonemgr_test.py +++ b/src/bin/zonemgr/tests/zonemgr_test.py @@ -29,8 +29,9 @@ ZONE_NAME_CLASS2_IN = ("tw.cn.", "IN") MAX_TRANSFER_TIMEOUT = 14400 LOWERBOUND_REFRESH = 10 -LOWERBOUND_RETRY = 5 -JITTER_SCOPE = 0.10 +LOWERBOUND_RETRY = 5 +REFRESH_JITTER = 0.10 +RELOAD_JITTER = 0.75 class ZonemgrTestException(Exception): pass @@ -60,8 +61,10 @@ class FakeConfig: return LOWERBOUND_RETRY elif name == 'max_transfer_timeout': return MAX_TRANSFER_TIMEOUT - elif name == 'jitter_scope': - return JITTER_SCOPE + elif name == 'refresh_jitter': + return REFRESH_JITTER + elif name == 'reload_jitter': + return RELOAD_JITTER elif name == 'secondary_zones': return self.zone_list else: @@ -71,6 +74,10 @@ class MyZonemgrRefresh(ZonemgrRefresh): def __init__(self): self._master_socket, self._slave_socket = socket.socketpair() self._zonemgr_refresh_info = {} + self._lowerbound_refresh = 10 + self._lowerbound_retry = 5 + self._reload_jitter = 0.75 + self._refresh_jitter = 0.25 def get_zone_soa(zone_name, db_file): if zone_name == 'sd.cn.': @@ -86,18 +93,18 @@ class MyZonemgrRefresh(ZonemgrRefresh): ZonemgrRefresh.__init__(self, MySession(), "initdb.file", self._slave_socket, FakeConfig()) current_time = time.time() - self._zonemgr_refresh_info = { + self._zonemgr_refresh_info = { ('sd.cn.', 'IN'): { 'last_refresh_time': current_time, - 'next_refresh_time': current_time + 6500, - 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', + 'next_refresh_time': current_time + 6500, + 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 'zone_state': 0}, ('tw.cn.', 'CH'): { - 'last_refresh_time': current_time, - 'next_refresh_time': current_time + 6900, - 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600', + 'last_refresh_time': current_time, + 'next_refresh_time': current_time + 6900, + 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600', 'zone_state': 0} - } + } class TestZonemgrRefresh(unittest.TestCase): def setUp(self): @@ -109,10 +116,10 @@ class TestZonemgrRefresh(unittest.TestCase): max = 100025.120 jitter = 0 self.assertEqual(max, self.zone_refresh._random_jitter(max, jitter)) - jitter = max / 4 + jitter = 0.3 * max for i in range (0, 150): - self.assertTrue((3 * max / 4) <= self.zone_refresh._random_jitter(max, jitter)) - self.assertTrue(self.zone_refresh._random_jitter(max, jitter) <= max) + self.assertTrue((max - jitter) <= self.zone_refresh._random_jitter(max, jitter)) + self.assertTrue(self.zone_refresh._random_jitter(max, jitter) <= max) i += 1; def test_get_current_time(self): @@ -133,7 +140,7 @@ class TestZonemgrRefresh(unittest.TestCase): self.zone_refresh._set_zone_refresh_timer(ZONE_NAME_CLASS1_IN) zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"] time2 = time.time() - self.assertTrue((time1 + 7200 * 3 / 4) <= zone_timeout) + self.assertTrue((time1 + 7200 * (1 - self.zone_refresh._refresh_jitter)) <= zone_timeout) self.assertTrue(zone_timeout <= time2 + 7200) def test_set_zone_retry_timer(self): @@ -141,7 +148,7 @@ class TestZonemgrRefresh(unittest.TestCase): self.zone_refresh._set_zone_retry_timer(ZONE_NAME_CLASS1_IN) zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"] time2 = time.time() - self.assertTrue((time1 + 3600 * 3 / 4) <= zone_timeout) + self.assertTrue((time1 + 3600 * (1 - self.zone_refresh._refresh_jitter)) <= zone_timeout) self.assertTrue(zone_timeout <= time2 + 3600) def test_zone_not_exist(self): @@ -172,19 +179,19 @@ class TestZonemgrRefresh(unittest.TestCase): self.assertTrue(self.zone_refresh._zone_is_expired(ZONE_NAME_CLASS1_IN)) def test_get_zone_soa_rdata(self): - soa_rdata1 = 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600' - soa_rdata2 = 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600' + soa_rdata1 = 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600' + soa_rdata2 = 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600' self.assertEqual(soa_rdata1, self.zone_refresh._get_zone_soa_rdata(ZONE_NAME_CLASS1_IN)) self.assertRaises(KeyError, self.zone_refresh._get_zone_soa_rdata, ZONE_NAME_CLASS1_CH) self.assertEqual(soa_rdata2, self.zone_refresh._get_zone_soa_rdata(ZONE_NAME_CLASS2_CH)) self.assertRaises(KeyError, self.zone_refresh._get_zone_soa_rdata, ZONE_NAME_CLASS2_IN) - + def test_zonemgr_reload_zone(self): soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600' # We need to restore this not to harm other tests old_get_zone_soa = sqlite3_ds.get_zone_soa def get_zone_soa(zone_name, db_file): - return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, + return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600') sqlite3_ds.get_zone_soa = get_zone_soa @@ -234,7 +241,7 @@ class TestZonemgrRefresh(unittest.TestCase): current_time = time.time() self.zone_refresh._set_zone_refresh_timeout(ZONE_NAME_CLASS1_IN, current_time) refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"] - self.assertEqual(current_time, refresh_time) + self.assertEqual(current_time, refresh_time) def test_get_zone_next_refresh_time(self): current_time = time.time() @@ -256,14 +263,14 @@ class TestZonemgrRefresh(unittest.TestCase): current_time = time.time() self.zone_refresh._set_zone_last_refresh_time(ZONE_NAME_CLASS1_IN, current_time) last_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] - self.assertEqual(current_time, last_refresh_time) + self.assertEqual(current_time, last_refresh_time) def test_send_command(self): self.assertRaises(ZonemgrTestException, self.zone_refresh._send_command, "Unknown", "Notify", None) def test_zone_mgr_is_empty(self): self.assertFalse(self.zone_refresh._zone_mgr_is_empty()) - self.zone_refresh._zonemgr_refresh_info = {} + self.zone_refresh._zonemgr_refresh_info = {} self.assertTrue(self.zone_refresh._zone_mgr_is_empty()) def test_zonemgr_add_zone(self): @@ -271,9 +278,10 @@ class TestZonemgrRefresh(unittest.TestCase): # This needs to be restored. The following test actually failed if we left # this unclean old_get_zone_soa = sqlite3_ds.get_zone_soa + time1 = time.time() def get_zone_soa(zone_name, db_file): - return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, + return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600') sqlite3_ds.get_zone_soa = get_zone_soa @@ -282,10 +290,14 @@ class TestZonemgrRefresh(unittest.TestCase): self.zone_refresh.zonemgr_add_zone(ZONE_NAME_CLASS1_IN) self.assertEqual(1, len(self.zone_refresh._zonemgr_refresh_info)) zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"] - self.assertEqual(soa_rdata, zone_soa_rdata) + self.assertEqual(soa_rdata, zone_soa_rdata) self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]) self.assertTrue("last_refresh_time" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys()) self.assertTrue("next_refresh_time" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys()) + time2 = time.time() + zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"] + self.assertTrue((time1 + 900 * (1 - self.zone_refresh._reload_jitter)) <= zone_timeout) + self.assertTrue(zone_timeout <= time2 + 900) def get_zone_soa2(zone_name, db_file): return None @@ -297,7 +309,7 @@ class TestZonemgrRefresh(unittest.TestCase): def test_zone_handle_notify(self): self.zone_refresh.zone_handle_notify(ZONE_NAME_CLASS1_IN,"127.0.0.1") notify_master = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["notify_master"] - self.assertEqual("127.0.0.1", notify_master) + self.assertEqual("127.0.0.1", notify_master) zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"] current_time = time.time() self.assertTrue(zone_timeout <= current_time) @@ -309,7 +321,7 @@ class TestZonemgrRefresh(unittest.TestCase): def test_zone_refresh_success(self): soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600' def get_zone_soa(zone_name, db_file): - return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, + return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600') sqlite3_ds.get_zone_soa = get_zone_soa time1 = time.time() @@ -317,19 +329,19 @@ class TestZonemgrRefresh(unittest.TestCase): self.zone_refresh.zone_refresh_success(ZONE_NAME_CLASS1_IN) time2 = time.time() zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"] - self.assertEqual(soa_rdata, zone_soa_rdata) + self.assertEqual(soa_rdata, zone_soa_rdata) next_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"] - self.assertTrue((time1 + 3 * 1800 / 4) <= next_refresh_time) + self.assertTrue((time1 + 1800 * (1 - self.zone_refresh._refresh_jitter)) <= next_refresh_time) self.assertTrue(next_refresh_time <= time2 + 1800) self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]) last_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] self.assertTrue(time1 <= last_refresh_time) self.assertTrue(last_refresh_time <= time2) self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ("org.cn.", "CH")) - self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ZONE_NAME_CLASS3_IN) + self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ZONE_NAME_CLASS3_IN) def test_zone_refresh_fail(self): - soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600' + soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600' time1 = time.time() self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_REFRESHING self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN) @@ -337,36 +349,36 @@ class TestZonemgrRefresh(unittest.TestCase): zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"] self.assertEqual(soa_rdata, zone_soa_rdata) next_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"] - self.assertTrue((time1 + 3 * 3600 / 4) <= next_refresh_time) + self.assertTrue(((time1 + 3600 * (1 - self.zone_refresh._refresh_jitter))) <= next_refresh_time) self.assertTrue(next_refresh_time <= time2 + 3600) self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]) - self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] = time1 - 2419200 + self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] = time1 - 2419200 self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN) self.assertEqual(ZONE_EXPIRED, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]) self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ("org.cn.", "CH")) - self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_IN) + self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_IN) def test_find_need_do_refresh_zone(self): time1 = time.time() - self.zone_refresh._zonemgr_refresh_info = { + self.zone_refresh._zonemgr_refresh_info = { ("sd.cn.","IN"):{ 'last_refresh_time': time1, - 'next_refresh_time': time1 + 7200, - 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', + 'next_refresh_time': time1 + 7200, + 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 'zone_state': ZONE_OK}, ("tw.cn.","CH"):{ - 'last_refresh_time': time1 - 7200, - 'next_refresh_time': time1, - 'refresh_timeout': time1 + MAX_TRANSFER_TIMEOUT, - 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600', + 'last_refresh_time': time1 - 7200, + 'next_refresh_time': time1, + 'refresh_timeout': time1 + MAX_TRANSFER_TIMEOUT, + 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600', 'zone_state': ZONE_REFRESHING} } zone_need_refresh = self.zone_refresh._find_need_do_refresh_zone() self.assertEqual(ZONE_NAME_CLASS1_IN, zone_need_refresh) - self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_CH]["refresh_timeout"] = time1 + self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_CH]["refresh_timeout"] = time1 zone_need_refresh = self.zone_refresh._find_need_do_refresh_zone() self.assertEqual(ZONE_NAME_CLASS2_CH, zone_need_refresh) @@ -375,42 +387,42 @@ class TestZonemgrRefresh(unittest.TestCase): self.zone_refresh._zonemgr_refresh_info = { ("sd.cn.", "IN"):{ 'last_refresh_time': time1 - 7200, - 'next_refresh_time': time1 - 1, - 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', + 'next_refresh_time': time1 - 1, + 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 'zone_state': ZONE_OK} } self.zone_refresh._do_refresh(ZONE_NAME_CLASS1_IN) time2 = time.time() zone_state = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] self.assertEqual(ZONE_REFRESHING, zone_state) - refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"] + refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"] self.assertTrue(time1 + MAX_TRANSFER_TIMEOUT <= refresh_timeout) - self.assertTrue(time2 + MAX_TRANSFER_TIMEOUT >= refresh_timeout) + self.assertTrue(time2 + MAX_TRANSFER_TIMEOUT >= refresh_timeout) self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["notify_master"] = "127.0.0.1" self.zone_refresh._do_refresh(ZONE_NAME_CLASS1_IN) time2 = time.time() zone_state = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] - self.assertEqual(ZONE_REFRESHING, zone_state) - refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"] + self.assertEqual(ZONE_REFRESHING, zone_state) + refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"] self.assertTrue(time1 + MAX_TRANSFER_TIMEOUT <= refresh_timeout) self.assertTrue(time2 + MAX_TRANSFER_TIMEOUT >= refresh_timeout) self.assertFalse("notify_master" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys()) def test_run_timer(self): - """This case will run timer in daemon thread. - The zone's next_refresh_time is less than now, so zonemgr will do zone refresh - immediately. The zone's state will become "refreshing". + """This case will run timer in daemon thread. + The zone's next_refresh_time is less than now, so zonemgr will do zone refresh + immediately. The zone's state will become "refreshing". """ time1 = time.time() self.zone_refresh._zonemgr_refresh_info = { ("sd.cn.", "IN"):{ 'last_refresh_time': time1 - 7200, - 'next_refresh_time': time1 - 1, - 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', + 'next_refresh_time': time1 - 1, + 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 'zone_state': ZONE_OK} } - self.zone_refresh._check_sock = self.zone_refresh._master_socket + self.zone_refresh._check_sock = self.zone_refresh._master_socket listener = self.zone_refresh.run_timer(daemon=True) # Shut down the timer thread self.zone_refresh.shutdown() @@ -424,17 +436,19 @@ class TestZonemgrRefresh(unittest.TestCase): "lowerbound_refresh" : 60, "lowerbound_retry" : 30, "max_transfer_timeout" : 19800, - "jitter_scope" : 0.25, + "refresh_jitter" : 0.25, + "reload_jitter" : 0.75, "secondary_zones": [] } self.zone_refresh.update_config_data(config_data) self.assertEqual(60, self.zone_refresh._lowerbound_refresh) self.assertEqual(30, self.zone_refresh._lowerbound_retry) self.assertEqual(19800, self.zone_refresh._max_transfer_timeout) - self.assertEqual(0.25, self.zone_refresh._jitter_scope) + self.assertEqual(0.25, self.zone_refresh._refresh_jitter) + self.assertEqual(0.75, self.zone_refresh._reload_jitter) def test_shutdown(self): - self.zone_refresh._check_sock = self.zone_refresh._master_socket + self.zone_refresh._check_sock = self.zone_refresh._master_socket listener = self.zone_refresh.run_timer() self.assertTrue(listener.is_alive()) # Shut down the timer thread @@ -473,7 +487,7 @@ class TestZonemgrRefresh(unittest.TestCase): class MyCCSession(): def __init__(self): pass - + def get_remote_config_value(self, module_name, identifier): if module_name == "Auth" and identifier == "database_file": return "initdb.file", False @@ -493,7 +507,8 @@ class MyZonemgr(Zonemgr): "lowerbound_refresh" : 10, "lowerbound_retry" : 5, "max_transfer_timeout" : 14400, - "jitter_scope" : 0.1, + "refresh_jitter" : 0.1, + "reload_jitter" : 0.75, "secondary_zones": [] } @@ -510,7 +525,8 @@ class TestZonemgr(unittest.TestCase): "lowerbound_refresh" : 60, "lowerbound_retry" : 30, "max_transfer_timeout" : 14400, - "jitter_scope" : 0.1, + "refresh_jitter" : 0.1, + "reload_jitter" : 0.75, "secondary_zones": [] } self.assertEqual(self.zonemgr.config_handler(config_data1), @@ -520,9 +536,9 @@ class TestZonemgr(unittest.TestCase): self.zonemgr.config_handler(config_data2) self.assertEqual(config_data1, self.zonemgr._config_data) # jitter should not be bigger than half of the original value - config_data3 = {"jitter_scope" : 0.7} + config_data3 = {"refresh_jitter" : 0.7} self.zonemgr.config_handler(config_data3) - self.assertEqual(0.5, self.zonemgr._config_data.get("jitter_scope")) + self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter")) # The zone doesn't exist in database, it should be rejected self.zonemgr._zone_refresh = ZonemgrRefresh(None, "initdb.file", None, config_data1) @@ -531,7 +547,7 @@ class TestZonemgr(unittest.TestCase): self.assertNotEqual(self.zonemgr.config_handler(config_data1), {"result": [0]}) # As it is rejected, the old value should be kept - self.assertEqual(0.5, self.zonemgr._config_data.get("jitter_scope")) + self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter")) def test_get_db_file(self): self.assertEqual("initdb.file", self.zonemgr.get_db_file()) @@ -549,12 +565,12 @@ class TestZonemgr(unittest.TestCase): def test_config_data_check(self): # jitter should not be bigger than half of the original value - config_data2 = {"jitter_scope" : 0.2} - config_data3 = {"jitter_scope" : 0.6} + config_data2 = {"refresh_jitter" : 0.2} + config_data3 = {"refresh_jitter" : 0.6} self.zonemgr._config_data_check(config_data2) - self.assertEqual(0.2, config_data2.get("jitter_scope")) + self.assertEqual(0.2, config_data2.get("refresh_jitter")) self.zonemgr._config_data_check(config_data3) - self.assertEqual(0.5, config_data3.get("jitter_scope")) + self.assertEqual(0.5, config_data3.get("refresh_jitter")) def tearDown(self): pass diff --git a/src/bin/zonemgr/zonemgr.py.in b/src/bin/zonemgr/zonemgr.py.in index 129c673ffe33415669836320d5ce12d1fd04bd83..cc6d7b9ef4ad59872a0e4db80c1ebb5c2de89501 100755 --- a/src/bin/zonemgr/zonemgr.py.in +++ b/src/bin/zonemgr/zonemgr.py.in @@ -125,19 +125,19 @@ class ZonemgrRefresh: def _set_zone_refresh_timer(self, zone_name_class): """Set zone next refresh time after zone refresh success. - now + refresh - jitter <= next_refresh_time <= now + refresh + now + refresh - refresh_jitter <= next_refresh_time <= now + refresh """ zone_refresh_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[REFRESH_OFFSET]) zone_refresh_time = max(self._lowerbound_refresh, zone_refresh_time) - self._set_zone_timer(zone_name_class, zone_refresh_time, self._jitter_scope * zone_refresh_time) + self._set_zone_timer(zone_name_class, zone_refresh_time, self._refresh_jitter * zone_refresh_time) def _set_zone_retry_timer(self, zone_name_class): """Set zone next refresh time after zone refresh fail. - now + retry - jitter <= next_refresh_time <= now + retry + now + retry - retry_jitter <= next_refresh_time <= now + retry """ zone_retry_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[RETRY_OFFSET]) zone_retry_time = max(self._lowerbound_retry, zone_retry_time) - self._set_zone_timer(zone_name_class, zone_retry_time, self._jitter_scope * zone_retry_time) + self._set_zone_timer(zone_name_class, zone_retry_time, self._refresh_jitter * zone_retry_time) def _set_zone_notify_timer(self, zone_name_class): """Set zone next refresh time after receiving notify @@ -194,9 +194,11 @@ class ZonemgrRefresh: zone_info["zone_soa_rdata"] = zone_soa[7] zone_info["zone_state"] = ZONE_OK zone_info["last_refresh_time"] = self._get_current_time() - zone_info["next_refresh_time"] = self._get_current_time() + \ - float(zone_soa[7].split(" ")[REFRESH_OFFSET]) self._zonemgr_refresh_info[zone_name_class] = zone_info + # Imposes some random jitters to avoid many zones need to do refresh at the same time. + zone_reload_jitter = float(zone_soa[7].split(" ")[RETRY_OFFSET]) + zone_reload_jitter = max(self._lowerbound_retry, zone_reload_jitter) + self._set_zone_timer(zone_name_class, zone_reload_jitter, self._reload_jitter * zone_reload_jitter) def _zone_is_expired(self, zone_name_class): """Judge whether a zone is expired or not.""" @@ -431,7 +433,8 @@ class ZonemgrRefresh: self._lowerbound_refresh = new_config.get('lowerbound_refresh') self._lowerbound_retry = new_config.get('lowerbound_retry') self._max_transfer_timeout = new_config.get('max_transfer_timeout') - self._jitter_scope = new_config.get('jitter_scope') + self._refresh_jitter = new_config.get('refresh_jitter') + self._reload_jitter = new_config.get('reload_jitter') class Zonemgr: """Zone manager class.""" @@ -510,9 +513,9 @@ class Zonemgr: not. It contains only basic logic, not full check against database.""" # jitter should not be bigger than half of the original value - if config_data.get('jitter_scope') > 0.5: - config_data['jitter_scope'] = 0.5 - log_msg("[b10-zonemgr] jitter_scope is too big, its value will " + if config_data.get('refresh_jitter') > 0.5: + config_data['refresh_jitter'] = 0.5 + log_msg("[b10-zonemgr] refresh_jitter is too big, its value will " "be set to 0.5") diff --git a/src/bin/zonemgr/zonemgr.spec.pre.in b/src/bin/zonemgr/zonemgr.spec.pre.in index 9df01f2846d400acd2e0fba974daf0f0a6eba480..36f02df95cbec1a4df65995ae54ec9af1b949b31 100644 --- a/src/bin/zonemgr/zonemgr.spec.pre.in +++ b/src/bin/zonemgr/zonemgr.spec.pre.in @@ -12,20 +12,26 @@ "item_name": "lowerbound_retry", "item_type": "integer", "item_optional": false, - "item_default": 5 + "item_default": 5 }, { "item_name": "max_transfer_timeout", "item_type": "integer", "item_optional": false, - "item_default": 14400 + "item_default": 14400 }, { - "item_name": "jitter_scope", + "item_name": "refresh_jitter", "item_type": "real", "item_optional": false, "item_default": 0.25 }, + { + "item_name": "reload_jitter", + "item_type": "real", + "item_optional": false, + "item_default": 0.75 + }, { "item_name": "secondary_zones", "item_type": "list", diff --git a/src/cppcheck-suppress.lst b/src/cppcheck-suppress.lst index 3e4dcd69488c75b744049ab871be87069e6a741b..e9c4beb23abfa8086602e50cfcf51825aaa863b2 100644 --- a/src/cppcheck-suppress.lst +++ b/src/cppcheck-suppress.lst @@ -3,13 +3,13 @@ debug missingInclude // This is a template, and should be excluded from the check -unreadVariable:src/lib/dns/rdata/template.cc:59 +unreadVariable:src/lib/dns/rdata/template.cc:60 // These three trigger warnings due to the incomplete implementation. This is // our problem, but we need to suppress the warnings for now. functionConst:src/lib/cache/resolver_cache.h functionConst:src/lib/cache/message_cache.h functionConst:src/lib/cache/rrset_cache.h // Intentional self assignment tests. Suppress warning about them. -selfAssignment:src/lib/dns/tests/name_unittest.cc:292 -selfAssignment:src/lib/dns/tests/rdata_unittest.cc:227 +selfAssignment:src/lib/dns/tests/name_unittest.cc:293 +selfAssignment:src/lib/dns/tests/rdata_unittest.cc:228 selfAssignment:src/lib/dns/tests/tsigkey_unittest.cc:104 diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index a5f67e5b317d50ec0a2dbd5772359bbb57c8b5f1..81455c454edf954ad8fc30cc9798b82e8715ea51 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = exceptions dns cc config util python xfr bench log asiolink \ - nsas cache resolve testutils datasrc server_common +SUBDIRS = exceptions util dns cc config python xfr bench log asiolink \ + asiodns nsas cache resolve testutils datasrc server_common diff --git a/src/lib/asiodns/Makefile.am b/src/lib/asiodns/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..4bcdde6125e791d9b4c18113d81e73503154bf71 --- /dev/null +++ b/src/lib/asiodns/Makefile.am @@ -0,0 +1,34 @@ +SUBDIRS = . tests + +AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink -I$(top_builddir)/src/lib/asiolink +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util + +AM_CXXFLAGS = $(B10_CXXFLAGS) + +CLEANFILES = *.gcno *.gcda + +lib_LTLIBRARIES = libasiodns.la +libasiodns_la_SOURCES = dns_answer.h +libasiodns_la_SOURCES += asiodns.h +libasiodns_la_SOURCES += asiodef.cc asiodef.h +libasiodns_la_SOURCES += dns_lookup.h +libasiodns_la_SOURCES += dns_server.h +libasiodns_la_SOURCES += dns_service.cc dns_service.h +libasiodns_la_SOURCES += tcp_server.cc tcp_server.h +libasiodns_la_SOURCES += udp_server.cc udp_server.h +libasiodns_la_SOURCES += io_fetch.cc io_fetch.h + +EXTRA_DIST = asiodef.msg + +# Note: the ordering matters: -Wno-... must follow -Wextra (defined in +# B10_CXXFLAGS) +libasiodns_la_CXXFLAGS = $(AM_CXXFLAGS) +if USE_CLANGPP +# Same for clang++, but we need to turn off -Werror completely. +libasiodns_la_CXXFLAGS += -Wno-error +endif +libasiodns_la_CPPFLAGS = $(AM_CPPFLAGS) +libasiodns_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la diff --git a/src/lib/asiodns/README b/src/lib/asiodns/README new file mode 100644 index 0000000000000000000000000000000000000000..596d1dffa629869a05d7c37d2225fabcc1e39daa --- /dev/null +++ b/src/lib/asiodns/README @@ -0,0 +1,157 @@ +The asiodns library is intended to provide an abstraction layer between +BIND10 modules and asiolink library. + +These DNS server and client routines are written using the "stackless +coroutine" pattern invented by Chris Kohlhoff and described at +http://blog.think-async.com/2010/03/potted-guide-to-stackless-coroutines.html. +This is intended to simplify development a bit, since it allows the +routines to be written in a straightfowrard step-step-step fashion rather +than as a complex chain of separate handler functions. + +Coroutine objects (i.e., UDPServer, TCPServer and IOFetch) are objects +with reenterable operator() members. When an instance of one of these +classes is called as a function, it resumes at the position where it left +off. Thus, a UDPServer can issue an asynchronous I/O call and specify +itself as the handler object; when the call completes, the UDPServer +carries on at the same position. As a result, the code can look as +if it were using synchronous, not asynchronous, I/O, providing some of +the benefit of threading but with minimal switching overhead. + +So, in simplified form, the behavior of a DNS Server is: + + REENTER: + while true: + YIELD packet = read_packet + FORK + if not parent: + break + + # This callback informs the caller that a packet has arrived, and + # gives it a chance to update configuration, etc + SimpleCallback(packet) + YIELD answer = DNSLookup(packet, this) + response = DNSAnswer(answer) + YIELD send(response) + +At each "YIELD" point, the coroutine initiates an asynchronous operation, +then pauses and turns over control to some other task on the ASIO service +queue. When the operation completes, the coroutine resumes. + +DNSLookup, DNSAnswer and SimpleCallback define callback methods +used by a DNS Server to communicate with the module that called it. +They are abstract-only classes whose concrete implementations +are supplied by the calling module. + +The DNSLookup callback always runs asynchronously. Concrete +implementations must be sure to call the server's "resume" method when +it is finished. + +In an authoritative server, the DNSLookup implementation would examine +the query, look up the answer, then call "resume". (See the diagram +in doc/auth_process.jpg.) + +In a recursive server, the DNSLookup impelemtation would initiate a +DNSQuery, which in turn would be responsible for calling the server's +"resume" method. (See the diagram in doc/recursive_process.jpg.) + +A DNSQuery object is intended to handle resolution of a query over +the network when the local authoritative data sources or cache are not +sufficient. The plan is that it will make use of subsidiary DNSFetch +calls to get data from particular authoritative servers, and when it has +gotten a complete answer, it calls "resume". + +In current form, however, DNSQuery is much simpler; it forwards queries +to a single upstream resolver and passes the answers back to the client. +It is constructed with the address of the forward server. Queries are +initiated with the question to ask the forward server, a buffer into +which to write the answer, and a pointer to the coroutine to be resumed +when the answer has arrived. In simplified form, the DNSQuery routine is: + + REENTER: + render the question into a wire-format query packet + YIELD send(query) + YIELD response = read_packet + server->resume + +Currently, DNSQuery is only implemented for UDP queries. In future work +it will be necessary to write code to fall back to TCP when circumstances +require it. + + +Upstream Fetches +================ +Upstream fetches (queries by the resolver on behalf of a client) are made +using a slightly-modified version of the pattern described above. + +Sockets +------- +First, it will be useful to understand the class hierarchy used in the +fetch logic: + + IOSocket + | + IOAsioSocket + | + +-----+-----+ + | | +UDPSocket TCPSocket + +IOSocket is a wrapper class for a socket and is used by the authoritative +server code. It is an abstract base class, providing little more that the ability to hold the socket and to return the protocol in use. + +Built on this is IOAsioSocket, which adds the open, close, asyncSend and +asyncReceive methods. This is a template class, which takes as template +argument the class of the object that will be used as the callback when the +asynchronous operation completes. This object can be of any type, but must +include an operator() method with the signature: + + operator()(asio::error_code ec, size_t length) + +... the two arguments being the status of the completed I/O operation and +the number of bytes transferred. (In the case of the open method, the second +argument will be zero.) + +Finally, the TCPSocket and UDPSocket classes provide the body of the +asynchronous operations. + +Fetch Sequence +-------------- +The fetch is implemented by the IOFetch class, which takes as argument the +protocol to use. The sequence is: + + REENTER: + render the question into a wire-format query packet + open() // Open socket and optionally connect + if (! synchronous) { + YIELD; + } + YIELD asyncSend(query) // Send query + do { + YIELD asyncReceive(response) // Read response + } while (! complete(response)) + close() // Drop connection and close socket + server->resume + +The open() method opens a socket for use. On TCP, it also makes a +connection to the remote end. So under UDP the operation will complete +immediately, but under TCP it could take a long time. One solution would be +for the open operation to post an event to the I/O queue; then both cases +could be regarded as being equivalent, with the completion being signalled +by the posting of the completion event. However UDP is the most common case +and that would involve extra overhead. So the open() returns a status +indicating whether the operation completed asynchronously. If it did, the +code yields back to the coroutine; if not the yield is bypassed. + +The asynchronous send is straightforward, invoking the underlying ASIO +function. (Note that the address/port is supplied to both the open() and +asyncSend() methods - it is used by the TCPSocket in open() and by the +UDPSocket in asyncSend().) + +The asyncReceive() method issues an asynchronous read and waits for completion. +The fetch object keeps track of the amount of data received so far and when +the receive completes it calls a method on the socket to determine if the +entire message has been received. (This will always be the case for UDP. On +TCP though, the message is preceded by a count field as several reads may be +required to read all the data.) The fetch loops until all the data is read. + +Finally, the socket is closed and the server called to resume operation. diff --git a/src/lib/asiolink/asiodef.cc b/src/lib/asiodns/asiodef.cc similarity index 58% rename from src/lib/asiolink/asiodef.cc rename to src/lib/asiodns/asiodef.cc index 94c71b5f46b56c62784de6389cd0b3998c7ff6dd..127e8487674284605d80aa8061f25c77312f94f6 100644 --- a/src/lib/asiolink/asiodef.cc +++ b/src/lib/asiodns/asiodef.cc @@ -4,18 +4,20 @@ #include #include -namespace asiolink { - -extern const isc::log::MessageID ASIO_FETCHCOMP = "FETCHCOMP"; -extern const isc::log::MessageID ASIO_FETCHSTOP = "FETCHSTOP"; -extern const isc::log::MessageID ASIO_OPENSOCK = "OPENSOCK"; -extern const isc::log::MessageID ASIO_RECVSOCK = "RECVSOCK"; -extern const isc::log::MessageID ASIO_RECVTMO = "RECVTMO"; -extern const isc::log::MessageID ASIO_SENDSOCK = "SENDSOCK"; -extern const isc::log::MessageID ASIO_UNKORIGIN = "UNKORIGIN"; -extern const isc::log::MessageID ASIO_UNKRESULT = "UNKRESULT"; - -} // namespace asiolink +namespace isc { +namespace asiodns { + +extern const isc::log::MessageID ASIODNS_FETCHCOMP = "FETCHCOMP"; +extern const isc::log::MessageID ASIODNS_FETCHSTOP = "FETCHSTOP"; +extern const isc::log::MessageID ASIODNS_OPENSOCK = "OPENSOCK"; +extern const isc::log::MessageID ASIODNS_RECVSOCK = "RECVSOCK"; +extern const isc::log::MessageID ASIODNS_RECVTMO = "RECVTMO"; +extern const isc::log::MessageID ASIODNS_SENDSOCK = "SENDSOCK"; +extern const isc::log::MessageID ASIODNS_UNKORIGIN = "UNKORIGIN"; +extern const isc::log::MessageID ASIODNS_UNKRESULT = "UNKRESULT"; + +} // namespace asiodns +} // namespace isc namespace { diff --git a/src/lib/asiodns/asiodef.h b/src/lib/asiodns/asiodef.h new file mode 100644 index 0000000000000000000000000000000000000000..50aa8a99f39ceeb6604ecb55df5d439b2ffa3348 --- /dev/null +++ b/src/lib/asiodns/asiodef.h @@ -0,0 +1,23 @@ +// File created from asiodef.msg on Mon Feb 28 17:15:30 2011 + +#ifndef __ASIODEF_H +#define __ASIODEF_H + +#include + +namespace isc { +namespace asiodns { + +extern const isc::log::MessageID ASIODNS_FETCHCOMP; +extern const isc::log::MessageID ASIODNS_FETCHSTOP; +extern const isc::log::MessageID ASIODNS_OPENSOCK; +extern const isc::log::MessageID ASIODNS_RECVSOCK; +extern const isc::log::MessageID ASIODNS_RECVTMO; +extern const isc::log::MessageID ASIODNS_SENDSOCK; +extern const isc::log::MessageID ASIODNS_UNKORIGIN; +extern const isc::log::MessageID ASIODNS_UNKRESULT; + +} // namespace asiodns +} // namespace isc + +#endif // __ASIODEF_H diff --git a/src/lib/asiolink/asiodef.msg b/src/lib/asiodns/asiodef.msg similarity index 98% rename from src/lib/asiolink/asiodef.msg rename to src/lib/asiodns/asiodef.msg index 2fcadd1f5411435084e34f0ae55168788076a54e..7f86acb7ee5d5e65e438d3593be537614e7f1b1f 100644 --- a/src/lib/asiolink/asiodef.msg +++ b/src/lib/asiodns/asiodef.msg @@ -12,8 +12,8 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -$PREFIX ASIO_ -$NAMESPACE asiolink +$PREFIX ASIODNS_ +$NAMESPACE isc::asiodns FETCHCOMP upstream fetch to %s(%d) has now completed + A debug message, this records the the upstream fetch (a query made by the diff --git a/src/lib/asiodns/asiodns.h b/src/lib/asiodns/asiodns.h new file mode 100644 index 0000000000000000000000000000000000000000..8791a72f1ab4af61778202525ea648bb36f309fc --- /dev/null +++ b/src/lib/asiodns/asiodns.h @@ -0,0 +1,23 @@ +// Copyright (C) 2011 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. + +#ifndef __ASIODNS_H +#define __ASIODNS_H 1 + +#include +#include +#include +#include + +#endif // __ASIODNS_H diff --git a/src/lib/asiolink/dns_answer.h b/src/lib/asiodns/dns_answer.h similarity index 91% rename from src/lib/asiolink/dns_answer.h rename to src/lib/asiodns/dns_answer.h index 84e1f6fd954c6343837b9b6612b26e39c55e33ea..36543697b796d9a46b710da216f0dfd35e653951 100644 --- a/src/lib/asiolink/dns_answer.h +++ b/src/lib/asiodns/dns_answer.h @@ -16,8 +16,11 @@ #define __ASIOLINK_DNS_ANSWER_H 1 #include +#include +#include -namespace asiolink { +namespace isc { +namespace asiodns { /// \brief The \c DNSAnswer class is an abstract base class for a DNS /// Answer provider function. @@ -63,11 +66,12 @@ public: /// \param answer_message The DNS MessagePtr of the answer we are /// building /// \param buffer Intermediate data results are put here - virtual void operator()(const IOMessage& io_message, + virtual void operator()(const asiolink::IOMessage& io_message, isc::dns::MessagePtr query_message, isc::dns::MessagePtr answer_message, - isc::dns::OutputBufferPtr buffer) const = 0; + isc::util::OutputBufferPtr buffer) const = 0; }; -} // namespace asiolink +} // namespace asiodns +} // namespace isc #endif // __ASIOLINK_DNS_ANSWER_H diff --git a/src/lib/asiolink/dns_lookup.h b/src/lib/asiodns/dns_lookup.h similarity index 91% rename from src/lib/asiolink/dns_lookup.h rename to src/lib/asiodns/dns_lookup.h index a79976f5266944e28c0ab8bd6cb63fca1861792b..40290e4e71156e41a3da9fcb7529c0afe8278323 100644 --- a/src/lib/asiolink/dns_lookup.h +++ b/src/lib/asiodns/dns_lookup.h @@ -16,11 +16,12 @@ #define __ASIOLINK_DNS_LOOKUP_H 1 #include -#include -#include +#include #include +#include -namespace asiolink { +namespace isc { +namespace asiodns { /// \brief The \c DNSLookup class is an abstract base class for a DNS /// Lookup provider function. @@ -67,10 +68,10 @@ public: /// this MessagePtr /// \param buffer The final answer is put here /// \param server DNSServer object to use - virtual void operator()(const IOMessage& io_message, + virtual void operator()(const asiolink::IOMessage& io_message, isc::dns::MessagePtr message, isc::dns::MessagePtr answer_message, - isc::dns::OutputBufferPtr buffer, + isc::util::OutputBufferPtr buffer, DNSServer* server) const { (*self_)(io_message, message, answer_message, buffer, server); @@ -79,5 +80,6 @@ private: DNSLookup* self_; }; -} // namespace asiolink +} // namespace asiodns +} // namespace isc #endif // __ASIOLINK_DNS_LOOKUP_H diff --git a/src/lib/asiolink/dns_server.h b/src/lib/asiodns/dns_server.h similarity index 97% rename from src/lib/asiolink/dns_server.h rename to src/lib/asiodns/dns_server.h index f15f808e6e442ed42e22990d5771fd66501ff914..f23586062cf9cdafa1ec619d81e9f79d9268a8d8 100644 --- a/src/lib/asiolink/dns_server.h +++ b/src/lib/asiodns/dns_server.h @@ -17,7 +17,8 @@ #include -namespace asiolink { +namespace isc { +namespace asiodns { /// \brief The \c DNSServer class is a wrapper (and base class) for /// classes which provide DNS server functionality. @@ -34,7 +35,7 @@ namespace asiolink { /// instantiated through a base class) are sometimes passed by /// reference (as this superclass); calls to methods in the base /// class are then rerouted via this pointer to methods in the derived -/// class. This allows code from outside asiolink, with no specific +/// class. This allows code from outside asiodns, with no specific /// knowledge of \c TCPServer or \c UDPServer, to access their methods. /// /// This class is both assignable and copy-constructable. Its subclasses @@ -151,5 +152,6 @@ private: }; -} // asiolink +} // namespace asiodns +} // namespace isc #endif // __ASIOLINK_DNS_SERVER_H diff --git a/src/lib/asiolink/dns_service.cc b/src/lib/asiodns/dns_service.cc similarity index 97% rename from src/lib/asiolink/dns_service.cc rename to src/lib/asiodns/dns_service.cc index f17bb4483deb7d52629b367fb7c95b8e39f228e7..94510fe520a5da1b8740031df1c66cb6027d1bf6 100644 --- a/src/lib/asiolink/dns_service.cc +++ b/src/lib/asiodns/dns_service.cc @@ -23,11 +23,11 @@ #include #include -#include +#include #include #include -#include -#include +#include +#include #include @@ -36,9 +36,11 @@ using isc::log::dlog; -namespace asiolink { +using namespace isc::asiolink; + +namespace isc { +namespace asiodns { -class SimpleCallback; class DNSLookup; class DNSAnswer; @@ -195,6 +197,5 @@ DNSService::clearServers() { impl_->servers_.clear(); } - - -} // namespace asiolink +} // namespace asiodns +} // namespace isc diff --git a/src/lib/asiolink/dns_service.h b/src/lib/asiodns/dns_service.h similarity index 88% rename from src/lib/asiolink/dns_service.h rename to src/lib/asiodns/dns_service.h index 9a3fb4c44f3c1674986838ab93d30a1f54534e31..6b6a6c07f4a5a75db3405ff533ad68a9cab7ca12 100644 --- a/src/lib/asiolink/dns_service.h +++ b/src/lib/asiodns/dns_service.h @@ -18,10 +18,11 @@ #include #include +#include -namespace asiolink { +namespace isc { +namespace asiodns { -class SimpleCallback; class DNSLookup; class DNSAnswer; class DNSServiceImpl; @@ -54,8 +55,8 @@ public: /// \param checkin Provider for cc-channel events (see \c SimpleCallback) /// \param lookup The lookup provider (see \c DNSLookup) /// \param answer The answer provider (see \c DNSAnswer) - DNSService(IOService& io_service, const char& port, - const char& address, SimpleCallback* checkin, + DNSService(asiolink::IOService& io_service, const char& port, + const char& address, isc::asiolink::SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer); /// \brief The constructor with a specific port on which the services /// listen on. @@ -71,14 +72,14 @@ public: /// \param checkin Provider for cc-channel events (see \c SimpleCallback) /// \param lookup The lookup provider (see \c DNSLookup) /// \param answer The answer provider (see \c DNSAnswer) - DNSService(IOService& io_service, const char& port, + DNSService(asiolink::IOService& io_service, const char& port, const bool use_ipv4, const bool use_ipv6, - SimpleCallback* checkin, DNSLookup* lookup, + isc::asiolink::SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer); /// \brief The constructor without any servers. /// /// Use addServer() to add some servers. - DNSService(IOService& io_service, SimpleCallback* checkin, + DNSService(asiolink::IOService& io_service, isc::asiolink::SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer); /// \brief The destructor. ~DNSService(); @@ -105,8 +106,9 @@ public: private: DNSServiceImpl* impl_; - IOService& io_service_; + asiolink::IOService& io_service_; }; -} // namespace asiolink +} // namespace asiodns +} // namespace isc #endif // __ASIOLINK_DNS_SERVICE_H diff --git a/src/lib/asiolink/io_fetch.cc b/src/lib/asiodns/io_fetch.cc similarity index 85% rename from src/lib/asiolink/io_fetch.cc rename to src/lib/asiodns/io_fetch.cc index fdc1f2e9b1eed55ff4336061ea5b93f7fb5f0207..8f57d8e12707e076e899591ac34bde47e8bd5a71 100644 --- a/src/lib/asiolink/io_fetch.cc +++ b/src/lib/asiodns/io_fetch.cc @@ -14,45 +14,50 @@ #include -#include // for some IPC/network system calls -#include #include +#include +#include +#include // for some IPC/network system calls #include #include #include -#include -#include -#include -#include -#include - -#include - #include #include -#include #include #include #include -#include #include #include #include #include #include -#include -#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + using namespace asio; +using namespace isc::asiolink; using namespace isc::dns; +using namespace isc::util; +using namespace isc::util::random; using namespace isc::log; using namespace std; -namespace asiolink { +namespace isc { +namespace asiodns { /// Use the ASIO logger @@ -76,8 +81,8 @@ struct IOFetchData { boost::scoped_ptr remote_snd;///< Where the fetch is sent boost::scoped_ptr remote_rcv;///< Where the response came from isc::dns::Question question; ///< Question to be asked - isc::dns::OutputBufferPtr msgbuf; ///< Wire buffer for question - isc::dns::OutputBufferPtr received; ///< Received data put here + OutputBufferPtr msgbuf; ///< Wire buffer for question + OutputBufferPtr received; ///< Received data put here IOFetch::Callback* callback; ///< Called on I/O Completion asio::deadline_timer timer; ///< Timer to measure timeouts IOFetch::Protocol protocol; ///< Protocol being used @@ -86,6 +91,7 @@ struct IOFetchData { size_t offset; ///< Offset to receive data bool stopped; ///< Have we stopped running? int timeout; ///< Timeout in ms + bool packet; ///< true if packet was supplied // In case we need to log an error, the origin of the last asynchronous // I/O is recorded. To save time and simplify the code, this is recorded @@ -117,8 +123,7 @@ struct IOFetchData { /// TODO: May need to alter constructor (see comment 4 in Trac ticket #554) IOFetchData(IOFetch::Protocol proto, IOService& service, const isc::dns::Question& query, const IOAddress& address, - uint16_t port, isc::dns::OutputBufferPtr& buff, IOFetch::Callback* cb, - int wait) + uint16_t port, OutputBufferPtr& buff, IOFetch::Callback* cb, int wait) : socket((proto == IOFetch::UDP) ? static_cast*>( @@ -135,9 +140,8 @@ struct IOFetchData { static_cast(new TCPEndpoint(address, port)) ), question(query), - msgbuf(new isc::dns::OutputBuffer(512)), + msgbuf(new OutputBuffer(512)), received(buff), - callback(cb), timer(service.get_io_service()), protocol(proto), @@ -146,7 +150,8 @@ struct IOFetchData { offset(0), stopped(false), timeout(wait), - origin(ASIO_UNKORIGIN), + packet(false), + origin(ASIODNS_UNKORIGIN), staging(), qid(QidGenerator::getInstance().generateQid()) {} @@ -175,6 +180,19 @@ IOFetch::IOFetch(Protocol protocol, IOService& service, { } +IOFetch::IOFetch(Protocol protocol, IOService& service, + OutputBufferPtr& outpkt, const IOAddress& address, uint16_t port, + OutputBufferPtr& buff, Callback* cb, int wait) + : + data_(new IOFetchData(protocol, service, + isc::dns::Question(isc::dns::Name("dummy.example.org"), + isc::dns::RRClass::IN(), isc::dns::RRType::A()), + address, port, buff, cb, wait)) +{ + data_->msgbuf = outpkt; + data_->packet = true; +} + // Return protocol in use. IOFetch::Protocol @@ -201,14 +219,22 @@ IOFetch::operator()(asio::error_code ec, size_t length) { /// This is done in a different scope to allow inline variable /// declarations. { - Message msg(Message::RENDER); - msg.setQid(data_->qid); - msg.setOpcode(Opcode::QUERY()); - msg.setRcode(Rcode::NOERROR()); - msg.setHeaderFlag(Message::HEADERFLAG_RD); - msg.addQuestion(data_->question); - MessageRenderer renderer(*data_->msgbuf); - msg.toWire(renderer); + if (data_->packet) { + // A packet was given, overwrite the QID (which is in the + // first two bytes of the packet). + data_->msgbuf->writeUint16At(data_->qid, 0); + + } else { + // A question was given, construct the packet + Message msg(Message::RENDER); + msg.setQid(data_->qid); + msg.setOpcode(Opcode::QUERY()); + msg.setRcode(Rcode::NOERROR()); + msg.setHeaderFlag(Message::HEADERFLAG_RD); + msg.addQuestion(data_->question); + MessageRenderer renderer(*data_->msgbuf); + msg.toWire(renderer); + } } // If we timeout, we stop, which will can cancel outstanding I/Os and @@ -222,7 +248,7 @@ IOFetch::operator()(asio::error_code ec, size_t length) { // Open a connection to the target system. For speed, if the operation // is synchronous (i.e. UDP operation) we bypass the yield. - data_->origin = ASIO_OPENSOCK; + data_->origin = ASIODNS_OPENSOCK; if (data_->socket->isOpenSynchronous()) { data_->socket->open(data_->remote_snd.get(), *this); } else { @@ -232,7 +258,7 @@ IOFetch::operator()(asio::error_code ec, size_t length) { do { // Begin an asynchronous send, and then yield. When the send completes, // we will resume immediately after this point. - data_->origin = ASIO_SENDSOCK; + data_->origin = ASIODNS_SENDSOCK; CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(), data_->msgbuf->getLength(), data_->remote_snd.get(), *this); @@ -255,7 +281,7 @@ IOFetch::operator()(asio::error_code ec, size_t length) { // received all the data before copying it back to the user's buffer. // And we want to minimise the amount of copying... - data_->origin = ASIO_RECVSOCK; + data_->origin = ASIODNS_RECVSOCK; data_->cumulative = 0; // No data yet received data_->offset = 0; // First data into start of buffer data_->received->clear(); // Clear the receive buffer @@ -271,7 +297,7 @@ IOFetch::operator()(asio::error_code ec, size_t length) { // Finished with this socket, so close it. This will not generate an // I/O error, but reset the origin to unknown in case we change this. - data_->origin = ASIO_UNKORIGIN; + data_->origin = ASIODNS_UNKORIGIN; data_->socket->close(); /// We are done @@ -314,7 +340,7 @@ IOFetch::stop(Result result) { switch (result) { case TIME_OUT: if (logger.isDebugEnabled(1)) { - logger.debug(20, ASIO_RECVTMO, + logger.debug(20, ASIODNS_RECVTMO, data_->remote_snd->getAddress().toText().c_str(), static_cast(data_->remote_snd->getPort())); } @@ -322,7 +348,7 @@ IOFetch::stop(Result result) { case SUCCESS: if (logger.isDebugEnabled(50)) { - logger.debug(30, ASIO_FETCHCOMP, + logger.debug(30, ASIODNS_FETCHCOMP, data_->remote_rcv->getAddress().toText().c_str(), static_cast(data_->remote_rcv->getPort())); } @@ -332,13 +358,13 @@ IOFetch::stop(Result result) { // Fetch has been stopped for some other reason. This is // allowed but as it is unusual it is logged, but with a lower // debug level than a timeout (which is totally normal). - logger.debug(1, ASIO_FETCHSTOP, + logger.debug(1, ASIODNS_FETCHSTOP, data_->remote_snd->getAddress().toText().c_str(), static_cast(data_->remote_snd->getPort())); break; default: - logger.error(ASIO_UNKRESULT, static_cast(result), + logger.error(ASIODNS_UNKRESULT, static_cast(result), data_->remote_snd->getAddress().toText().c_str(), static_cast(data_->remote_snd->getPort())); } @@ -362,10 +388,10 @@ IOFetch::stop(Result result) { void IOFetch::logIOFailure(asio::error_code ec) { // Should only get here with a known error code. - assert((data_->origin == ASIO_OPENSOCK) || - (data_->origin == ASIO_SENDSOCK) || - (data_->origin == ASIO_RECVSOCK) || - (data_->origin == ASIO_UNKORIGIN)); + assert((data_->origin == ASIODNS_OPENSOCK) || + (data_->origin == ASIODNS_SENDSOCK) || + (data_->origin == ASIODNS_RECVSOCK) || + (data_->origin == ASIODNS_UNKORIGIN)); static const char* PROTOCOL[2] = {"TCP", "UDP"}; logger.error(data_->origin, @@ -376,5 +402,6 @@ void IOFetch::logIOFailure(asio::error_code ec) { static_cast(data_->remote_snd->getPort())); } -} // namespace asiolink +} // namespace asiodns +} // namespace isc { diff --git a/src/lib/asiolink/io_fetch.h b/src/lib/asiodns/io_fetch.h similarity index 78% rename from src/lib/asiolink/io_fetch.h rename to src/lib/asiodns/io_fetch.h index 0723777e1143ae1d2d46d76ccc2b7578919a2ea1..98c917d548fad40c14013ec8cea311d5e5b1bab9 100644 --- a/src/lib/asiolink/io_fetch.h +++ b/src/lib/asiodns/io_fetch.h @@ -24,16 +24,17 @@ #include #include +#include +#include -#include +#include #include -namespace asiolink { +namespace isc { +namespace asiodns { // Forward declarations -class IOAddress; class IOFetchData; -class IOService; /// \brief Upstream Fetch Processing /// @@ -116,12 +117,34 @@ public: /// /// Creates the object that will handle the upstream fetch. /// - /// TODO: Need to randomise the source port + /// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP + /// \param service I/O Service object to handle the asynchronous + /// operations. + /// \param question DNS question to send to the upstream server. + /// \param address IP address of upstream server + /// \param port Port to which to connect on the upstream server + /// \param buff Output buffer into which the response (in wire format) + /// is written (if a response is received). + /// \param cb Callback object containing the callback to be called when we + /// terminate. The caller is responsible for managing this object + /// and deleting it if necessary. + /// \param wait Timeout for the fetch (in ms). The default value of + /// -1 indicates no timeout. + IOFetch(Protocol protocol, isc::asiolink::IOService& service, + const isc::dns::Question& question, + const isc::asiolink::IOAddress& address, + uint16_t port, isc::util::OutputBufferPtr& buff, Callback* cb, + int wait = -1); + + /// \brief Constructor. + /// + /// Creates the object that will handle the upstream fetch. /// /// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP /// \param service I/O Service object to handle the asynchronous /// operations. - /// \param question DNS question to send to the upstream server. + /// \param outpkt Packet to send to upstream server. Note that the + /// QID (first two bytes of the packet) may be altered in the sending. /// \param buff Output buffer into which the response (in wire format) /// is written (if a response is received). /// \param cb Callback object containing the callback to be called @@ -132,9 +155,10 @@ public: /// (default = 53) /// \param wait Timeout for the fetch (in ms). The default value of /// -1 indicates no timeout. - IOFetch(Protocol protocol, IOService& service, - const isc::dns::Question& question, const IOAddress& address, - uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb, + IOFetch(Protocol protocol, isc::asiolink::IOService& service, + isc::util::OutputBufferPtr& outpkt, + const isc::asiolink::IOAddress& address, + uint16_t port, isc::util::OutputBufferPtr& buff, Callback* cb, int wait = -1); /// \brief Return Current Protocol @@ -174,6 +198,7 @@ private: }; -} // namespace asiolink +} // namespace asiodns +} // namespace isc #endif // __IO_FETCH_H diff --git a/src/lib/asiolink/tcp_server.cc b/src/lib/asiodns/tcp_server.cc similarity index 97% rename from src/lib/asiolink/tcp_server.cc rename to src/lib/asiodns/tcp_server.cc index db59551c3bd0d2a8978f17a252ac7544bcdac473..f91eb3293ba9dde8c2e12f81b8517e5107872fd6 100644 --- a/src/lib/asiolink/tcp_server.cc +++ b/src/lib/asiodns/tcp_server.cc @@ -23,11 +23,13 @@ #include +#include + #include #include #include #include -#include +#include using namespace asio; @@ -36,8 +38,11 @@ using asio::ip::tcp; using namespace std; using namespace isc::dns; +using namespace isc::util; +using namespace isc::asiolink; -namespace asiolink { +namespace isc { +namespace asiodns { /// The following functions implement the \c TCPServer class. /// @@ -235,5 +240,5 @@ TCPServer::resume(const bool done) { io_.post(*this); } -} // namespace asiolink - +} // namespace asiodns +} // namespace isc diff --git a/src/lib/asiolink/tcp_server.h b/src/lib/asiodns/tcp_server.h similarity index 89% rename from src/lib/asiolink/tcp_server.h rename to src/lib/asiodns/tcp_server.h index 2fe0d371dcf40a4d91387e8b20d041f07bba4acf..22a2f691f2dc0fd36b2e44312604c57ca48c8516 100644 --- a/src/lib/asiolink/tcp_server.h +++ b/src/lib/asiodns/tcp_server.h @@ -24,9 +24,12 @@ #include #include +#include "dns_server.h" +#include "dns_lookup.h" +#include "dns_answer.h" - -namespace asiolink { +namespace isc { +namespace asiodns { /// \brief A TCP-specific \c DNSServer object. /// @@ -36,7 +39,7 @@ class TCPServer : public virtual DNSServer, public virtual coroutine { public: explicit TCPServer(asio::io_service& io_service, const asio::ip::address& addr, const uint16_t port, - const SimpleCallback* checkin = NULL, + const isc::asiolink::SimpleCallback* checkin = NULL, const DNSLookup* lookup = NULL, const DNSAnswer* answer = NULL); @@ -91,11 +94,11 @@ private: boost::shared_ptr socket_; // The buffer into which the response is written - boost::shared_ptr respbuf_; + boost::shared_ptr respbuf_; // \c IOMessage and \c Message objects to be passed to the // DNS lookup and answer providers - boost::shared_ptr io_message_; + boost::shared_ptr io_message_; isc::dns::MessagePtr query_message_; isc::dns::MessagePtr answer_message_; @@ -108,13 +111,14 @@ private: bool done_; // Callback functions provided by the caller - const SimpleCallback* checkin_callback_; + const isc::asiolink::SimpleCallback* checkin_callback_; const DNSLookup* lookup_callback_; const DNSAnswer* answer_callback_; - boost::shared_ptr peer_; - boost::shared_ptr iosock_; + boost::shared_ptr peer_; + boost::shared_ptr iosock_; }; -} // namespace asiolink +} // namespace asiodns +} // namespace isc #endif // __TCP_SERVER_H diff --git a/src/lib/asiodns/tests/Makefile.am b/src/lib/asiodns/tests/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..fd65d0b065de2c8fa42fd98246b677def3e08145 --- /dev/null +++ b/src/lib/asiodns/tests/Makefile.am @@ -0,0 +1,50 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin +AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc -I$(top_builddir)/src/lib/util +AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\" + +AM_CXXFLAGS = $(B10_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +CLEANFILES = *.gcno *.gcda + +TESTS = +if HAVE_GTEST +TESTS += run_unittests +run_unittests_SOURCES = run_unittests.cc +run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.h +run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc +run_unittests_SOURCES += io_service_unittest.cc +run_unittests_SOURCES += dns_server_unittest.cc +run_unittests_SOURCES += io_fetch_unittest.cc + +run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) + +run_unittests_LDADD = $(GTEST_LDADD) +run_unittests_LDADD += $(SQLITE_LIBS) +run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la +run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la +run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la +run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la +run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la + +run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) + +# Note: the ordering matters: -Wno-... must follow -Wextra (defined in +# B10_CXXFLAGS) +run_unittests_CXXFLAGS = $(AM_CXXFLAGS) +if USE_GXX +run_unittests_CXXFLAGS += -Wno-unused-parameter +endif +if USE_CLANGPP +# Same for clang++, but we need to turn off -Werror completely. +run_unittests_CXXFLAGS += -Wno-error +endif +endif + +noinst_PROGRAMS = $(TESTS) diff --git a/src/lib/asiolink/tests/dns_server_unittest.cc b/src/lib/asiodns/tests/dns_server_unittest.cc similarity index 98% rename from src/lib/asiolink/tests/dns_server_unittest.cc rename to src/lib/asiodns/tests/dns_server_unittest.cc index 5b8b683276363326f4077f481d668cdc5925fc66..1ef3192f358c33f2890e7c75911c618a7bd4c6a9 100644 --- a/src/lib/asiolink/tests/dns_server_unittest.cc +++ b/src/lib/asiodns/tests/dns_server_unittest.cc @@ -18,10 +18,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include //for alarm @@ -65,8 +65,10 @@ /// involved so the message sending between client and server is plain text /// And the valid checker, question lookup and answer composition are dummy. -using namespace asiolink; +using namespace isc::asiolink; +using namespace isc::asiodns; using namespace asio; + namespace { static const std::string server_ip = "127.0.0.1"; const int server_port = 5553; @@ -109,7 +111,7 @@ class DummyLookup : public DNSLookup, public ServerStopper { void operator()(const IOMessage& io_message, isc::dns::MessagePtr message, isc::dns::MessagePtr answer_message, - isc::dns::OutputBufferPtr buffer, + isc::util::OutputBufferPtr buffer, DNSServer* server) const { stopServer(); server->resume(true); @@ -123,7 +125,7 @@ class SimpleAnswer : public DNSAnswer, public ServerStopper { void operator()(const IOMessage& message, isc::dns::MessagePtr query_message, isc::dns::MessagePtr answer_message, - isc::dns::OutputBufferPtr buffer) const + isc::util::OutputBufferPtr buffer) const { //copy what we get from user buffer->writeData(message.getData(), message.getDataSize()); diff --git a/src/lib/asiolink/tests/io_fetch_unittest.cc b/src/lib/asiodns/tests/io_fetch_unittest.cc similarity index 99% rename from src/lib/asiolink/tests/io_fetch_unittest.cc rename to src/lib/asiodns/tests/io_fetch_unittest.cc index 2b258b87b197b086ff8aff23c15679fd45e30a76..2464b6d6dcff64bca7b27543f2eafb553c7c0e8b 100644 --- a/src/lib/asiolink/tests/io_fetch_unittest.cc +++ b/src/lib/asiodns/tests/io_fetch_unittest.cc @@ -26,7 +26,9 @@ #include -#include +#include +#include + #include #include #include @@ -34,18 +36,20 @@ #include #include -#include #include #include -#include #include +#include using namespace asio; using namespace isc::dns; +using namespace isc::util; using namespace asio::ip; using namespace std; +using namespace isc::asiolink; -namespace asiolink { +namespace isc { +namespace asiodns { const asio::ip::address TEST_HOST(asio::ip::address::from_string("127.0.0.1")); const uint16_t TEST_PORT(5301); @@ -720,4 +724,5 @@ TEST_F(IOFetchTest, TcpSendReceive8192ShortSend) { } -} // namespace asiolink +} // namespace asiodns +} // namespace isc diff --git a/src/lib/asiolink/tests/io_service_unittest.cc b/src/lib/asiodns/tests/io_service_unittest.cc similarity index 98% rename from src/lib/asiolink/tests/io_service_unittest.cc rename to src/lib/asiodns/tests/io_service_unittest.cc index 779d03e88ef24e097ade8b1d1142236b636c6552..cc64022606ce74eaa585f3a70701d94b3d070217 100644 --- a/src/lib/asiolink/tests/io_service_unittest.cc +++ b/src/lib/asiodns/tests/io_service_unittest.cc @@ -17,8 +17,10 @@ #include #include +#include -using namespace asiolink; +using namespace isc::asiolink; +using namespace isc::asiodns; const char* const TEST_SERVER_PORT = "53535"; const char* const TEST_CLIENT_PORT = "53536"; diff --git a/src/lib/asiodns/tests/run_unittests.cc b/src/lib/asiodns/tests/run_unittests.cc new file mode 100644 index 0000000000000000000000000000000000000000..c285f9e8c81f5cc57d475b4f473aad8c85f7a2f0 --- /dev/null +++ b/src/lib/asiodns/tests/run_unittests.cc @@ -0,0 +1,28 @@ +// Copyright (C) 2009 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. + +#include + +#include +#include + +int +main(int argc, char* argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); // Initialize Google test + isc::log::setRootLoggerName("unittest"); // Set a root logger name + isc::UnitTestUtil::addDataPath(TEST_DATA_DIR); // Add location of test data + + return (RUN_ALL_TESTS()); +} diff --git a/src/lib/asiolink/udp_server.cc b/src/lib/asiodns/udp_server.cc similarity index 98% rename from src/lib/asiolink/udp_server.cc rename to src/lib/asiodns/udp_server.cc index 5b48f288d06ce498221999516ea5694afe79c60b..f103e5a94ce6226d3633f8a23061987a6ab3ce49 100644 --- a/src/lib/asiolink/udp_server.cc +++ b/src/lib/asiodns/udp_server.cc @@ -27,8 +27,8 @@ #include #include #include -#include #include +#include "udp_server.h" #include @@ -38,8 +38,11 @@ using isc::log::dlog; using namespace std; using namespace isc::dns; +using namespace isc::util; +using namespace isc::asiolink; -namespace asiolink { +namespace isc { +namespace asiodns { /* * Some of the member variables here are shared_ptrs and some are @@ -134,7 +137,7 @@ struct UDPServer::Data { isc::dns::MessagePtr answer_message_; // The buffer into which the response is written - isc::dns::OutputBufferPtr respbuf_; + isc::util::OutputBufferPtr respbuf_; // The buffer into which the query packet is written boost::shared_array data_; @@ -318,4 +321,5 @@ UDPServer::hasAnswer() { return (data_->done_); } -} // namespace asiolink +} // namespace asiodns +} // namespace isc diff --git a/src/lib/asiolink/udp_server.h b/src/lib/asiodns/udp_server.h similarity index 93% rename from src/lib/asiolink/udp_server.h rename to src/lib/asiodns/udp_server.h index 1d374717efcd188cf6448234297e367b416539bb..4c195443655dd03240dee9a25f4ef2a994276461 100644 --- a/src/lib/asiolink/udp_server.h +++ b/src/lib/asiodns/udp_server.h @@ -19,14 +19,15 @@ #error "asio.hpp must be included before including this, see asiolink.h as to why" #endif -#include #include -#include -#include +#include +#include +#include #include -namespace asiolink { +namespace isc { +namespace asiodns { // // Asynchronous UDP server coroutine @@ -47,7 +48,7 @@ public: /// \param answer the callbackprovider for DNS answer events explicit UDPServer(asio::io_service& io_service, const asio::ip::address& addr, const uint16_t port, - SimpleCallback* checkin = NULL, + isc::asiolink::SimpleCallback* checkin = NULL, DNSLookup* lookup = NULL, DNSAnswer* answer = NULL); @@ -102,5 +103,6 @@ private: boost::shared_ptr data_; }; -} // namespace asiolink +} // namespace asiodns +} // namespace isc #endif // __UDP_SERVER_H diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am index 2fda7284111f2805266855e1738b4ab4e5782713..66d5eda3e70b3f8fdc1f3373721d9f9dc9376c6a 100644 --- a/src/lib/asiolink/Makefile.am +++ b/src/lib/asiolink/Makefile.am @@ -13,33 +13,21 @@ CLEANFILES = *.gcno *.gcda # which would make the build fail with -Werror (our default setting). lib_LTLIBRARIES = libasiolink.la libasiolink_la_SOURCES = asiolink.h -libasiolink_la_SOURCES += asiolink_utilities.h -libasiolink_la_SOURCES += asiodef.cc asiodef.h -libasiolink_la_SOURCES += dns_answer.h -libasiolink_la_SOURCES += dns_lookup.h -libasiolink_la_SOURCES += dns_server.h -libasiolink_la_SOURCES += dns_service.cc dns_service.h libasiolink_la_SOURCES += dummy_io_cb.h libasiolink_la_SOURCES += interval_timer.cc interval_timer.h libasiolink_la_SOURCES += io_address.cc io_address.h libasiolink_la_SOURCES += io_asio_socket.h libasiolink_la_SOURCES += io_endpoint.cc io_endpoint.h libasiolink_la_SOURCES += io_error.h -libasiolink_la_SOURCES += io_fetch.cc io_fetch.h libasiolink_la_SOURCES += io_message.h -libasiolink_la_SOURCES += qid_gen.cc qid_gen.h libasiolink_la_SOURCES += io_service.h io_service.cc libasiolink_la_SOURCES += io_socket.h io_socket.cc libasiolink_la_SOURCES += simple_callback.h libasiolink_la_SOURCES += tcp_endpoint.h -libasiolink_la_SOURCES += tcp_server.cc tcp_server.h libasiolink_la_SOURCES += tcp_socket.h libasiolink_la_SOURCES += udp_endpoint.h -libasiolink_la_SOURCES += udp_server.cc udp_server.h libasiolink_la_SOURCES += udp_socket.h -EXTRA_DIST = asiodef.msg - # Note: the ordering matters: -Wno-... must follow -Wextra (defined in # B10_CXXFLAGS) libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS) diff --git a/src/lib/asiolink/README b/src/lib/asiolink/README index 6bd1a7383c28a33bf384193fb387ded30c562a24..66091b1c2bc403756be440cc0b42137f559f0878 100644 --- a/src/lib/asiolink/README +++ b/src/lib/asiolink/README @@ -16,167 +16,7 @@ including: them in only one place allows us to relax strictness here, while leaving it in place elsewhere. -Currently, the asiolink library only supports DNS servers (i.e., b10-auth -and b10-resolver). The plan is to make it more generic and allow it to -support other modules as well. - Some of the classes defined here--for example, IOSocket, IOEndpoint, and IOAddress--are to be used by BIND 10 modules as wrappers around ASIO-specific classes. -Other classes implement the DNS protocol on behalf of BIND 10 modules. - -These DNS server and client routines are written using the "stackless -coroutine" pattern invented by Chris Kohlhoff and described at -http://blog.think-async.com/2010/03/potted-guide-to-stackless-coroutines.html. -This is intended to simplify development a bit, since it allows the -routines to be written in a straightfowrard step-step-step fashion rather -than as a complex chain of separate handler functions. - -Coroutine objects (i.e., UDPServer, TCPServer and IOFetch) are objects -with reenterable operator() members. When an instance of one of these -classes is called as a function, it resumes at the position where it left -off. Thus, a UDPServer can issue an asynchronous I/O call and specify -itself as the handler object; when the call completes, the UDPServer -carries on at the same position. As a result, the code can look as -if it were using synchronous, not asynchronous, I/O, providing some of -the benefit of threading but with minimal switching overhead. - -So, in simplified form, the behavior of a DNS Server is: - - REENTER: - while true: - YIELD packet = read_packet - FORK - if not parent: - break - - # This callback informs the caller that a packet has arrived, and - # gives it a chance to update configuration, etc - SimpleCallback(packet) - YIELD answer = DNSLookup(packet, this) - response = DNSAnswer(answer) - YIELD send(response) - -At each "YIELD" point, the coroutine initiates an asynchronous operation, -then pauses and turns over control to some other task on the ASIO service -queue. When the operation completes, the coroutine resumes. - -DNSLookup, DNSAnswer and SimpleCallback define callback methods -used by a DNS Server to communicate with the module that called it. -They are abstract-only classes whose concrete implementations -are supplied by the calling module. - -The DNSLookup callback always runs asynchronously. Concrete -implementations must be sure to call the server's "resume" method when -it is finished. - -In an authoritative server, the DNSLookup implementation would examine -the query, look up the answer, then call "resume". (See the diagram -in doc/auth_process.jpg.) - -In a recursive server, the DNSLookup impelemtation would initiate a -DNSQuery, which in turn would be responsible for calling the server's -"resume" method. (See the diagram in doc/recursive_process.jpg.) - -A DNSQuery object is intended to handle resolution of a query over -the network when the local authoritative data sources or cache are not -sufficient. The plan is that it will make use of subsidiary DNSFetch -calls to get data from particular authoritative servers, and when it has -gotten a complete answer, it calls "resume". - -In current form, however, DNSQuery is much simpler; it forwards queries -to a single upstream resolver and passes the answers back to the client. -It is constructed with the address of the forward server. Queries are -initiated with the question to ask the forward server, a buffer into -which to write the answer, and a pointer to the coroutine to be resumed -when the answer has arrived. In simplified form, the DNSQuery routine is: - - REENTER: - render the question into a wire-format query packet - YIELD send(query) - YIELD response = read_packet - server->resume - -Currently, DNSQuery is only implemented for UDP queries. In future work -it will be necessary to write code to fall back to TCP when circumstances -require it. - - -Upstream Fetches -================ -Upstream fetches (queries by the resolver on behalf of a client) are made -using a slightly-modified version of the pattern described above. - -Sockets -------- -First, it will be useful to understand the class hierarchy used in the -fetch logic: - - IOSocket - | - IOAsioSocket - | - +-----+-----+ - | | -UDPSocket TCPSocket - -IOSocket is a wrapper class for a socket and is used by the authoritative -server code. It is an abstract base class, providing little more that the ability to hold the socket and to return the protocol in use. - -Built on this is IOAsioSocket, which adds the open, close, asyncSend and -asyncReceive methods. This is a template class, which takes as template -argument the class of the object that will be used as the callback when the -asynchronous operation completes. This object can be of any type, but must -include an operator() method with the signature: - - operator()(asio::error_code ec, size_t length) - -... the two arguments being the status of the completed I/O operation and -the number of bytes transferred. (In the case of the open method, the second -argument will be zero.) - -Finally, the TCPSocket and UDPSocket classes provide the body of the -asynchronous operations. - -Fetch Sequence --------------- -The fetch is implemented by the IOFetch class, which takes as argument the -protocol to use. The sequence is: - - REENTER: - render the question into a wire-format query packet - open() // Open socket and optionally connect - if (! synchronous) { - YIELD; - } - YIELD asyncSend(query) // Send query - do { - YIELD asyncReceive(response) // Read response - } while (! complete(response)) - close() // Drop connection and close socket - server->resume - -The open() method opens a socket for use. On TCP, it also makes a -connection to the remote end. So under UDP the operation will complete -immediately, but under TCP it could take a long time. One solution would be -for the open operation to post an event to the I/O queue; then both cases -could be regarded as being equivalent, with the completion being signalled -by the posting of the completion event. However UDP is the most common case -and that would involve extra overhead. So the open() returns a status -indicating whether the operation completed asynchronously. If it did, the -code yields back to the coroutine; if not the yield is bypassed. - -The asynchronous send is straightforward, invoking the underlying ASIO -function. (Note that the address/port is supplied to both the open() and -asyncSend() methods - it is used by the TCPSocket in open() and by the -UDPSocket in asyncSend().) - -The asyncReceive() method issues an asynchronous read and waits for completion. -The fetch object keeps track of the amount of data received so far and when -the receive completes it calls a method on the socket to determine if the -entire message has been received. (This will always be the case for UDP. On -TCP though, the message is preceded by a count field as several reads may be -required to read all the data.) The fetch loops until all the data is read. - -Finally, the socket is closed and the server called to resume operation. diff --git a/src/lib/asiolink/asiodef.h b/src/lib/asiolink/asiodef.h deleted file mode 100644 index ba77817974164a6a4b5f4b0bd3b71b9f3f30b2cd..0000000000000000000000000000000000000000 --- a/src/lib/asiolink/asiodef.h +++ /dev/null @@ -1,21 +0,0 @@ -// File created from asiodef.msg on Mon Feb 28 17:15:30 2011 - -#ifndef __ASIODEF_H -#define __ASIODEF_H - -#include - -namespace asiolink { - -extern const isc::log::MessageID ASIO_FETCHCOMP; -extern const isc::log::MessageID ASIO_FETCHSTOP; -extern const isc::log::MessageID ASIO_OPENSOCK; -extern const isc::log::MessageID ASIO_RECVSOCK; -extern const isc::log::MessageID ASIO_RECVTMO; -extern const isc::log::MessageID ASIO_SENDSOCK; -extern const isc::log::MessageID ASIO_UNKORIGIN; -extern const isc::log::MessageID ASIO_UNKRESULT; - -} // namespace asiolink - -#endif // __ASIODEF_H diff --git a/src/lib/asiolink/asiolink.h b/src/lib/asiolink/asiolink.h index 6e8fe84c0ea0f53fa3d09fd1b100b685d95d3af5..51d3a141c1450a534e0da0ce4b52a655040119cf 100644 --- a/src/lib/asiolink/asiolink.h +++ b/src/lib/asiolink/asiolink.h @@ -20,10 +20,6 @@ // See the description of the namespace below. #include -#include -#include -#include -#include #include #include @@ -62,11 +58,6 @@ /// this module. The resulting interfaces are thus straightforward mapping /// to the ASIO counterparts. /// -/// Notes to developers: -/// Currently the wrapper interface is fairly specific to use by a -/// DNS server, i.e., b10-auth or b10-resolver. But the plan is to -/// generalize it and have other modules use it as well. -/// /// One obvious drawback of this approach is performance overhead /// due to the additional layer. We should eventually evaluate the cost /// of the wrapper abstraction in benchmark tests. Another drawback is diff --git a/src/lib/asiolink/dummy_io_cb.h b/src/lib/asiolink/dummy_io_cb.h index 0006b95cfcbc131bed5714b778f01c1416c54fe4..2081906dd3a04f2e5f357239a330ac1ef870e7d5 100644 --- a/src/lib/asiolink/dummy_io_cb.h +++ b/src/lib/asiolink/dummy_io_cb.h @@ -20,6 +20,7 @@ #include #include +namespace isc { namespace asiolink { /// \brief Asynchronous I/O Completion Callback @@ -55,5 +56,6 @@ public: }; } // namespace asiolink +} // namespace isc #endif // __DUMMY_IO_CB_H diff --git a/src/lib/asiolink/interval_timer.cc b/src/lib/asiolink/interval_timer.cc index 8efb102cd9efb67367b8da889afce7eec0482d45..0ed06eb98509202de138f9ec4f7af8b151ea066a 100644 --- a/src/lib/asiolink/interval_timer.cc +++ b/src/lib/asiolink/interval_timer.cc @@ -26,6 +26,7 @@ #include #include +namespace isc { namespace asiolink { class IntervalTimerImpl { @@ -133,4 +134,5 @@ IntervalTimer::getInterval() const { return (impl_->getInterval()); } -} +} // namespace asiolink +} // namespace isc diff --git a/src/lib/asiolink/interval_timer.h b/src/lib/asiolink/interval_timer.h index 6c4332764d71567fa9eff4ebd7ace93b731d8b6f..0831d449f5553e40be425f94192eace95fc2bcb4 100644 --- a/src/lib/asiolink/interval_timer.h +++ b/src/lib/asiolink/interval_timer.h @@ -19,6 +19,7 @@ #include +namespace isc { namespace asiolink { struct IntervalTimerImpl; @@ -129,5 +130,6 @@ private: IntervalTimerImpl* impl_; }; -} // namespace asiolink +} // namespace asiolink +} // namespace isc #endif // __ASIOLINK_INTERVAL_TIMER_H diff --git a/src/lib/asiolink/io_address.cc b/src/lib/asiolink/io_address.cc index 70e837456d2e00d8665884e95f6d7a6ed2d2dce2..7f7a6fc2b322ec6eeaaf01594e1420c92b2f5858 100644 --- a/src/lib/asiolink/io_address.cc +++ b/src/lib/asiolink/io_address.cc @@ -31,6 +31,7 @@ using asio::ip::tcp; using namespace std; +namespace isc { namespace asiolink { // XXX: we cannot simply construct the address in the initialization list, @@ -62,4 +63,5 @@ IOAddress::getFamily() const { } } -} +} // namespace asiolink +} // namespace isc diff --git a/src/lib/asiolink/io_address.h b/src/lib/asiolink/io_address.h index 53c1a7a13a6543153ab15bb0abd815b5780e4a9c..655b727896f689ec07e3467b54a07ca51a3d6abc 100644 --- a/src/lib/asiolink/io_address.h +++ b/src/lib/asiolink/io_address.h @@ -26,6 +26,7 @@ #include +namespace isc { namespace asiolink { /// \brief The \c IOAddress class represents an IP addresses (version @@ -119,5 +120,6 @@ private: asio::ip::address asio_address_; }; -} // asiolink +} // namespace asiolink +} // namespace isc #endif // __IO_ADDRESS_H diff --git a/src/lib/asiolink/io_asio_socket.h b/src/lib/asiolink/io_asio_socket.h index ac793a6af7a5f455b303f8d2ebef92a773f1e370..864708cdfd22d96f6b9945888b0129817a304228 100644 --- a/src/lib/asiolink/io_asio_socket.h +++ b/src/lib/asiolink/io_asio_socket.h @@ -26,12 +26,12 @@ #include #include -#include +#include #include #include - +namespace isc { namespace asiolink { /// \brief Socket not open @@ -270,7 +270,7 @@ public: virtual bool processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, - isc::dns::OutputBufferPtr& outbuff) = 0; + isc::util::OutputBufferPtr& outbuff) = 0; /// \brief Cancel I/O On AsioSocket virtual void cancel() = 0; @@ -372,7 +372,7 @@ public: virtual bool receiveComplete(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, - isc::dns::OutputBufferPtr& outbuff) + isc::util::OutputBufferPtr& outbuff) { return (true); } @@ -395,5 +395,6 @@ private: }; } // namespace asiolink +} // namespace isc #endif // __IO_ASIO_SOCKET_H diff --git a/src/lib/asiolink/io_endpoint.cc b/src/lib/asiolink/io_endpoint.cc index e0b1a9eb2cebbc08ee53553fd7a8839ff2e703a1..63830a5b5ea3f988fbba6f7c3f6cb411a4305342 100644 --- a/src/lib/asiolink/io_endpoint.cc +++ b/src/lib/asiolink/io_endpoint.cc @@ -28,6 +28,7 @@ using namespace std; +namespace isc { namespace asiolink { const IOEndpoint* @@ -57,4 +58,5 @@ IOEndpoint::operator!=(const IOEndpoint& other) const { return (!operator==(other)); } -} +} // namespace asiolink +} // namespace isc diff --git a/src/lib/asiolink/io_endpoint.h b/src/lib/asiolink/io_endpoint.h index d21da96ea9d0117d5dbe5db60c872bc29ed64889..756fa3b4ce6a7f54aa79f4b4d9597669f7095ca8 100644 --- a/src/lib/asiolink/io_endpoint.h +++ b/src/lib/asiolink/io_endpoint.h @@ -26,6 +26,7 @@ #include #include +namespace isc { namespace asiolink { /// \brief The \c IOEndpoint class is an abstract base class to represent @@ -117,5 +118,6 @@ public: const unsigned short port); }; -} // asiolink +} // namespace asiolink +} // namespace isc #endif // __IO_ENDPOINT_H diff --git a/src/lib/asiolink/io_error.h b/src/lib/asiolink/io_error.h index 2869e0bd1a031fe6ddb757f81f2bd429e3453745..c19d91c693711dfc4e999214d28b1d12503f916d 100644 --- a/src/lib/asiolink/io_error.h +++ b/src/lib/asiolink/io_error.h @@ -18,6 +18,7 @@ #include +namespace isc { namespace asiolink { /// \brief An exception that is thrown if an error occurs within the IO @@ -30,6 +31,7 @@ public: }; -} // asiolink +} // namespace asiolink +} // namespace isc #endif // __IO_ERROR_H diff --git a/src/lib/asiolink/io_message.h b/src/lib/asiolink/io_message.h index e857bd9f1cf3f5bea873deb596c851255b03e13a..81f6da1cf0663a6cf4e850baf005e2c4dba44fa2 100644 --- a/src/lib/asiolink/io_message.h +++ b/src/lib/asiolink/io_message.h @@ -28,6 +28,7 @@ #include #include +namespace isc { namespace asiolink { /// \brief The \c IOMessage class encapsulates an incoming message received @@ -96,5 +97,6 @@ private: }; -} // asiolink +} // namespace asiolink +} // namespace isc #endif // __IO_MESSAGE_H diff --git a/src/lib/asiolink/io_service.cc b/src/lib/asiolink/io_service.cc index 55fc4b3560fce4678d2030b9bd1ad2b9c1d0fea7..70cc18b0fa184d109b6cd70363db4144202fff5c 100644 --- a/src/lib/asiolink/io_service.cc +++ b/src/lib/asiolink/io_service.cc @@ -21,6 +21,7 @@ #include #include +namespace isc { namespace asiolink { class IOServiceImpl { @@ -95,4 +96,5 @@ IOService::get_io_service() { return (io_impl_->get_io_service()); } -} // namepsace asiolink +} // namespace asiolink +} // namespace isc diff --git a/src/lib/asiolink/io_service.h b/src/lib/asiolink/io_service.h index 66558b7e26734988af7e3ad61e26ca39f84d9ac2..438667c92720e7a004bdca4bc0248c74ee6f4cd9 100644 --- a/src/lib/asiolink/io_service.h +++ b/src/lib/asiolink/io_service.h @@ -19,6 +19,7 @@ namespace asio { class io_service; } +namespace isc { namespace asiolink { struct IOServiceImpl; @@ -73,5 +74,6 @@ private: IOServiceImpl* io_impl_; }; -} // namespace asiolink +} // namespace asiolink +} // namespace isc #endif // __ASIOLINK_IO_SERVICE_H diff --git a/src/lib/asiolink/io_socket.cc b/src/lib/asiolink/io_socket.cc index c386ca159a9eeeac45e3ad49482c1d1a0c82e84a..e1498dc9739c68cb04c748050395e8d6b33da2a6 100644 --- a/src/lib/asiolink/io_socket.cc +++ b/src/lib/asiolink/io_socket.cc @@ -16,8 +16,7 @@ #include -using namespace asio; - +namespace isc { namespace asiolink { /// \brief The \c DummySocket class is a concrete derived class of @@ -62,4 +61,5 @@ IOSocket::getDummyTCPSocket() { return (socket); } -} +} // namespace asiolink +} // namespace isc diff --git a/src/lib/asiolink/io_socket.h b/src/lib/asiolink/io_socket.h index bebc8b6bf8fc8a0d6224537ac29904d167ccc160..ab6479c62ae84f9418d379797f395f60696435cb 100644 --- a/src/lib/asiolink/io_socket.h +++ b/src/lib/asiolink/io_socket.h @@ -25,6 +25,7 @@ #include +namespace isc { namespace asiolink { /// \brief The \c IOSocket class is an abstract base class to represent @@ -120,5 +121,6 @@ public: }; } // namespace asiolink +} // namespace isc #endif // __IO_SOCKET_H diff --git a/src/lib/asiolink/simple_callback.h b/src/lib/asiolink/simple_callback.h index ab5deaf12f65f2b93d0b535c9876638e64595294..92093ec5943dfa5b119056439a083fbed4b60d8f 100644 --- a/src/lib/asiolink/simple_callback.h +++ b/src/lib/asiolink/simple_callback.h @@ -17,6 +17,7 @@ #include +namespace isc { namespace asiolink { /// \brief The \c SimpleCallback class is an abstract base class for a @@ -67,5 +68,6 @@ private: SimpleCallback* self_; }; -} // namespace asiolink +} // namespace asiolink +} // namespace isc #endif // __ASIOLINK_SIMPLE_CALLBACK_H diff --git a/src/lib/asiolink/tcp_endpoint.h b/src/lib/asiolink/tcp_endpoint.h index 158ca4a97e93655ec8714f15961a6d1d4922fa69..3e420f3276ef9f866ad5b96ca8b8c903d9e53d98 100644 --- a/src/lib/asiolink/tcp_endpoint.h +++ b/src/lib/asiolink/tcp_endpoint.h @@ -21,6 +21,7 @@ #include +namespace isc { namespace asiolink { /// \brief The \c TCPEndpoint class is a concrete derived class of @@ -109,5 +110,6 @@ private: asio::ip::tcp::endpoint& asio_endpoint_; }; -} // namespace asiolink +} // namespace asiolink +} // namespace isc #endif // __TCP_ENDPOINT_H diff --git a/src/lib/asiolink/tcp_socket.h b/src/lib/asiolink/tcp_socket.h index e6e0863b197c8a3496c6672aa58487d3ff7a8219..c8876c89ec84904319d53b7ca33d0785302bb100 100644 --- a/src/lib/asiolink/tcp_socket.h +++ b/src/lib/asiolink/tcp_socket.h @@ -33,14 +33,15 @@ #include -#include +#include +#include -#include #include #include #include #include +namespace isc { namespace asiolink { /// \brief Buffer Too Large @@ -155,7 +156,7 @@ public: virtual bool processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, - isc::dns::OutputBufferPtr& outbuff); + isc::util::OutputBufferPtr& outbuff); /// \brief Cancel I/O On Socket virtual void cancel(); @@ -185,7 +186,7 @@ private: // The option of sending the data in two operations, the count followed by // the data was discounted as that would lead to two callbacks which would // cause problems with the stackless coroutine code. - isc::dns::OutputBufferPtr send_buffer_; ///< Send buffer + isc::util::OutputBufferPtr send_buffer_; ///< Send buffer }; // Constructor - caller manages socket @@ -268,7 +269,7 @@ TCPSocket::asyncSend(const void* data, size_t length, uint16_t count = boost::numeric_cast(length); // Copy data into a buffer preceded by the count field. - send_buffer_.reset(new isc::dns::OutputBuffer(length + 2)); + send_buffer_.reset(new isc::util::OutputBuffer(length + 2)); send_buffer_->writeUint16(count); send_buffer_->writeData(data, length); @@ -333,7 +334,7 @@ template bool TCPSocket::processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, - isc::dns::OutputBufferPtr& outbuff) + isc::util::OutputBufferPtr& outbuff) { // Point to the data in the staging buffer and note how much there is. const uint8_t* data = static_cast(staging); @@ -358,7 +359,7 @@ TCPSocket::processReceivedData(const void* staging, size_t length, } // Have enough data to interpret the packet count, so do so now. - expected = readUint16(data); + expected = isc::util::readUint16(data); // We have two bytes less of data to process. Point to the start of the // data and adjust the packet size. Note that at this point, @@ -412,5 +413,6 @@ TCPSocket::close() { } } // namespace asiolink +} // namespace isc #endif // __TCP_SOCKET_H diff --git a/src/lib/asiolink/tests/Makefile.am b/src/lib/asiolink/tests/Makefile.am index f67e5470f55fec5ed552dcfa9486e638e2cdaa30..37d9ef39e190559302b694e3b998f38022c0698d 100644 --- a/src/lib/asiolink/tests/Makefile.am +++ b/src/lib/asiolink/tests/Makefile.am @@ -1,6 +1,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin +AM_CPPFLAGS += -I$(top_builddir)/src/lib/util -I$(top_srcdir)/src/util AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\" @@ -18,19 +19,14 @@ TESTS += run_unittests run_unittests_SOURCES = run_unittests.cc run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.h run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc -run_unittests_SOURCES += asiolink_utilities_unittest.cc run_unittests_SOURCES += io_address_unittest.cc run_unittests_SOURCES += io_endpoint_unittest.cc -run_unittests_SOURCES += io_fetch_unittest.cc run_unittests_SOURCES += io_socket_unittest.cc -run_unittests_SOURCES += io_service_unittest.cc run_unittests_SOURCES += interval_timer_unittest.cc run_unittests_SOURCES += tcp_endpoint_unittest.cc run_unittests_SOURCES += tcp_socket_unittest.cc run_unittests_SOURCES += udp_endpoint_unittest.cc run_unittests_SOURCES += udp_socket_unittest.cc -run_unittests_SOURCES += dns_server_unittest.cc -run_unittests_SOURCES += qid_gen_unittest.cc run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) @@ -38,6 +34,7 @@ run_unittests_LDADD = $(GTEST_LDADD) run_unittests_LDADD += $(SQLITE_LIBS) run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la diff --git a/src/lib/asiolink/tests/interval_timer_unittest.cc b/src/lib/asiolink/tests/interval_timer_unittest.cc index 7e0e7bcc1b68c4843675c86a036026110889ca5f..c24e60effa630a062025855a67599c862d83ecd3 100644 --- a/src/lib/asiolink/tests/interval_timer_unittest.cc +++ b/src/lib/asiolink/tests/interval_timer_unittest.cc @@ -26,7 +26,7 @@ const boost::posix_time::time_duration TIMER_MARGIN_MSEC = boost::posix_time::milliseconds(50); } -using namespace asiolink; +using namespace isc::asiolink; // This fixture is for testing IntervalTimer. Some callback functors are // registered as callback function of the timer to test if they are called diff --git a/src/lib/asiolink/tests/io_address_unittest.cc b/src/lib/asiolink/tests/io_address_unittest.cc index 894f1433cc009fd445148dc1d28cb10588d2c6ce..18b181e8b6efa4c91d012a4bc55a52116f185dba 100644 --- a/src/lib/asiolink/tests/io_address_unittest.cc +++ b/src/lib/asiolink/tests/io_address_unittest.cc @@ -18,7 +18,7 @@ #include #include -using namespace asiolink; +using namespace isc::asiolink; TEST(IOAddressTest, fromText) { IOAddress io_address_v4("192.0.2.1"); diff --git a/src/lib/asiolink/tests/io_endpoint_unittest.cc b/src/lib/asiolink/tests/io_endpoint_unittest.cc index 5170f7d105ee6409000ee5192f5e42ae767201b4..ce21fde111d34c65bc68e385b388cdf06f396318 100644 --- a/src/lib/asiolink/tests/io_endpoint_unittest.cc +++ b/src/lib/asiolink/tests/io_endpoint_unittest.cc @@ -18,7 +18,7 @@ #include #include -using namespace asiolink; +using namespace isc::asiolink; TEST(IOEndpointTest, createUDPv4) { const IOEndpoint* ep; diff --git a/src/lib/asiolink/tests/io_socket_unittest.cc b/src/lib/asiolink/tests/io_socket_unittest.cc index 6538550bc89e6c62153a168dae652e3372b17a79..15afc170b9bf71941ebd812596df3e85274d5522 100644 --- a/src/lib/asiolink/tests/io_socket_unittest.cc +++ b/src/lib/asiolink/tests/io_socket_unittest.cc @@ -20,7 +20,7 @@ #include #include -using namespace asiolink; +using namespace isc::asiolink; TEST(IOSocketTest, dummySockets) { EXPECT_EQ(IPPROTO_UDP, IOSocket::getDummyUDPSocket().getProtocol()); diff --git a/src/lib/asiolink/tests/tcp_endpoint_unittest.cc b/src/lib/asiolink/tests/tcp_endpoint_unittest.cc index 3787e1c152e42dde55d97ed5002dea0188d01d7b..6988082edc88d3997b2a0e34c8aeb9b38786a53f 100644 --- a/src/lib/asiolink/tests/tcp_endpoint_unittest.cc +++ b/src/lib/asiolink/tests/tcp_endpoint_unittest.cc @@ -22,7 +22,7 @@ #include #include -using namespace asiolink; +using namespace isc::asiolink; using namespace std; // This test checks that the endpoint can manage its own internal diff --git a/src/lib/asiolink/tests/tcp_socket_unittest.cc b/src/lib/asiolink/tests/tcp_socket_unittest.cc index f0a45eeaa4f7d72411e86174231b2dbc6b873492..538cf48386a158bea0be7dfef4049ae389047275 100644 --- a/src/lib/asiolink/tests/tcp_socket_unittest.cc +++ b/src/lib/asiolink/tests/tcp_socket_unittest.cc @@ -35,19 +35,19 @@ #include #include -#include +#include +#include #include -#include #include #include #include using namespace asio; using namespace asio::ip; -using namespace asiolink; -using namespace isc::dns; +using namespace isc::util; +using namespace isc::asiolink; using namespace std; namespace { diff --git a/src/lib/asiolink/tests/udp_endpoint_unittest.cc b/src/lib/asiolink/tests/udp_endpoint_unittest.cc index 18135ec26b4b12d0df4cfa4be317c368004bf60f..03de6b8ae8eab2d60d2da6fad3d963c0557b382f 100644 --- a/src/lib/asiolink/tests/udp_endpoint_unittest.cc +++ b/src/lib/asiolink/tests/udp_endpoint_unittest.cc @@ -22,7 +22,7 @@ #include #include -using namespace asiolink; +using namespace isc::asiolink; using namespace std; // This test checks that the endpoint can manage its own internal diff --git a/src/lib/asiolink/tests/udp_socket_unittest.cc b/src/lib/asiolink/tests/udp_socket_unittest.cc index 8563d22b79da6ab5af8caed1696f3850f8b07491..1ab1a09c0992d5f00e3a6bf06729a811b057e213 100644 --- a/src/lib/asiolink/tests/udp_socket_unittest.cc +++ b/src/lib/asiolink/tests/udp_socket_unittest.cc @@ -35,18 +35,18 @@ #include #include -#include +#include +#include #include -#include #include #include #include using namespace asio; -using namespace asiolink; -using namespace isc::dns; +using namespace isc::util; +using namespace isc::asiolink; using namespace std; namespace { diff --git a/src/lib/asiolink/udp_endpoint.h b/src/lib/asiolink/udp_endpoint.h index 99dc27ffee95614558a0ce1ec13e2083e11edd18..5c8a1fe18cdf0f50128e7b7091cf13e0ab4fd0ed 100644 --- a/src/lib/asiolink/udp_endpoint.h +++ b/src/lib/asiolink/udp_endpoint.h @@ -21,6 +21,7 @@ #include +namespace isc { namespace asiolink { /// \brief The \c UDPEndpoint class is a concrete derived class of @@ -109,5 +110,6 @@ private: asio::ip::udp::endpoint& asio_endpoint_; }; -} // namespace asiolink +} // namespace asiolink +} // namespace isc #endif // __UDP_ENDPOINT_H diff --git a/src/lib/asiolink/udp_socket.h b/src/lib/asiolink/udp_socket.h index 35fc7b1841984147454911156a9c9b5ab9d34483..c061fba965cccace96db854ef309bc50978d25cd 100644 --- a/src/lib/asiolink/udp_socket.h +++ b/src/lib/asiolink/udp_socket.h @@ -33,6 +33,7 @@ #include #include +namespace isc { namespace asiolink { /// \brief The \c UDPSocket class is a concrete derived class of \c IOAsioSocket @@ -141,7 +142,7 @@ public: virtual bool processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, - isc::dns::OutputBufferPtr& outbuff); + isc::util::OutputBufferPtr& outbuff); /// \brief Cancel I/O On Socket virtual void cancel(); @@ -283,7 +284,7 @@ template bool UDPSocket::processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, - isc::dns::OutputBufferPtr& outbuff) + isc::util::OutputBufferPtr& outbuff) { // Set return values to what we should expect. cumulative = length; @@ -318,5 +319,6 @@ UDPSocket::close() { } } // namespace asiolink +} // namespace isc #endif // __UDP_SOCKET_H diff --git a/src/lib/bench/benchmark_util.cc b/src/lib/bench/benchmark_util.cc index ca2ca1b4156e2be458a6d7dfcc35f1489b059283..c67a851eb3562ea317bc209041631704a0d2b2e1 100644 --- a/src/lib/bench/benchmark_util.cc +++ b/src/lib/bench/benchmark_util.cc @@ -19,7 +19,7 @@ #include -#include +#include #include #include #include @@ -35,6 +35,7 @@ using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; namespace isc { namespace bench { diff --git a/src/lib/bench/tests/Makefile.am b/src/lib/bench/tests/Makefile.am index 63d3c878316da00ed7f331fb0325fd2a3b144843..4259b0ef85e203ecc5f9437f5e94935d2b1f2f40 100644 --- a/src/lib/bench/tests/Makefile.am +++ b/src/lib/bench/tests/Makefile.am @@ -16,6 +16,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) run_unittests_LDADD = $(top_builddir)/src/lib/exceptions/libexceptions.la run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la run_unittests_LDADD += $(top_builddir)/src/lib/bench/libbench.la run_unittests_LDADD += $(GTEST_LDADD) endif diff --git a/src/lib/bench/tests/loadquery_unittest.cc b/src/lib/bench/tests/loadquery_unittest.cc index a53e19151ada576817794878e1baf239debc074d..93130d2fc74e07be6562ba725a2a8c996b1919cd 100644 --- a/src/lib/bench/tests/loadquery_unittest.cc +++ b/src/lib/bench/tests/loadquery_unittest.cc @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -32,6 +32,7 @@ using namespace std; using namespace isc::bench; using namespace isc::dns; +using namespace isc::util; namespace { typedef pair QueryParam; diff --git a/src/lib/cache/Makefile.am b/src/lib/cache/Makefile.am index 107fc9a5a0c68ecb7dd6cd8cdfceaa40537c49dc..bfbe24a0b2a4dd35f13c5d1b929ec014a82e0c6f 100644 --- a/src/lib/cache/Makefile.am +++ b/src/lib/cache/Makefile.am @@ -2,6 +2,7 @@ SUBDIRS = . tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG) +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cache -I$(top_builddir)/src/lib/cache diff --git a/src/lib/cache/message_cache.h b/src/lib/cache/message_cache.h index 790ed83025ef21939ce28770baedefe3779d4175..7455f6680f3ee55dbfc32dfa62e866c2ab282019 100644 --- a/src/lib/cache/message_cache.h +++ b/src/lib/cache/message_cache.h @@ -20,7 +20,7 @@ #include #include "message_entry.h" #include -#include +#include #include "rrset_cache.h" namespace isc { @@ -92,7 +92,7 @@ protected: RRsetCachePtr rrset_cache_; RRsetCachePtr negative_soa_cache_; isc::nsas::HashTable message_table_; - isc::nsas::LruList message_lru_; + isc::util::LruList message_lru_; }; typedef boost::shared_ptr MessageCachePtr; diff --git a/src/lib/cache/rrset_cache.h b/src/lib/cache/rrset_cache.h index 104c2a542cb85d99c8e2c841480c3f76cc20b7a7..0e1b08f4bae222a7b169961b3a96e07cff1c1c9b 100644 --- a/src/lib/cache/rrset_cache.h +++ b/src/lib/cache/rrset_cache.h @@ -17,7 +17,8 @@ #include #include -#include + +#include using namespace isc::nsas; @@ -98,7 +99,7 @@ public: protected: uint16_t class_; // The class of the rrset cache. isc::nsas::HashTable rrset_table_; - isc::nsas::LruList rrset_lru_; + isc::util::LruList rrset_lru_; }; typedef boost::shared_ptr RRsetCachePtr; diff --git a/src/lib/cache/tests/Makefile.am b/src/lib/cache/tests/Makefile.am index 4763f55641ca87bedeb40530363e333f8f437f73..68a8425d0a96fbecf88f172a17cbefee706eb408 100644 --- a/src/lib/cache/tests/Makefile.am +++ b/src/lib/cache/tests/Makefile.am @@ -2,6 +2,7 @@ SUBDIRS = . AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG) +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cache -I$(top_builddir)/src/lib/cache AM_CPPFLAGS += -DTEST_DATA_SRCDIR=\"$(srcdir)/testdata\" @@ -54,6 +55,7 @@ endif run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la endif diff --git a/src/lib/cache/tests/cache_test_messagefromfile.h b/src/lib/cache/tests/cache_test_messagefromfile.h index 62e237c83bb4a30e63b5ba46c79676469da6346e..7d55f08c71dcb744417bb3af6a002f14ebe71ceb 100644 --- a/src/lib/cache/tests/cache_test_messagefromfile.h +++ b/src/lib/cache/tests/cache_test_messagefromfile.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include using namespace isc; @@ -31,7 +31,7 @@ messageFromFile(Message& message, const char* datafile) { std::vector data; UnitTestUtil::readWireData(datafile, data); - InputBuffer buffer(&data[0], data.size()); + isc::util::InputBuffer buffer(&data[0], data.size()); message.fromWire(buffer); } diff --git a/src/lib/cache/tests/cache_test_sectioncount.h b/src/lib/cache/tests/cache_test_sectioncount.h index 537ca81054be3f35b761ad7675e6f57d479cff71..df7cb5258dad0780eead5d7fba250f9d88a572bb 100644 --- a/src/lib/cache/tests/cache_test_sectioncount.h +++ b/src/lib/cache/tests/cache_test_sectioncount.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include using namespace isc; diff --git a/src/lib/cache/tests/message_cache_unittest.cc b/src/lib/cache/tests/message_cache_unittest.cc index fc62e2119263babbc1e07eea234b2ebba0d3276c..60ae0371a28caa81ba4fa64b2fb4b8e337a9179e 100644 --- a/src/lib/cache/tests/message_cache_unittest.cc +++ b/src/lib/cache/tests/message_cache_unittest.cc @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "../message_cache.h" #include "../rrset_cache.h" #include "../resolver_cache.h" @@ -25,6 +25,7 @@ using namespace isc::cache; using namespace isc; using namespace isc::dns; +using namespace isc::util; using namespace std; namespace { diff --git a/src/lib/cache/tests/message_entry_unittest.cc b/src/lib/cache/tests/message_entry_unittest.cc index 2ca33eca461401ede6a842c67fe60f498102f869..d9709ed298e519ebec0d007d9c37328e1d1fa086 100644 --- a/src/lib/cache/tests/message_entry_unittest.cc +++ b/src/lib/cache/tests/message_entry_unittest.cc @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "../message_entry.h" #include "../rrset_cache.h" #include "../resolver_cache.h" diff --git a/src/lib/datasrc/data_source.cc b/src/lib/datasrc/data_source.cc index c9819bb37a1cb7c867a8857683d5b188f2c72dc1..90e1dd71c70de4608642194a26f2b1d332026137 100644 --- a/src/lib/datasrc/data_source.cc +++ b/src/lib/datasrc/data_source.cc @@ -26,15 +26,16 @@ #include #include -#include -#include +#include +#include +#include + #include #include #include #include #include #include -#include #include @@ -45,6 +46,9 @@ } while (0) using namespace std; +using namespace isc::util; +using namespace isc::util::encode; +using namespace isc::util::hash; using namespace isc::dns; using namespace isc::dns::rdata; diff --git a/src/lib/datasrc/query.cc b/src/lib/datasrc/query.cc index d3de5c7e5de1ad036f65705a8c1aec7e9c2a2ee5..a8d675acc027f98777f2ef14338884a86aa0b942 100644 --- a/src/lib/datasrc/query.cc +++ b/src/lib/datasrc/query.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include diff --git a/src/lib/datasrc/tests/datasrc_unittest.cc b/src/lib/datasrc/tests/datasrc_unittest.cc index 810aef992227662fdf90ccbd0acde0397778b147..01de77abd41c0f3d62dd3f43d9757921f7d556df 100644 --- a/src/lib/datasrc/tests/datasrc_unittest.cc +++ b/src/lib/datasrc/tests/datasrc_unittest.cc @@ -20,7 +20,8 @@ #include -#include +#include + #include #include #include @@ -44,6 +45,7 @@ using isc::UnitTestUtil; using namespace std; +using namespace isc::util; using namespace isc::dns; using namespace isc::dns::rdata; using namespace isc::datasrc; diff --git a/src/lib/datasrc/tests/query_unittest.cc b/src/lib/datasrc/tests/query_unittest.cc index fa7216bb9f0bdf29eb995da644a9ad72c54de42d..7a20b86f3f6dd358fde13d87e6fb3406560236a5 100644 --- a/src/lib/datasrc/tests/query_unittest.cc +++ b/src/lib/datasrc/tests/query_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include #include diff --git a/src/lib/datasrc/tests/rbtree_unittest.cc b/src/lib/datasrc/tests/rbtree_unittest.cc index dd1b7fe04eacea7d04150d97f52e8373feadcd45..b26a22bc5fd7ad2e8565d846fde8c729903154a7 100644 --- a/src/lib/datasrc/tests/rbtree_unittest.cc +++ b/src/lib/datasrc/tests/rbtree_unittest.cc @@ -398,7 +398,7 @@ TEST_F(RBTreeTest, getLastComparedNode) { EXPECT_EQ(static_cast(NULL), chain.getLastComparedNode()); chain.clear(); - const RBNode* expected_node; + const RBNode* expected_node = NULL; // Exact match case. The returned node should be last compared. EXPECT_EQ(RBTree::EXACTMATCH, diff --git a/src/lib/datasrc/tests/test_datasrc.cc b/src/lib/datasrc/tests/test_datasrc.cc index c18f0bdc8eeb2218c658d0813d893ea7afc8343f..d78e7dba92dd1303cb18aad5ac6fcff2263bc147 100644 --- a/src/lib/datasrc/tests/test_datasrc.cc +++ b/src/lib/datasrc/tests/test_datasrc.cc @@ -23,7 +23,7 @@ #include -#include +#include #include #include #include diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am index c5c5cd15fb634dd0e0b1db9ff2c745aebd2697fc..5a7151ed0eb1e742246088ad100cd6378d81f303 100644 --- a/src/lib/dns/Makefile.am +++ b/src/lib/dns/Makefile.am @@ -1,6 +1,8 @@ -SUBDIRS = . tests python +SUBDIRS = . tests python benchmarks AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util AM_CPPFLAGS += $(BOOST_INCLUDES) AM_CXXFLAGS = $(B10_CXXFLAGS) @@ -60,15 +62,9 @@ BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc lib_LTLIBRARIES = libdns++.la -libdns___la_SOURCES = util/base32hex.h util/base64.h util/base_n.cc -libdns___la_SOURCES += util/base32hex_from_binary.h -libdns___la_SOURCES += util/binary_from_base32hex.h -libdns___la_SOURCES += util/base16_from_binary.h util/binary_from_base16.h -libdns___la_SOURCES += buffer.h -libdns___la_SOURCES += dnssectime.h dnssectime.cc +libdns___la_SOURCES = libdns___la_SOURCES += edns.h edns.cc libdns___la_SOURCES += exceptions.h exceptions.cc -libdns___la_SOURCES += util/hex.h libdns___la_SOURCES += masterload.h masterload.cc libdns___la_SOURCES += message.h message.cc libdns___la_SOURCES += messagerenderer.h messagerenderer.cc @@ -76,6 +72,7 @@ libdns___la_SOURCES += name.h name.cc libdns___la_SOURCES += opcode.h opcode.cc libdns___la_SOURCES += rcode.h rcode.cc libdns___la_SOURCES += rdata.h rdata.cc +libdns___la_SOURCES += rdatafields.h rdatafields.cc libdns___la_SOURCES += rrclass.cc libdns___la_SOURCES += rrparamregistry.h libdns___la_SOURCES += rrset.h rrset.cc @@ -83,11 +80,13 @@ libdns___la_SOURCES += rrsetlist.h rrsetlist.cc libdns___la_SOURCES += rrttl.h rrttl.cc libdns___la_SOURCES += rrtype.cc libdns___la_SOURCES += question.h question.cc -libdns___la_SOURCES += util/sha1.h util/sha1.cc libdns___la_SOURCES += tsigkey.h tsigkey.cc libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.cc +libdns___la_CPPFLAGS = $(AM_CPPFLAGS) +libdns___la_LIBADD = $(top_builddir)/src/lib/util/libutil.la + nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h nodist_libdns___la_SOURCES += rrparamregistry.cc @@ -99,8 +98,6 @@ rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile libdns___includedir = $(includedir)/dns libdns___include_HEADERS = \ - buffer.h \ - dnssectime.h \ edns.h \ exceptions.h \ message.h \ diff --git a/src/lib/dns/benchmarks/Makefile.am b/src/lib/dns/benchmarks/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..864538518efb9d8db960eb05b122b62310e7e0be --- /dev/null +++ b/src/lib/dns/benchmarks/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) + +AM_CXXFLAGS = $(B10_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +CLEANFILES = *.gcno *.gcda + +noinst_PROGRAMS = rdatarender_bench +rdatarender_bench_SOURCES = rdatarender_bench.cc + +rdatarender_bench_LDADD = $(top_builddir)/src/lib/dns/libdns++.la +rdatarender_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la +rdatarender_bench_LDADD += $(SQLITE_LIBS) diff --git a/src/lib/dns/benchmarks/README b/src/lib/dns/benchmarks/README new file mode 100644 index 0000000000000000000000000000000000000000..7119c1374468cf82e39f7926a386cad1f0827e03 --- /dev/null +++ b/src/lib/dns/benchmarks/README @@ -0,0 +1,10 @@ +- rdatarender_bench + + This is a benchmark for RDATA rendering performance comparing the basic + Rdata objects and RdataField objects. It takes a command line argument + that specifies an input data file. Each line of the data file should + specify a single RDATA with its RR class and type, e.g. + IN A 192.0.2.1 + IN NS ns.example.com. + Lines beginning with '#' and empty lines will be ignored. Sample input + files can be found in benchmarkdata/rdatarender_*. diff --git a/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_com b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_com new file mode 100644 index 0000000000000000000000000000000000000000..12155a65fe423fe429892e09b8cc80f55e1bc94d --- /dev/null +++ b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_com @@ -0,0 +1,32 @@ +# This is sample input data for rdatarender_bench. +# These are RDATA in the authority and additional sections in a response from +# a root server for a query domain under COM. + +IN NS g.gtld-servers.net. +IN NS a.gtld-servers.net. +IN NS k.gtld-servers.net. +IN NS c.gtld-servers.net. +IN NS d.gtld-servers.net. +IN NS m.gtld-servers.net. +IN NS h.gtld-servers.net. +IN NS b.gtld-servers.net. +IN NS j.gtld-servers.net. +IN NS l.gtld-servers.net. +IN NS e.gtld-servers.net. +IN NS f.gtld-servers.net. +IN NS i.gtld-servers.net. +IN A 192.5.6.30 +IN A 192.33.14.30 +IN A 192.26.92.30 +IN A 192.31.80.30 +IN A 192.12.94.30 +IN A 192.35.51.30 +IN A 192.42.93.30 +IN A 192.54.112.30 +IN A 192.43.172.30 +IN A 192.48.79.30 +IN A 192.52.178.30 +IN A 192.41.162.30 +IN A 192.55.83.30 +IN AAAA 2001:503:a83e::2:30 +IN AAAA 2001:503:231d::2:30 diff --git a/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_nxdomain b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_nxdomain new file mode 100644 index 0000000000000000000000000000000000000000..eb14b5f9634e5fb86afdc8aa0929c9909b89a6fc --- /dev/null +++ b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_nxdomain @@ -0,0 +1,10 @@ +# This is sample input data for rdatarender_bench. +# These are RDATA in the authority section in a response from +# a root server for a non existent query domain (with DNSSEC). + +IN SOA a.root-servers.net. nstld.verisign-grs.com. 2010110301 1800 900 604800 86400 +IN RRSIG SOA 8 0 86400 20101110000000 20101102230000 40288 . WtvYyX2nIsaqjWqkIG1WHFE5PnJ6eno0KqF6azU/MFJ/t1JpKWQ1P4rA 61rnoq0p252fg7wT4XzEz9UDxmpB5pvF2VApe2w9LvSWxsWIIOg8ue5u e9NAAYdzjd0rsYObQQ6msf7WchyAUbnmrqKvf8/CK6+s1xFihXp5DpYL 6K0= +IN NSEC ac. NS SOA RRSIG NSEC DNSKEY +IN RRSIG NSEC 8 0 86400 20101110000000 20101102230000 40288 . rWfgg4YUDFAjhiUOT+niJy/qbaIbydqoXg5oB/5j//ZjNFy4hqU8DvdM xJr9UybQpEvu7pvmKQ0jRYO98Fw/UTlY5KiKbhVBJ1t8AE93cbU+s5gX d3Q6+wRcFX5MjZyIe+f30llKrYOZHjRyEFALCkLt4XEmr0xsua+ztAFY 65k= +IN NSEC np. NS RRSIG NSEC +IN RRSIG NSEC 8 1 86400 20101110000000 20101102230000 40288 . G32LGynsGA2fyDnesyeCtBCoM3ERMgGS4touDUuoBYW1NrZub76kz5fc z93p8VZfoYWAW7LuC8vJ1jl2sUgBNns4zN4RsfFeopcYjjFnGbGuoZnO NmTU+NKO53Ub7uIcCSeqV+COAaL8XqDfyk1FmVdQvtrBaOW/PWpRahVq 7E8= diff --git a/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_org b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_org new file mode 100644 index 0000000000000000000000000000000000000000..17b80d2e13dbf4915f95ed12de4b2dbb7a22cb86 --- /dev/null +++ b/src/lib/dns/benchmarks/benchmarkdata/rdatarender_data_org @@ -0,0 +1,22 @@ +# This is sample input data for rdatarender_bench. +# These are RDATA in the authority and additional sections in a response from +# a root server for a query domain under ORG. + +IN NS b0.org.afilias-nst.org. +IN NS a2.org.afilias-nst.info. +IN NS a0.org.afilias-nst.info. +IN NS c0.org.afilias-nst.info. +IN NS d0.org.afilias-nst.org. +IN NS b2.org.afilias-nst.org. +IN A 199.19.56.1 +IN A 199.249.112.1 +IN A 199.19.54.1 +IN A 199.249.120.1 +IN A 199.19.53.1 +IN A 199.19.57.1 +IN AAAA 2001:500:e::1 +IN AAAA 2001:500:40::1 +IN AAAA 2001:500:c::1 +IN AAAA 2001:500:48::1 +IN AAAA 2001:500:b::1 +IN AAAA 2001:500:f::1 diff --git a/src/lib/dns/benchmarks/rdatarender_bench.cc b/src/lib/dns/benchmarks/rdatarender_bench.cc new file mode 100644 index 0000000000000000000000000000000000000000..d1fb0f27b799ae1862fd47469fa5c031ce82fa37 --- /dev/null +++ b/src/lib/dns/benchmarks/rdatarender_bench.cc @@ -0,0 +1,188 @@ +// 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. + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace isc::bench; +using namespace isc::dns; +using namespace isc::dns::rdata; +using isc::util::OutputBuffer; + +namespace { +// This templated benchmark class is constructed with a vector of Rdata-like +// (pointer) objects which should have a "toWire()" method. In its run(), +// it calls toWire() for each element of the vector. +template +class RdataRenderBenchMark { +public: + RdataRenderBenchMark(const vector& dataset) : + dataset_(dataset), buffer_(4096), renderer_(buffer_) + {} + unsigned int run() { + typename vector::const_iterator data; + typename vector::const_iterator data_end = dataset_.end(); + for (data = dataset_.begin(); data != data_end; ++data) { + renderer_.clear(); + (*data)->toWire(renderer_); + } + return (dataset_.size()); + } +private: + const vector& dataset_; + OutputBuffer buffer_; + MessageRenderer renderer_; +}; + +// This supplemental class emulates an RRset like class that internally +// uses RdataFields. On construction it stores RDATA information in the +// form of RdataFields fields. Its toWire() method restores the data as +// an RdataFields object for the rendering. +class RdataFieldsStore { +public: + RdataFieldsStore(ConstRdataPtr rdata) { + const RdataFields fields(*rdata); + + spec_size_ = fields.getFieldSpecDataSize(); + spec_store_.resize(spec_size_); + void* cp_spec = &spec_store_[0]; + memcpy(cp_spec, fields.getFieldSpecData(), spec_store_.size()); + spec_ptr_ = cp_spec; + + data_length_ = fields.getDataLength(); + data_store_.resize(data_length_); + void* cp_data = &data_store_[0]; + memcpy(cp_data, fields.getData(), data_store_.size()); + // Vector guarantees that the elements are stored in continuous array + // in memory, so this is actually correct by the standard + data_ptr_ = cp_data; + } + void toWire(MessageRenderer& renderer) const { + RdataFields(spec_ptr_, spec_size_, + data_ptr_, data_length_).toWire(renderer); + } +private: + vector spec_store_; + vector data_store_; + const void* spec_ptr_; + const void* data_ptr_; + unsigned int spec_size_; + size_t data_length_; +}; + +// We wouldn't necessarily have to use a shared pointer, but it's easier +// to use pointer-like values to adjust them with the RdataRenderBenchMark +// template. +typedef boost::shared_ptr ConstRdataFieldsStorePtr; + +void +readInputFile(const char* const input_file, vector& rdata_sets, + vector& fields_sets) +{ + ifstream ifs; + ifs.open(input_file, ios_base::in); + if ((ifs.rdstate() & istream::failbit) != 0) { + cerr << "Failed to read input file: " << input_file << endl; + exit (1); + } + string line; + unsigned int linenum = 0; + while (getline(ifs, line), !ifs.eof()) { + ++linenum; + if (ifs.bad() || ifs.fail()) { + cerr << "Unexpected input at line " << linenum << endl; + exit (1); + } + if (line.empty() || line[0] == '#') { + continue; // skip comment and blank lines + } + istringstream iss(line); + string rrclass_string, rrtype_string; + stringbuf rdatabuf; + iss >> rrclass_string >> rrtype_string >> &rdatabuf; + if (iss.bad() || iss.fail()) { + cerr << "Unexpected input at line " << linenum << endl; + exit (1); + } + ConstRdataPtr rdata = createRdata(RRType(rrtype_string), + RRClass(rrclass_string), + rdatabuf.str()); + rdata_sets.push_back(rdata); + fields_sets.push_back(ConstRdataFieldsStorePtr( + new RdataFieldsStore(rdata))); + } + ifs.close(); +} + +void +usage() { + cerr << "Usage: rdatafields_bench [-n iterations] input_file" << endl; + exit (1); +} +} + +int +main(int argc, char* argv[]) { + int ch; + int iteration = 10000; + while ((ch = getopt(argc, argv, "n:")) != -1) { + switch (ch) { + case 'n': + iteration = atoi(optarg); + break; + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc < 1) { + usage(); + } + const char* const input_file = argv[0]; + + vector rdata_sets; + vector fields_sets; + + readInputFile(input_file, rdata_sets, fields_sets); + + cout << "Parameters:" << endl; + cout << " Iterations: " << iteration << endl; + cout << " Input File: " << input_file << endl; + + typedef RdataRenderBenchMark RdataBenchMark; + cout << "Benchmark for rendering with standard Rdata" << endl; + BenchMark(iteration, RdataBenchMark(rdata_sets)); + + typedef RdataRenderBenchMark FieldsBenchMark; + cout << "Benchmark for rendering with RdataFields" << endl; + BenchMark(iteration, FieldsBenchMark(fields_sets)); + + return (0); +} diff --git a/src/lib/dns/edns.cc b/src/lib/dns/edns.cc index 6e25624cb910ff46067e9c2f627a519129b11382..5405dab5151c2801d642d2a76c01c07b2560af33 100644 --- a/src/lib/dns/edns.cc +++ b/src/lib/dns/edns.cc @@ -36,6 +36,7 @@ using namespace std; using namespace boost; using namespace isc::dns::rdata; +using namespace isc::util; namespace isc { namespace dns { @@ -143,8 +144,8 @@ EDNS::toWire(MessageRenderer& renderer, const uint8_t extended_rcode) const { } unsigned int -EDNS::toWire(OutputBuffer& buffer, const uint8_t extended_rcode) const { - return (toWire(buffer, extended_rcode)); +EDNS::toWire(isc::util::OutputBuffer& buffer, const uint8_t extended_rcode) const { + return (toWire(buffer, extended_rcode)); } EDNS* diff --git a/src/lib/dns/edns.h b/src/lib/dns/edns.h index ca3db4737a38e9641435f52328823529f8a42acd..b794183ad1f0f7e7ab45206a653ce8beaeb2c32d 100644 --- a/src/lib/dns/edns.h +++ b/src/lib/dns/edns.h @@ -24,6 +24,10 @@ #include namespace isc { +namespace util { +class OutputBuffer; +} + namespace dns { class EDNS; @@ -319,7 +323,7 @@ public: /// except it renders the OPT RR in an \c OutputBuffer and therefore /// does not care about message size limit. /// As a consequence it always returns 1. - unsigned int toWire(OutputBuffer& buffer, + unsigned int toWire(isc::util::OutputBuffer& buffer, const uint8_t extended_rcode) const; /// \brief Convert the EDNS to a string. diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in index 04e5c6a92b67ef43a8d80155c96492c6e88d99f0..b3c8da23ab67b5a9baa5a850fa633d77f78498db 100755 --- a/src/lib/dns/gen-rdatacode.py.in +++ b/src/lib/dns/gen-rdatacode.py.in @@ -86,6 +86,11 @@ def import_classheader(class_txt, type_txt, type_code, file): continue if re.match('// BEGIN_ISC_NAMESPACE', line): content += 'namespace isc {\n' + content += 'namespace util {\n' + content += ''' +class InputBuffer; +class OutputBuffer;\n''' + content += '}\n\n' content += 'namespace dns {\n' continue if re.match('// BEGIN_RDATA_NAMESPACE', line): @@ -105,17 +110,15 @@ def import_classheader(class_txt, type_txt, type_code, file): content += line if re.match('// BEGIN_COMMON_DECLARATIONS', line): content += ''' -class InputBuffer; -class OutputBuffer; -class MessageRenderer;\n\n''' +class AbstractMessageRenderer;\n\n''' if re.match('\s+// BEGIN_COMMON_MEMBERS$', line): content += ''' explicit ''' + type_utxt + '''(const std::string& type_str); - ''' + type_utxt + '''(InputBuffer& buffer, size_t rdata_len); + ''' + type_utxt + '''(isc::util::InputBuffer& buffer, size_t rdata_len); ''' + type_utxt + '''(const ''' + type_utxt + '''& other); virtual std::string toText() const; - virtual void toWire(OutputBuffer& buffer) const; - virtual void toWire(MessageRenderer& renderer) const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; virtual int compare(const Rdata& other) const;\n\n''' rdata_header.close() return content diff --git a/src/lib/dns/message.cc b/src/lib/dns/message.cc index 9eae6052dd029af1f4afb5291489e365bb5cd6b0..d1025d10babbc9bc56855b2c2c20d0408e175d89 100644 --- a/src/lib/dns/message.cc +++ b/src/lib/dns/message.cc @@ -25,7 +25,8 @@ #include -#include +#include + #include #include #include @@ -43,6 +44,7 @@ using namespace std; using namespace boost; using namespace isc::dns::rdata; +using namespace isc::util; namespace isc { namespace dns { diff --git a/src/lib/dns/message.h b/src/lib/dns/message.h index 0bbb9ea673da5d54845670d1639f9d802774f446..560129924f5f2ce1d8a1befd30674f68a6d6ac16 100644 --- a/src/lib/dns/message.h +++ b/src/lib/dns/message.h @@ -28,6 +28,10 @@ #include namespace isc { +namespace util { +class InputBuffer; +} + namespace dns { /// @@ -76,7 +80,6 @@ public: typedef uint16_t qid_t; -class InputBuffer; class MessageRenderer; class Message; class MessageImpl; @@ -529,10 +532,10 @@ public: void toWire(MessageRenderer& renderer); /// \brief Parse the header section of the \c Message. - void parseHeader(InputBuffer& buffer); + void parseHeader(isc::util::InputBuffer& buffer); /// \brief Parse the \c Message. - void fromWire(InputBuffer& buffer); + void fromWire(isc::util::InputBuffer& buffer); /// /// \name Protocol constants diff --git a/src/lib/dns/messagerenderer.cc b/src/lib/dns/messagerenderer.cc index 212411a4894ba9c42dd39ff15ae991ca8e6cddac..6438fb0d32ea458caa6d20b59d229307c0040b25 100644 --- a/src/lib/dns/messagerenderer.cc +++ b/src/lib/dns/messagerenderer.cc @@ -16,10 +16,12 @@ #include #include -#include +#include #include #include +using namespace isc::util; + namespace isc { namespace dns { @@ -150,12 +152,10 @@ struct MessageRenderer::MessageRendererImpl { /// /// \param buffer An \c OutputBuffer object to which wire format data is /// written. - MessageRendererImpl(OutputBuffer& buffer) : - buffer_(buffer), nbuffer_(Name::MAX_WIRE), msglength_limit_(512), + MessageRendererImpl() : + nbuffer_(Name::MAX_WIRE), msglength_limit_(512), truncated_(false), compress_mode_(MessageRenderer::CASE_INSENSITIVE) {} - /// The buffer that holds the entire DNS message. - OutputBuffer& buffer_; /// A local working buffer to convert each given name into wire format. /// This could be a local variable of the \c writeName() method, but /// we keep it in the class so that we can reuse it and avoid construction @@ -174,26 +174,17 @@ struct MessageRenderer::MessageRendererImpl { }; MessageRenderer::MessageRenderer(OutputBuffer& buffer) : - impl_(new MessageRendererImpl(buffer)) + AbstractMessageRenderer(buffer), + impl_(new MessageRendererImpl) {} MessageRenderer::~MessageRenderer() { delete impl_; } -void -MessageRenderer::skip(const size_t len) { - impl_->buffer_.skip(len); -} - -void -MessageRenderer::trim(const size_t len) { - impl_->buffer_.trim(len); -} - void MessageRenderer::clear() { - impl_->buffer_.clear(); + AbstractMessageRenderer::clear(); impl_->nbuffer_.clear(); impl_->nodeset_.clear(); impl_->msglength_limit_ = 512; @@ -201,41 +192,6 @@ MessageRenderer::clear() { impl_->compress_mode_ = CASE_INSENSITIVE; } -void -MessageRenderer::writeUint8(const uint8_t data) { - impl_->buffer_.writeUint8(data); -} - -void -MessageRenderer::writeUint16(const uint16_t data) { - impl_->buffer_.writeUint16(data); -} - -void -MessageRenderer::writeUint16At(const uint16_t data, const size_t pos) { - impl_->buffer_.writeUint16At(data, pos); -} - -void -MessageRenderer::writeUint32(const uint32_t data) { - impl_->buffer_.writeUint32(data); -} - -void -MessageRenderer::writeData(const void* const data, const size_t len) { - impl_->buffer_.writeData(data, len); -} - -const void* -MessageRenderer::getData() const { - return (impl_->buffer_.getData()); -} - -size_t -MessageRenderer::getLength() const { - return (impl_->buffer_.getLength()); -} - size_t MessageRenderer::getLengthLimit() const { return (impl_->msglength_limit_); @@ -291,15 +247,15 @@ MessageRenderer::writeName(const Name& name, const bool compress) { } // Record the current offset before extending the buffer. - const size_t offset = impl_->buffer_.getLength(); + const size_t offset = getLength(); // Write uncompress part... - impl_->buffer_.writeData(impl_->nbuffer_.getData(), - compress ? i : impl_->nbuffer_.getLength()); + writeData(impl_->nbuffer_.getData(), + compress ? i : impl_->nbuffer_.getLength()); if (compress && n != notfound) { // ...and compression pointer if available. uint16_t pointer = (*n).pos_; pointer |= Name::COMPRESS_POINTER_MARK16; - impl_->buffer_.writeUint16(pointer); + writeUint16(pointer); } // Finally, add to the set the newly rendered name and its ancestors that @@ -311,11 +267,17 @@ MessageRenderer::writeName(const Name& name, const bool compress) { if (offset + j > Name::MAX_COMPRESS_POINTER) { break; } - impl_->nodeset_.insert(NameCompressNode(*this, impl_->buffer_, + impl_->nodeset_.insert(NameCompressNode(*this, getBuffer(), offset + j, impl_->nbuffer_.getLength() - j)); } } + +void +AbstractMessageRenderer::clear() { + buffer_.clear(); +} + } } diff --git a/src/lib/dns/messagerenderer.h b/src/lib/dns/messagerenderer.h index 9a7f149b0ace07557477ca6ef6b2299d4a6c9eb9..52d9245211e577224178af0ea42ea49ce099c445 100644 --- a/src/lib/dns/messagerenderer.h +++ b/src/lib/dns/messagerenderer.h @@ -15,64 +15,64 @@ #ifndef __MESSAGERENDERER_H #define __MESSAGERENDERER_H 1 +#include + namespace isc { + namespace dns { // forward declarations -class OutputBuffer; class Name; +/// \brief The \c AbstractMessageRenderer class is an abstract base class +/// that provides common interfaces for rendering a DNS message into a buffer +/// in wire format. /// -/// \brief The \c MessageRenderer class encapsulates implementation details -/// of rendering a DNS message into a buffer in wire format. +/// A specific derived class of \c AbstractMessageRenderer (we call it +/// a renderer class hereafter) is simply responsible for name compression at +/// least in the current design. A renderer class object (conceptually) +/// manages the positions of names rendered in some sort of buffer and uses +/// that information to render subsequent names with compression. /// -/// In effect, it's simply responsible for name compression at least in the -/// current implementation. A \c MessageRenderer class object manages the -/// positions of names rendered in a buffer and uses that information to render -/// subsequent names with compression. -/// -/// This class is mainly intended to be used as a helper for a more +/// A renderer class is mainly intended to be used as a helper for a more /// comprehensive \c Message class internally; normal applications won't have -/// to care about this class. -/// -/// A \c MessageRenderer class object is constructed with a \c OutputBuffer -/// object, which is the buffer into which the rendered %data will be written. -/// Normally the buffer is expected to be empty on construction, but it doesn't -/// have to be so; the \c MessageRenderer object will start rendering from the -/// end of the buffer at the time of construction. However, if the -/// pre-existing portion of the buffer contains DNS names, these names won't -/// be considered for name compression. +/// to care about details of this class. /// -/// Once a \c MessageRenderer object is constructed with a buffer, it is -/// generally expected that all rendering operations are performed via the -/// \c MessageRenderer object. If the application modifies the buffer in -/// parallel with the \c MessageRenderer, the result will be undefined. +/// Once a renderer class object is constructed with a buffer, it is +/// generally expected that all rendering operations are performed via that +/// object. If the application modifies the buffer in +/// parallel with the renderer, the result will be undefined. /// /// Note to developers: we introduced a separate class for name compression /// because previous benchmark with BIND9 showed compression affects overall /// response performance very much. By having a separate class dedicated for /// this purpose, we'll be able to change the internal implementation of name /// compression in the future without affecting other part of the API and -/// implementation. For the same reason, we adopt the "pimpl" idiom in the -/// class definition (i.e., using a pointer to a \c MessageRendererImpl class, -/// which is defined with the class implementation, not in the header file): -/// we may want to modify the compression implementation without modifying the -/// header file thereby requesting rebuild the package. +/// implementation. /// -/// Furthermore, we may eventually want to allow other developers to develop -/// and use their own compression implementation. Should such a case become -/// realistic, we may want to make the \c MessageRendererImpl class an abstract -/// base class and let concrete derived classes have their own implementations. -/// At the moment we don't the strong need for it, so we rather avoid over -/// abstraction and keep the definition simpler. -class MessageRenderer { +/// In addition, by introducing a class hierarchy from +/// \c AbstractMessageRenderer, we allow an application to use a customized +/// renderer class for specific purposes. For example, a high performance +/// DNS server may want to use an optimized renderer class assuming some +/// specific underlying data representation. +/// +/// \note Some functions (like writeUint8) are not virtual. It is because +/// it is hard to imagine any version of message renderer that would +/// do anything else than just putting the data into a buffer, so we +/// provide a default implementation and having them virtual would only +/// hurt the performance with no real gain. If it would happen a different +/// implementation is really needed, we can make them virtual in future. +/// The only one that is virtual is writeName and it's because this +/// function is much more complicated, therefore there's a lot of space +/// for different implementations or behaviours. +class AbstractMessageRenderer { public: /// \brief Compression mode constants. /// /// The \c CompressMode enum type represents the name compression mode - /// for the \c MessageRenderer. + /// for renderer classes. /// \c CASE_INSENSITIVE means compress names in case-insensitive manner; /// \c CASE_SENSITIVE means compress names in case-sensitive manner. - /// By default, \c MessageRenderer compresses names in case-insensitive + /// By default, a renderer compresses names in case-insensitive /// manner. /// Compression mode can be dynamically modified by the /// \c setCompressMode() method. @@ -80,7 +80,7 @@ public: /// is not an intended usage. In this case the names already compressed /// are intact; only names being compressed after the mode change are /// affected by the change. - /// If the internal \c MessageRenderer is reinitialized by the \c clear() + /// If a renderer class object is reinitialized by the \c clear() /// method, the compression mode will be reset to the default, which is /// \c CASE_INSENSITIVE /// @@ -93,25 +93,39 @@ public: CASE_INSENSITIVE, //!< Compress names case-insensitive manner (default) CASE_SENSITIVE //!< Compress names case-sensitive manner }; -public: +protected: /// /// \name Constructors and Destructor //@{ - /// \brief Constructor from an output buffer. - /// - /// \param buffer An \c OutputBuffer object to which wire format data is - /// written. - MessageRenderer(OutputBuffer& buffer); + /// \brief 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). + /// \param buffer The buffer where the data should be rendered into. + /// \todo We might want to revisit this API at some point and remove the + /// buffer parameter. In that case it would create it's own buffer and + /// a function to extract the data would be available instead. It seems + /// like a cleaner design, but it's left undone until we would actually + /// benefit from the change. + AbstractMessageRenderer(isc::util::OutputBuffer& buffer) : + buffer_(buffer) + {} +public: /// \brief The destructor. - /// - /// The destructor does nothing on the given \c buffer on construction; - /// in fact, it is expected that the user will use the resulting buffer - /// for some post rendering purposes (e.g., send the data to the network). - /// It's the user's responsibility to do any necessary cleanup for the - /// \c buffer. - ~MessageRenderer(); + virtual ~AbstractMessageRenderer() {} //@} - +protected: + /// \brief Return the output buffer we render into. + const isc::util::OutputBuffer& getBuffer() const { return (buffer_); } + isc::util::OutputBuffer& getBuffer() { return (buffer_); } +private: + /// \short Buffer to store data + /// + /// It was decided that there's no need to have this in every subclass, + /// at least not now, and this reduces code size and gives compiler a better + /// chance to optimise. + isc::util::OutputBuffer& buffer_; +public: /// /// \name Getter Methods /// @@ -121,9 +135,15 @@ public: /// /// This method works exactly same as the same method of the \c OutputBuffer /// class; all notes for \c OutputBuffer apply. - const void* getData() const; + const void* getData() const { + return (buffer_.getData()); + } + /// \brief Return the length of data written in the internal buffer. - size_t getLength() const; + size_t getLength() const { + return (buffer_.getLength()); + } + /// \brief Return whether truncation has occurred while rendering. /// /// Once the return value of this method is \c true, it doesn't make sense @@ -133,20 +153,22 @@ public: /// This method never throws an exception. /// /// \return true if truncation has occurred; otherwise \c false. - bool isTruncated() const; + virtual bool isTruncated() const = 0; + /// \brief Return the maximum length of rendered data that can fit in the /// corresponding DNS message without truncation. /// /// This method never throws an exception. /// /// \return The maximum length in bytes. - size_t getLengthLimit() const; - /// \brief Return the compression mode of the \c MessageRenderer. + virtual size_t getLengthLimit() const = 0; + + /// \brief Return the compression mode of the renderer class object. /// /// This method never throws an exception. /// /// \return The current compression mode. - CompressMode getCompressMode() const; + virtual CompressMode getCompressMode() const = 0; //@} /// @@ -157,20 +179,22 @@ public: /// rendering. /// /// This method never throws an exception. - void setTruncated(); + virtual void setTruncated() = 0; + /// \brief Set the maximum length of rendered data that can fit in the /// corresponding DNS message without truncation. /// /// This method never throws an exception. /// /// \param len The maximum length in bytes. - void setLengthLimit(size_t len); - /// \brief Set the compression mode of the \c MessageRenderer. + virtual void setLengthLimit(size_t len) = 0; + + /// \brief Set the compression mode of the renderer class object. /// /// This method never throws an exception. /// /// \param mode A \c CompressMode value representing the compression mode. - void setCompressMode(CompressMode mode); + virtual void setCompressMode(CompressMode mode) = 0; //@} /// @@ -184,7 +208,10 @@ public: /// that is to be filled in later, e.g, by \ref writeUint16At(). /// /// \param len The length of the gap to be inserted in bytes. - void skip(size_t len); + void skip(size_t len) { + buffer_.skip(len); + } + /// \brief Trim the specified length of data from the end of the internal /// buffer. /// @@ -195,21 +222,31 @@ public: /// be thrown. /// /// \param len The length of data that should be trimmed. - void trim(size_t len); + void trim(size_t len) { + buffer_.trim(len); + } + /// \brief Clear the internal buffer and other internal resources. /// /// This method can be used to re-initialize and reuse the renderer /// without constructing a new one. - void clear(); + virtual void clear(); + /// \brief Write an unsigned 8-bit integer into the internal buffer. /// /// \param data The 8-bit integer to be written into the internal buffer. - void writeUint8(uint8_t data); + void writeUint8(const uint8_t data) { + buffer_.writeUint8(data); + } + /// \brief Write an unsigned 16-bit integer in host byte order into the /// internal buffer in network byte order. /// /// \param data The 16-bit integer to be written into the buffer. - void writeUint16(uint16_t data); + void writeUint16(uint16_t data) { + buffer_.writeUint16(data); + } + /// \brief Write an unsigned 16-bit integer in host byte order at the /// specified position of the internal buffer in network byte order. /// @@ -221,26 +258,29 @@ public: /// /// \param data The 16-bit integer to be written into the internal buffer. /// \param pos The beginning position in the buffer to write the data. - void writeUint16At(uint16_t data, size_t pos); + void writeUint16At(uint16_t data, size_t pos) { + buffer_.writeUint16At(data, pos); + } + /// \brief Write an unsigned 32-bit integer in host byte order into the /// internal buffer in network byte order. /// /// \param data The 32-bit integer to be written into the buffer. - void writeUint32(uint32_t data); + void writeUint32(uint32_t data) { + buffer_.writeUint32(data); + } + /// \brief Copy an arbitrary length of data into the internal buffer - /// of the \c MessageRenderer. + /// of the renderer object. /// /// No conversion on the copied data is performed. /// /// \param data A pointer to the data to be copied into the internal buffer. /// \param len The length of the data in bytes. - void writeData(const void *data, size_t len); - //@} + void writeData(const void *data, size_t len) { + buffer_.writeData(data, len); + } - /// - /// \name Rendering Methods - /// - //@{ /// \brief Write a \c Name object into the internal buffer in wire format, /// with or without name compression. /// @@ -255,8 +295,41 @@ public: /// /// \param name A \c Name object to be written. /// \param compress A boolean indicating whether to enable name compression. - void writeName(const Name& name, bool compress = true); + virtual void writeName(const Name& name, bool compress = true) = 0; //@} +}; + +/// The \c MessageRenderer is a concrete derived class of +/// \c AbstractMessageRenderer as a general purpose implementation of the +/// renderer interfaces. +/// +/// A \c MessageRenderer object is constructed with a \c OutputBuffer +/// object, which is the buffer into which the rendered %data will be written. +/// Normally the buffer is expected to be empty on construction, but it doesn't +/// have to be so; the renderer object will start rendering from the +/// end of the buffer at the time of construction. However, if the +/// pre-existing portion of the buffer contains DNS names, these names won't +/// be considered for name compression. +class MessageRenderer : public AbstractMessageRenderer { +public: + using AbstractMessageRenderer::CASE_INSENSITIVE; + using AbstractMessageRenderer::CASE_SENSITIVE; + + /// \brief Constructor from an output buffer. + /// + /// \param buffer An \c OutputBuffer object to which wire format data is + /// written. + MessageRenderer(isc::util::OutputBuffer& buffer); + + virtual ~MessageRenderer(); + virtual bool isTruncated() const; + virtual size_t getLengthLimit() const; + virtual CompressMode getCompressMode() const; + virtual void setTruncated(); + virtual void setLengthLimit(size_t len); + virtual void setCompressMode(CompressMode mode); + virtual void clear(); + virtual void writeName(const Name& name, bool compress = true); private: struct MessageRendererImpl; MessageRendererImpl* impl_; diff --git a/src/lib/dns/name.cc b/src/lib/dns/name.cc index 8786bcf8b90497b734bf2d6c72859860a4e4fb08..4cd0b2bc22909259d4059623709721c5639f8cae 100644 --- a/src/lib/dns/name.cc +++ b/src/lib/dns/name.cc @@ -20,14 +20,14 @@ #include #include -#include +#include #include #include #include using namespace std; +using namespace isc::util; using isc::dns::NameComparisonResult; -using isc::dns::MessageRenderer; namespace isc { namespace dns { @@ -403,7 +403,7 @@ Name::toWire(OutputBuffer& buffer) const { } void -Name::toWire(MessageRenderer& renderer) const { +Name::toWire(AbstractMessageRenderer& renderer) const { renderer.writeName(*this); } diff --git a/src/lib/dns/name.h b/src/lib/dns/name.h index dc1b5b30af70a93ab4d183a9d42bb8ac174479d9..4ff7fe505378aca285012d0477d4d56904c6e665 100644 --- a/src/lib/dns/name.h +++ b/src/lib/dns/name.h @@ -23,10 +23,13 @@ #include namespace isc { -namespace dns { +namespace util { class InputBuffer; class OutputBuffer; -class MessageRenderer; +} + +namespace dns { +class AbstractMessageRenderer; /// /// \brief A standard DNS module exception that is thrown if the name parser @@ -247,7 +250,7 @@ public: /// /// \param buffer A buffer storing the wire format %data. /// \param downcase Whether to convert upper case alphabets to lower case. - explicit Name(InputBuffer& buffer, bool downcase = false); + explicit Name(isc::util::InputBuffer& buffer, bool downcase = false); /// /// We use the default copy constructor intentionally. //@} @@ -347,7 +350,7 @@ public: /// /// \param renderer DNS message rendering context that encapsulates the /// output buffer and name compression information. - void toWire(MessageRenderer& renderer) const; + void toWire(AbstractMessageRenderer& renderer) const; /// \brief Render the Name in the wire format without /// compression. @@ -359,7 +362,7 @@ public: /// then this method should not throw an exception. /// /// \param buffer An output buffer to store the wire %data. - void toWire(OutputBuffer& buffer) const; + void toWire(isc::util::OutputBuffer& buffer) const; //@} /// diff --git a/src/lib/dns/python/edns_python.cc b/src/lib/dns/python/edns_python.cc index 82db8d80bbf9037c480d3cb26bdd3156e5b0ef14..d781e894dec615f08059081973c3cac2c9912ab9 100644 --- a/src/lib/dns/python/edns_python.cc +++ b/src/lib/dns/python/edns_python.cc @@ -17,6 +17,7 @@ #include using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; // diff --git a/src/lib/dns/python/message_python.cc b/src/lib/dns/python/message_python.cc index 97bc28dac074968569c697eddf0569f93c143bec..058312e676d22e5238bb48e3c8b0e25fba245d5a 100644 --- a/src/lib/dns/python/message_python.cc +++ b/src/lib/dns/python/message_python.cc @@ -15,6 +15,7 @@ #include #include using namespace isc::dns; +using namespace isc::util; // // Declaration of the custom exceptions diff --git a/src/lib/dns/python/messagerenderer_python.cc b/src/lib/dns/python/messagerenderer_python.cc index f12001d20263fafc595b1d3377acdcb83d78f342..85a4f17d7ced9f2bc3f9f17ca317ddca01ca4487 100644 --- a/src/lib/dns/python/messagerenderer_python.cc +++ b/src/lib/dns/python/messagerenderer_python.cc @@ -18,6 +18,7 @@ // and static wrappers around the methods we export), a list of methods, // and a type description using namespace isc::dns; +using namespace isc::util; // MessageRenderer diff --git a/src/lib/dns/python/name_python.cc b/src/lib/dns/python/name_python.cc index 7d8913a758065d7f82d10abdf3396dabaa04ba18..b030ba15e82527cad45d0925c1448af4986b0d00 100644 --- a/src/lib/dns/python/name_python.cc +++ b/src/lib/dns/python/name_python.cc @@ -41,6 +41,7 @@ static PyObject* po_NameRelation; // and static wrappers around the methods we export), a list of methods, // and a type description using namespace isc::dns; +using namespace isc::util; // NameComparisonResult class s_NameComparisonResult : public PyObject { diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc index 7b4159886ddcdfe8fd5f7fc9b3b2a41832e74d68..27dbae684a7f9843b9b01326da17e9512d801435 100644 --- a/src/lib/dns/python/pydnspp.cc +++ b/src/lib/dns/python/pydnspp.cc @@ -31,7 +31,7 @@ #include -#include +#include #include #include #include diff --git a/src/lib/dns/python/rdata_python.cc b/src/lib/dns/python/rdata_python.cc index 8579b7e3cb54a8e00ffcb17cbefea503d160c93f..faa4f4c41fe3595f682f48c0215de76c2a58a754 100644 --- a/src/lib/dns/python/rdata_python.cc +++ b/src/lib/dns/python/rdata_python.cc @@ -14,6 +14,7 @@ #include using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; // diff --git a/src/lib/dns/python/rrclass_python.cc b/src/lib/dns/python/rrclass_python.cc index ca20e68210b90589b239858b480d6730d2e10cb9..6d150c2b5e0d5b1044024b66e6d64b163e909b6d 100644 --- a/src/lib/dns/python/rrclass_python.cc +++ b/src/lib/dns/python/rrclass_python.cc @@ -14,6 +14,7 @@ #include using namespace isc::dns; +using namespace isc::util; // // Declaration of the custom exceptions diff --git a/src/lib/dns/python/rrset_python.cc b/src/lib/dns/python/rrset_python.cc index 22927846c95b9dd16463ec36c5e078bebf529221..c7d05d1e1de8e89cf1f6850e2a0fd4bc709a014b 100644 --- a/src/lib/dns/python/rrset_python.cc +++ b/src/lib/dns/python/rrset_python.cc @@ -29,6 +29,7 @@ static PyObject* po_EmptyRRset; // and static wrappers around the methods we export), a list of methods, // and a type description using namespace isc::dns; +using namespace isc::util; // RRset diff --git a/src/lib/dns/python/rrttl_python.cc b/src/lib/dns/python/rrttl_python.cc index 696e1a044f858ffd00163ec8a5966041c7cafc67..c4b25bfa307c78fc2417a1724d0bd97776431441 100644 --- a/src/lib/dns/python/rrttl_python.cc +++ b/src/lib/dns/python/rrttl_python.cc @@ -18,6 +18,7 @@ using namespace std; using namespace isc::dns; +using namespace isc::util; // // Declaration of the custom exceptions diff --git a/src/lib/dns/python/rrtype_python.cc b/src/lib/dns/python/rrtype_python.cc index 4fc0284771366c91e1864ea625651ea3e505d911..00e0acd6322a25fc6a2a0288d3e5664281028091 100644 --- a/src/lib/dns/python/rrtype_python.cc +++ b/src/lib/dns/python/rrtype_python.cc @@ -18,6 +18,7 @@ using namespace std; using namespace isc::dns; +using namespace isc::util; // // Declaration of the custom exceptions diff --git a/src/lib/dns/python/tests/Makefile.am b/src/lib/dns/python/tests/Makefile.am index 7f3c2139ef857f6e0f5261a8ce54ebfe30476471..272f1c14420212fa34de619e7383846a8e31c54d 100644 --- a/src/lib/dns/python/tests/Makefile.am +++ b/src/lib/dns/python/tests/Makefile.am @@ -20,7 +20,7 @@ EXTRA_DIST += testutil.py # required by loadable python modules. LIBRARY_PATH_PLACEHOLDER = if SET_ENV_LIBRARY_PATH -LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH) +LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH) endif # test using command-line arguments, so use check-local target instead of TESTS diff --git a/src/lib/dns/question.cc b/src/lib/dns/question.cc index 3e14c7874909168870cc6fd9c697d7fa3c329b95..723fc88ae07ea92183327b30a5499eaaae8a77fc 100644 --- a/src/lib/dns/question.cc +++ b/src/lib/dns/question.cc @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -23,6 +23,7 @@ #include using namespace std; +using namespace isc::util; namespace isc { namespace dns { diff --git a/src/lib/dns/question.h b/src/lib/dns/question.h index 520207b5eb925e028c98794c59bd06bff8a25cf4..3c038b371d286a8c1903b8b9a51f0ba030635ee4 100644 --- a/src/lib/dns/question.h +++ b/src/lib/dns/question.h @@ -25,9 +25,13 @@ #include namespace isc { +namespace util { +class InputBuffer; +class OutputBuffer; +} + namespace dns { -class InputBuffer; class MessageRenderer; class Question; @@ -118,7 +122,7 @@ public: /// classes fails. /// /// \param buffer A buffer storing the wire format data. - Question(InputBuffer& buffer); + Question(isc::util::InputBuffer& buffer); /// \brief Constructor from fixed parameters of the \c Question. /// @@ -224,7 +228,7 @@ public: /// /// \param buffer An output buffer to store the wire data. /// \return 1 - unsigned int toWire(OutputBuffer& buffer) const; + unsigned int toWire(isc::util::OutputBuffer& buffer) const; //@} /// diff --git a/src/lib/dns/rdata.cc b/src/lib/dns/rdata.cc index 19b266a1e174c8b634bc21dd2fcd0d98fcd50478..27496a27c64d7057d78f31948f858c8b284b9346 100644 --- a/src/lib/dns/rdata.cc +++ b/src/lib/dns/rdata.cc @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -36,6 +36,7 @@ using namespace std; using namespace boost; +using namespace isc::util; namespace isc { namespace dns { @@ -53,7 +54,7 @@ createRdata(const RRType& rrtype, const RRClass& rrclass, RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, - InputBuffer& buffer, size_t len) + isc::util::InputBuffer& buffer, size_t len) { if (len > MAX_RDLENGTH) { isc_throw(InvalidRdataLength, "RDLENGTH too large"); @@ -105,7 +106,7 @@ struct GenericImpl { vector data_; }; -Generic::Generic(InputBuffer& buffer, size_t rdata_len) { +Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) { if (rdata_len > MAX_RDLENGTH) { isc_throw(InvalidRdataLength, "RDLENGTH too large"); } @@ -224,12 +225,12 @@ Generic::toText() const { } void -Generic::toWire(OutputBuffer& buffer) const { +Generic::toWire(isc::util::OutputBuffer& buffer) const { buffer.writeData(&impl_->data_[0], impl_->data_.size()); } void -Generic::toWire(MessageRenderer& renderer) const { +Generic::toWire(AbstractMessageRenderer& renderer) const { renderer.writeData(&impl_->data_[0], impl_->data_.size()); } diff --git a/src/lib/dns/rdata.h b/src/lib/dns/rdata.h index 0908c75fb1d163870ad6300d27680efbac1bdec3..afcf4b3da011071d9d807ca42b213611d6b3c816 100644 --- a/src/lib/dns/rdata.h +++ b/src/lib/dns/rdata.h @@ -22,10 +22,12 @@ #include namespace isc { -namespace dns { +namespace util { class InputBuffer; class OutputBuffer; -class MessageRenderer; +} +namespace dns { +class AbstractMessageRenderer; class RRType; class RRClass; class Name; @@ -169,7 +171,7 @@ public: /// 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; + virtual void toWire(isc::util::OutputBuffer& buffer) const = 0; /// \brief Render the \c Rdata in the wire format into a /// \c MessageRenderer object. @@ -180,7 +182,7 @@ public: /// /// \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; + virtual void toWire(AbstractMessageRenderer& renderer) const = 0; //@} /// @@ -275,7 +277,7 @@ public: /// \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); + Generic(isc::util::InputBuffer& buffer, size_t rdata_len); /// /// \brief The destructor. @@ -323,7 +325,7 @@ public: /// be thrown. /// /// \param buffer An output buffer to store the wire data. - virtual void toWire(OutputBuffer& buffer) const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; /// \brief Render the \c generic::Generic in the wire format into a /// \c MessageRenderer object. @@ -335,7 +337,7 @@ public: /// /// \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; + virtual void toWire(AbstractMessageRenderer& renderer) const; //@} /// @@ -453,7 +455,7 @@ RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, /// \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); + isc::util::InputBuffer& buffer, size_t len); /// \brief Create RDATA of a given pair of RR type and class, copying /// of another RDATA of same kind. diff --git a/src/lib/dns/rdata/any_255/tsig_250.cc b/src/lib/dns/rdata/any_255/tsig_250.cc index e025ce4f219910d7970563d76788e4229cfd6be6..f2bd7ad72addbf906c762d75602fa7498341399a 100644 --- a/src/lib/dns/rdata/any_255/tsig_250.cc +++ b/src/lib/dns/rdata/any_255/tsig_250.cc @@ -18,15 +18,18 @@ #include -#include +#include +#include + #include #include #include -#include using namespace std; using namespace boost; +using namespace isc::util; +using namespace isc::util::encode; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -377,9 +380,9 @@ TSIG::toWire(OutputBuffer& buffer) const { /// \param renderer DNS message rendering context that encapsulates the /// output buffer and name compression information. void -TSIG::toWire(MessageRenderer& renderer) const { +TSIG::toWire(AbstractMessageRenderer& renderer) const { renderer.writeName(impl_->algorithm_, false); - impl_->toWireCommon(renderer); + impl_->toWireCommon(renderer); } // A helper function commonly used for TSIG::compare(). diff --git a/src/lib/dns/rdata/ch_3/a_1.cc b/src/lib/dns/rdata/ch_3/a_1.cc index 376cbddc63ec5ebb84d71c747d124d29191abbf1..65378a1f844645a6f6e477d7f57f734535900bf3 100644 --- a/src/lib/dns/rdata/ch_3/a_1.cc +++ b/src/lib/dns/rdata/ch_3/a_1.cc @@ -16,12 +16,13 @@ #include -#include +#include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -44,7 +45,7 @@ A::toWire(OutputBuffer&) const { } void -A::toWire(MessageRenderer&) const { +A::toWire(AbstractMessageRenderer&) const { // TBD } diff --git a/src/lib/dns/rdata/generic/cname_5.cc b/src/lib/dns/rdata/generic/cname_5.cc index c7f97d02fef12cfbeabc0fdc159cc5c8f354e9ef..5bb0aeab15bddc20e0f8415f78df09abeab62506 100644 --- a/src/lib/dns/rdata/generic/cname_5.cc +++ b/src/lib/dns/rdata/generic/cname_5.cc @@ -16,13 +16,14 @@ #include -#include +#include #include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -52,7 +53,7 @@ CNAME::toWire(OutputBuffer& buffer) const { } void -CNAME::toWire(MessageRenderer& renderer) const { +CNAME::toWire(AbstractMessageRenderer& renderer) const { renderer.writeName(cname_); } diff --git a/src/lib/dns/rdata/generic/dname_39.cc b/src/lib/dns/rdata/generic/dname_39.cc index b88720ef5e3de45c7b8235655cb6534896a4f4fe..165c4a66aa6b1df1af6da2d63e8f5ad77037f006 100644 --- a/src/lib/dns/rdata/generic/dname_39.cc +++ b/src/lib/dns/rdata/generic/dname_39.cc @@ -16,13 +16,14 @@ #include -#include +#include #include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -52,7 +53,7 @@ DNAME::toWire(OutputBuffer& buffer) const { } void -DNAME::toWire(MessageRenderer& renderer) const { +DNAME::toWire(AbstractMessageRenderer& renderer) const { renderer.writeName(dname_); } diff --git a/src/lib/dns/rdata/generic/dnskey_48.cc b/src/lib/dns/rdata/generic/dnskey_48.cc index 16a748ec8fd0113126c32c3f88cbb98d8076aa33..e0f5461b01149d6fa3bde48a9d528f1004af54de 100644 --- a/src/lib/dns/rdata/generic/dnskey_48.cc +++ b/src/lib/dns/rdata/generic/dnskey_48.cc @@ -20,8 +20,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -31,6 +31,8 @@ #include using namespace std; +using namespace isc::util; +using namespace isc::util::encode; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -134,7 +136,7 @@ DNSKEY::toWire(OutputBuffer& buffer) const { } void -DNSKEY::toWire(MessageRenderer& renderer) const { +DNSKEY::toWire(AbstractMessageRenderer& renderer) const { renderer.writeUint16(impl_->flags_); renderer.writeUint8(impl_->protocol_); renderer.writeUint8(impl_->algorithm_); diff --git a/src/lib/dns/rdata/generic/ds_43.cc b/src/lib/dns/rdata/generic/ds_43.cc index cca19aef6945d22a898b3c12d79ab5f147c4d078..1b48456d8b03f4138a0990e21cee3badd2f3d567 100644 --- a/src/lib/dns/rdata/generic/ds_43.cc +++ b/src/lib/dns/rdata/generic/ds_43.cc @@ -19,8 +19,9 @@ #include -#include -#include +#include +#include + #include #include #include @@ -30,6 +31,8 @@ #include using namespace std; +using namespace isc::util; +using namespace isc::util::encode; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -130,7 +133,7 @@ DS::toWire(OutputBuffer& buffer) const { } void -DS::toWire(MessageRenderer& renderer) const { +DS::toWire(AbstractMessageRenderer& renderer) const { renderer.writeUint16(impl_->tag_); renderer.writeUint8(impl_->algorithm_); renderer.writeUint8(impl_->digest_type_); diff --git a/src/lib/dns/rdata/generic/mx_15.cc b/src/lib/dns/rdata/generic/mx_15.cc index 0ae22518eb989c457659b802fd02e2248e214567..4765222323fbc482a7eec820d8ac3c73fe050d40 100644 --- a/src/lib/dns/rdata/generic/mx_15.cc +++ b/src/lib/dns/rdata/generic/mx_15.cc @@ -20,7 +20,7 @@ #include -#include +#include #include #include #include @@ -28,6 +28,7 @@ using namespace std; using namespace boost; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -71,7 +72,7 @@ MX::toWire(OutputBuffer& buffer) const { } void -MX::toWire(MessageRenderer& renderer) const { +MX::toWire(AbstractMessageRenderer& renderer) const { renderer.writeUint16(preference_); renderer.writeName(mxname_); } diff --git a/src/lib/dns/rdata/generic/ns_2.cc b/src/lib/dns/rdata/generic/ns_2.cc index 0e56911d8ddffbcb6a0132d675c151c9db7da9c6..631da9d45be9258196cfff3c9d833314b036b28a 100644 --- a/src/lib/dns/rdata/generic/ns_2.cc +++ b/src/lib/dns/rdata/generic/ns_2.cc @@ -16,13 +16,14 @@ #include -#include +#include #include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -48,7 +49,7 @@ NS::toWire(OutputBuffer& buffer) const { } void -NS::toWire(MessageRenderer& renderer) const { +NS::toWire(AbstractMessageRenderer& renderer) const { renderer.writeName(nsname_); } diff --git a/src/lib/dns/rdata/generic/nsec3_50.cc b/src/lib/dns/rdata/generic/nsec3_50.cc index fbe66122574437d07bab7f0e7b012063d84adbe0..3bd0bb2d50ff9e668dd6ed4b69c37e1e9e3243b6 100644 --- a/src/lib/dns/rdata/generic/nsec3_50.cc +++ b/src/lib/dns/rdata/generic/nsec3_50.cc @@ -20,10 +20,11 @@ #include -#include -#include +#include +#include +#include + #include -#include #include #include #include @@ -37,6 +38,8 @@ using namespace std; using namespace isc::dns::rdata::generic::detail::nsec; +using namespace isc::util::encode; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -259,7 +262,7 @@ NSEC3::toWire(OutputBuffer& buffer) const { } void -NSEC3::toWire(MessageRenderer& renderer) const { +NSEC3::toWire(AbstractMessageRenderer& renderer) const { renderer.writeUint8(impl_->hashalg_); renderer.writeUint8(impl_->flags_); renderer.writeUint16(impl_->iterations_); diff --git a/src/lib/dns/rdata/generic/nsec3param_51.cc b/src/lib/dns/rdata/generic/nsec3param_51.cc index 639feedcde442fe78afc817e5c266a6d7fb36210..49f666b7d02e16ca797b4f4025891c0a9ae9562c 100644 --- a/src/lib/dns/rdata/generic/nsec3param_51.cc +++ b/src/lib/dns/rdata/generic/nsec3param_51.cc @@ -19,8 +19,8 @@ #include -#include -#include +#include +#include #include #include #include @@ -30,6 +30,8 @@ #include using namespace std; +using namespace isc::util; +using namespace isc::util::encode; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -134,7 +136,7 @@ NSEC3PARAM::toWire(OutputBuffer& buffer) const { } void -NSEC3PARAM::toWire(MessageRenderer& renderer) const { +NSEC3PARAM::toWire(AbstractMessageRenderer& renderer) const { renderer.writeUint8(impl_->hashalg_); renderer.writeUint8(impl_->flags_); renderer.writeUint16(impl_->iterations_); diff --git a/src/lib/dns/rdata/generic/nsec_47.cc b/src/lib/dns/rdata/generic/nsec_47.cc index 72eb946a14e43047cbacfeb4707845e2756b23a4..93b8b5f260862464f2ff2264cad45b881235fa84 100644 --- a/src/lib/dns/rdata/generic/nsec_47.cc +++ b/src/lib/dns/rdata/generic/nsec_47.cc @@ -17,8 +17,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -32,6 +32,8 @@ #include using namespace std; +using namespace isc::util; +using namespace isc::util::encode; using namespace isc::dns::rdata::generic::detail::nsec; // BEGIN_ISC_NAMESPACE @@ -171,7 +173,7 @@ NSEC::toWire(OutputBuffer& buffer) const { } void -NSEC::toWire(MessageRenderer& renderer) const { +NSEC::toWire(AbstractMessageRenderer& renderer) const { impl_->nextname_.toWire(renderer); renderer.writeData(&impl_->typebits_[0], impl_->typebits_.size()); } diff --git a/src/lib/dns/rdata/generic/opt_41.cc b/src/lib/dns/rdata/generic/opt_41.cc index 1aae8104e0acb06336ece8fdc4e8bb2e4a51d930..62cfc175e3cc3b98b5d00e322f276bb1ff4448ee 100644 --- a/src/lib/dns/rdata/generic/opt_41.cc +++ b/src/lib/dns/rdata/generic/opt_41.cc @@ -16,12 +16,13 @@ #include -#include +#include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -56,7 +57,7 @@ OPT::toWire(OutputBuffer&) const { } void -OPT::toWire(MessageRenderer&) const { +OPT::toWire(AbstractMessageRenderer&) const { // nothing to do, as this simple version doesn't support any options. } diff --git a/src/lib/dns/rdata/generic/ptr_12.cc b/src/lib/dns/rdata/generic/ptr_12.cc index dc656b882433228923daddfdd4e901aa7667142f..86ddeb4a3c5ff042ddbd6fac0ae52d05cbb6d175 100644 --- a/src/lib/dns/rdata/generic/ptr_12.cc +++ b/src/lib/dns/rdata/generic/ptr_12.cc @@ -16,13 +16,14 @@ #include -#include +#include #include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -53,7 +54,7 @@ PTR::toWire(OutputBuffer& buffer) const { } void -PTR::toWire(MessageRenderer& renderer) const { +PTR::toWire(AbstractMessageRenderer& renderer) const { renderer.writeName(ptr_name_); } diff --git a/src/lib/dns/rdata/generic/rp_17.cc b/src/lib/dns/rdata/generic/rp_17.cc index 5b39dc3218da3b5ce9c46f8d15d54b5d79c2d27a..b8b2ba21b148a9ccf170eba9ecd78bfb94c15950 100644 --- a/src/lib/dns/rdata/generic/rp_17.cc +++ b/src/lib/dns/rdata/generic/rp_17.cc @@ -15,7 +15,8 @@ #include #include -#include +#include + #include #include #include @@ -102,7 +103,7 @@ RP::toWire(OutputBuffer& buffer) const { } void -RP::toWire(MessageRenderer& renderer) const { +RP::toWire(AbstractMessageRenderer& renderer) const { // Type RP is not "well-known", and name compression must be disabled // per RFC3597. renderer.writeName(mailbox_, false); diff --git a/src/lib/dns/rdata/generic/rrsig_46.cc b/src/lib/dns/rdata/generic/rrsig_46.cc index c9d1e525e894b2d907a9041f3870016a1791f060..0c82406895516ee70f6f60021f92226e7c01b9ca 100644 --- a/src/lib/dns/rdata/generic/rrsig_46.cc +++ b/src/lib/dns/rdata/generic/rrsig_46.cc @@ -20,9 +20,9 @@ #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -34,6 +34,8 @@ #include using namespace std; +using namespace isc::util; +using namespace isc::util::encode; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -182,7 +184,7 @@ RRSIG::toWire(OutputBuffer& buffer) const { } void -RRSIG::toWire(MessageRenderer& renderer) const { +RRSIG::toWire(AbstractMessageRenderer& renderer) const { impl_->covered_.toWire(renderer); renderer.writeUint8(impl_->algorithm_); renderer.writeUint8(impl_->labels_); diff --git a/src/lib/dns/rdata/generic/soa_6.cc b/src/lib/dns/rdata/generic/soa_6.cc index c4b87c6844de5170f37344f7848d14b040aae709..7ecd84fef162f8b5fa3ba07ae915561a921d8206 100644 --- a/src/lib/dns/rdata/generic/soa_6.cc +++ b/src/lib/dns/rdata/generic/soa_6.cc @@ -20,7 +20,7 @@ #include -#include +#include #include #include #include @@ -28,6 +28,7 @@ using namespace std; using namespace boost; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -99,7 +100,7 @@ SOA::toWire(OutputBuffer& buffer) const { } void -SOA::toWire(MessageRenderer& renderer) const { +SOA::toWire(AbstractMessageRenderer& renderer) const { renderer.writeName(mname_); renderer.writeName(rname_); renderer.writeData(numdata_, sizeof(numdata_)); diff --git a/src/lib/dns/rdata/generic/txt_16.cc b/src/lib/dns/rdata/generic/txt_16.cc index 0e20f4efe866492dbb9ba241514db3bcfe8e5c72..ac2ba8a9f032f5019aa92b8f475f90262bef307e 100644 --- a/src/lib/dns/rdata/generic/txt_16.cc +++ b/src/lib/dns/rdata/generic/txt_16.cc @@ -18,13 +18,14 @@ #include #include -#include +#include #include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -101,7 +102,7 @@ TXT::toWire(OutputBuffer& buffer) const { } void -TXT::toWire(MessageRenderer& renderer) const { +TXT::toWire(AbstractMessageRenderer& renderer) const { for (vector >::const_iterator it = string_list_.begin(); it != string_list_.end(); ++it) diff --git a/src/lib/dns/rdata/hs_4/a_1.cc b/src/lib/dns/rdata/hs_4/a_1.cc index 376cbddc63ec5ebb84d71c747d124d29191abbf1..65378a1f844645a6f6e477d7f57f734535900bf3 100644 --- a/src/lib/dns/rdata/hs_4/a_1.cc +++ b/src/lib/dns/rdata/hs_4/a_1.cc @@ -16,12 +16,13 @@ #include -#include +#include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -44,7 +45,7 @@ A::toWire(OutputBuffer&) const { } void -A::toWire(MessageRenderer&) const { +A::toWire(AbstractMessageRenderer&) const { // TBD } diff --git a/src/lib/dns/rdata/in_1/a_1.cc b/src/lib/dns/rdata/in_1/a_1.cc index ddd03f8c3c11720c216e15c9c9a38ca377e2b6e3..fa46f9042b37302be91867ca5aeb4f7ffa80143f 100644 --- a/src/lib/dns/rdata/in_1/a_1.cc +++ b/src/lib/dns/rdata/in_1/a_1.cc @@ -22,13 +22,14 @@ #include -#include +#include #include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -69,7 +70,7 @@ A::toWire(OutputBuffer& buffer) const { } void -A::toWire(MessageRenderer& renderer) const { +A::toWire(AbstractMessageRenderer& renderer) const { renderer.writeData(&addr_, sizeof(addr_)); } diff --git a/src/lib/dns/rdata/in_1/aaaa_28.cc b/src/lib/dns/rdata/in_1/aaaa_28.cc index 45c46822016a335319068a719b4fa35070bd7cf9..e9fc122544912da0ff08ecef1feeb52fecccc3cd 100644 --- a/src/lib/dns/rdata/in_1/aaaa_28.cc +++ b/src/lib/dns/rdata/in_1/aaaa_28.cc @@ -22,13 +22,14 @@ #include -#include +#include #include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -66,7 +67,7 @@ AAAA::toWire(OutputBuffer& buffer) const { } void -AAAA::toWire(MessageRenderer& renderer) const { +AAAA::toWire(AbstractMessageRenderer& renderer) const { renderer.writeData(&addr_, sizeof(addr_)); } diff --git a/src/lib/dns/rdata/template.cc b/src/lib/dns/rdata/template.cc index b737f6092d5c20da49d1a5bf6fac36744e2b305b..d9f08ee91ba36a8f6e58d4c55baa436237855f2a 100644 --- a/src/lib/dns/rdata/template.cc +++ b/src/lib/dns/rdata/template.cc @@ -14,12 +14,13 @@ #include -#include +#include #include #include #include using namespace std; +using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE @@ -50,7 +51,7 @@ MyType::toWire(OutputBuffer& buffer) const { } void -MyType::toWire(MessageRenderer& renderer) const { +MyType::toWire(AbstractMessageRenderer& renderer) const { } int diff --git a/src/lib/dns/rdatafields.cc b/src/lib/dns/rdatafields.cc new file mode 100644 index 0000000000000000000000000000000000000000..d3f282be13af0d76a494e6dc95a02f6f960d1137 --- /dev/null +++ b/src/lib/dns/rdatafields.cc @@ -0,0 +1,223 @@ +// 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. + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace isc::dns; +using namespace isc::dns::rdata; +using isc::util::OutputBuffer; +using isc::util::InputBuffer; + +namespace isc { +namespace dns { +namespace rdata { + +/// This is a helper class for \c RdataFields. +/// +/// It manages a local storage for the data when \c RdataFields is constructed +/// from an \c Rdata. +/// To minimize construction overhead in the other case, an instance of +/// this class is instantiated only when necessary - we don't need the vectors +/// when only rendering. +struct RdataFields::RdataFieldsDetail { + RdataFieldsDetail(const vector& fields, + const uint8_t* data, size_t data_length) : + allocated_fields_(fields), + allocated_data_(data, data + data_length) + {} + const vector allocated_fields_; + const vector allocated_data_; +}; + +namespace { +// This class is used to divide the content of RDATA into \c RdataField +// fields via message rendering logic. +// The idea is to identify domain name fields in the writeName() method, +// and determine whether they are compressible using the "compress" +// parameter. +// Other types of data are simply copied into the internal buffer, and +// consecutive such fields are combined into a single \c RdataField field. +// +// Technically, this use of inheritance may be considered a violation of +// Liskov Substitution Principle in that it doesn't actually compress domain +// names, and some of the methods are not expected to be used. +// In fact, skip() or trim() may not be make much sense in this context. +// Nevertheless we keep this idea at the moment. Since the usage is limited +// (it's only used within this file, and only used with \c Rdata variants), +// it's hopefully an acceptable practice. +class RdataFieldComposer : public AbstractMessageRenderer { +public: + RdataFieldComposer(OutputBuffer& buffer) : + AbstractMessageRenderer(buffer), + truncated_(false), length_limit_(65535), + mode_(CASE_INSENSITIVE), last_data_pos_(0) + {} + virtual ~RdataFieldComposer() {} + virtual bool isTruncated() const { return (truncated_); } + virtual size_t getLengthLimit() const { return (length_limit_); } + virtual CompressMode getCompressMode() const { return (mode_); } + virtual void setTruncated() { truncated_ = true; } + virtual void setLengthLimit(size_t len) { length_limit_ = len; } + virtual void setCompressMode(CompressMode mode) { mode_ = mode; } + virtual void writeName(const Name& name, bool compress) { + extendData(); + const RdataFields::Type field_type = + compress ? RdataFields::COMPRESSIBLE_NAME : + RdataFields::INCOMPRESSIBLE_NAME; + // TODO: When we get rid of need for getBuffer, we can output the name + // to a buffer and then write the buffer inside + name.toWire(getBuffer()); + fields_.push_back(RdataFields::FieldSpec(field_type, + name.getLength())); + last_data_pos_ = getLength(); + } + + virtual void clear() { + isc_throw(Unexpected, "unexpected clear() for RdataFieldComposer"); + } + bool truncated_; + size_t length_limit_; + CompressMode mode_; + vector fields_; + vector& getFields() { + extendData(); + return (fields_); + } + // We use generict write* methods, with the exception of writeName. + // So new data can arrive without us knowing it, this considers all new + // data to be just data and extends the fields to take it into account. + size_t last_data_pos_; + void extendData() { + // No news, return to work + if (getLength() == last_data_pos_) { + return; + } + // The new bytes are just ordinary uninteresting data + if (fields_.empty() || fields_.back().type != RdataFields::DATA) { + fields_.push_back(RdataFields::FieldSpec(RdataFields::DATA, 0)); + } + // We added this much data from last time + fields_.back().len += getLength() - last_data_pos_; + last_data_pos_ = getLength(); + } +}; + +} + +RdataFields::RdataFields(const Rdata& rdata) { + OutputBuffer buffer(0); + RdataFieldComposer field_composer(buffer); + rdata.toWire(field_composer); + nfields_ = field_composer.getFields().size(); + data_length_ = field_composer.getLength(); + if (nfields_ > 0) { + assert(data_length_ > 0); + detail_ = new RdataFieldsDetail(field_composer.getFields(), + static_cast + (field_composer.getData()), + field_composer.getLength()); + data_ = &detail_->allocated_data_[0]; + fields_ = &detail_->allocated_fields_[0]; + } else { + assert(data_length_ == 0); + detail_ = NULL; + data_ = NULL; + fields_ = NULL; + } +} + +RdataFields::RdataFields(const void* fields, const unsigned int fields_length, + const void* data, const size_t data_length) : + fields_(static_cast(fields)), + nfields_(fields_length / sizeof(*fields_)), + data_(static_cast(data)), + data_length_(data_length), + detail_(NULL) +{ + if ((fields_ == NULL && nfields_ > 0) || + (fields_ != NULL && nfields_ == 0)) { + isc_throw(InvalidParameter, + "Inconsistent parameters for RdataFields: fields_length (" + << fields_length << ") and fields conflict each other"); + } + if ((data_ == NULL && data_length_ > 0) || + (data_ != NULL && data_length_ == 0)) { + isc_throw(InvalidParameter, + "Inconsistent parameters for RdataFields: data length (" + << data_length_ << ") and data conflict each other"); + } + + size_t total_length = 0; + for (int i = 0; i < nfields_; ++i) { + total_length += fields_[i].len; + } + if (total_length != data_length_) { + isc_throw(InvalidParameter, + "Inconsistent parameters for RdataFields; " + "fields len: " << total_length << + " data len: " << data_length_); + } +} + +RdataFields::~RdataFields() { + delete detail_; +} + +RdataFields::FieldSpec +RdataFields::getFieldSpec(const unsigned int field_id) const { + if (field_id >= nfields_) { + isc_throw(OutOfRange, "Rdata field ID is out of range: " << field_id); + } + return (fields_[field_id]); +} + +void +RdataFields::toWire(AbstractMessageRenderer& renderer) const { + size_t offset = 0; + + for (int i = 0; i < nfields_; ++i) { + if (fields_[i].type == DATA) { + renderer.writeData(data_ + offset, fields_[i].len); + } else { + // XXX: this is inefficient. Even if it's quite likely the + // data is a valid wire representation of a name we parse + // it to construct the Name object in the generic mode. + // This should be improved in a future version. + InputBuffer buffer(data_ + offset, fields_[i].len); + renderer.writeName(Name(buffer), + fields_[i].type == COMPRESSIBLE_NAME); + } + offset += fields_[i].len; + } +} + +void +RdataFields::toWire(OutputBuffer& buffer) const { + buffer.writeData(data_, data_length_); +} +} // end of namespace rdata +} // end of namespace dns +} // end of namespace isc diff --git a/src/lib/dns/rdatafields.h b/src/lib/dns/rdatafields.h new file mode 100644 index 0000000000000000000000000000000000000000..e33bcd75eab2ef9f9845246d6b61e0af2a65984d --- /dev/null +++ b/src/lib/dns/rdatafields.h @@ -0,0 +1,427 @@ +// 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. + +#ifndef __RDATAFIELDS_H +#define __RDATAFIELDS_H 1 + +#include + +#include + +namespace isc { +namespace util { +class OutputBuffer; +} +namespace dns { +class AbstractMessageRenderer; + +namespace rdata { +class Rdata; + +/// A low-level, RR type-independent representation of DNS RDATA. +/// +/// Purpose of the Class +/// +/// This class intends to help "serialization" of the content of RDATA +/// in a space-efficient manner. Specific derived classes of \c Rdata +/// focus on the convenience of accessing RDATA fields for RR type-specific +/// protocol operations, and can be inefficient in terms of space. +/// For example, a DNS character string may be internally represented as a +/// \c std::string object with all of the overhead of the richer class. +/// If an application needs to maintain a very large number of RRs and it +/// does not have to perform RR specific operation so often, it may make more +/// sense to store the data in memory in a lower-level but space efficient +/// form. +/// +/// Another purpose of this class is to improve rendering performance for +/// RDATA. If the only requirement were space efficiency, it would be just +/// sufficient to convert the \c RDATA into a binary sequence in the wire +/// format. However, to render the data in a DNS message, we'd have to +/// re-construct a corresponding \c Rdata object in the case where name +/// compression is necessary. This is not desirable, and this class is +/// provided to avoid such unnecessary overhead. +/// +/// Data Format +/// +/// To meet these goals, this class helps convert an \c Rdata object into +/// two pieces of information: Wire-format representation of the \c Rdata +/// and associated meta information for efficient rendering. +/// +/// Specifically, it maintains the wire-format data as a sequence of typed +/// fields. The types are: +/// - Compressible name: a domain name as an RDATA field that can be compressed +/// - Incompressible name: a domain name as an RDATA field that cannot be +/// compressed +/// - Other data: any other fields of RDATA, which should be treated as opaque +/// +/// (See also the description of \c RdataFields::Type) +/// Whether a name can or cannot be compressed is determined according to +/// RFC3597. +/// +/// A "other data" field may not always correspond to a single RDATA field. +/// A \c RdataFields field (of other data) is just a contiguous region of the +/// wire-format data that does not involve name compression. +/// For example, the SOA RDATA begins with two "compressible" names followed +/// by 5 32-bit fields. +/// In \c RdataFields the last 5 fields would be considered a single 20-byte +/// field. +/// +/// Each \c RdataFields field is identified by the \c FieldSpec structure, +/// which provides the type and length of the field. +/// An \c RdataFields object internally maintains a sequence of \c FieldSpec +/// objects in a form of plain C-style array, which can be referenced via +/// a pointer returned by the \c getFieldSpecData() method. +/// The \c \c FieldSpec for a specific field can also be retrieved by the +/// \c getFieldSpec() method. +/// +/// The following diagram shows the internal memory representation of +/// an SOA RDATA in the form of \c RdataFields object and how an application +/// can get access to the memory region. +/** \verbatim +accessible via |0 getDataLength() bytes +getData()----------> + <---------- 3 * sizeof(FieldSpec) bytes -------------> +getFieldSpecData()-> { compressible name { compressible name { other data + len: MNAME-len } len: RNAME-len } len: 20 } +\endverbatim + */ +/// where MNAME and RNAME are wire format representations of the MNAME and +/// RNAME fields of the SOA RDATA, respectively, and "Rest of the data" +/// encodes the remaining 20 bytes of the RDATA in network byte order. +/// +/// Usage of the Class +/// +/// One major and common use case of the \c RdataFields class is to convert +/// a \c Rdata object (possibly given from a DNS message or some configuration +/// source such as a zone file) in the serialized format and store a copy of +/// the data somewhere in memory. The following code sample implements this +/// scenario: +/// \code // assume "rdata" is a reference type to Rdata +/// const RdataFields fields(rdata); +/// const unsigned int fields_size = fields.getFieldDataSize(); +/// memcpy(some_place, fields.getFieldSpecData(), fields_size); +/// const size_t data_length = fields.getDataLength(); +/// memcpy(other_place, fields.getData(), data_length); +/// // (fields_size and data_length should be stored somewhere, too) +/// \endcode +/// +/// Another typical usage is to render the stored data in the wire format +/// as efficiently as possible. The following code is an example of such +/// usage: +/// \code // assume "renderer" is of type MessageRenderer +/// // retrieve data_length and fields_size from the storage +/// RdataFields(some_place, fields_size, other_place, +/// data_length).toWire(renderer); +/// \endcode +/// +/// Notes to Users +/// +/// The main purposes of this class is to help efficient operation +/// for some (limited classes of) performance sensitive application. +/// For this reason the interface and implementation rely on relatively +/// lower-level, riskier primitives such as passing around bare pointers. +/// +/// It is therefore discouraged to use this class for general purpose +/// applications that do not need to maximize performance in terms of either +/// memory footprint or rendering speed. +/// All functionality provided by this class can be achieved via higher level +/// interfaces such as the \c Rdata class variants. +/// Normal applications should use those interfaces. +/// +/// The data format is public information so that an application can examine +/// and use selected parts of data. For example, an application may want to +/// encode domain names in RDATA in a different way while storing the other +/// data in a separate place. +/// However, at this moment the format is still in flux, and it may not +/// be compatible with future versions (see below). +/// +/// Development Notes +/// +/// We should conduct benchmark tests to measure rendering performance. +/// +/// The current implementation needs to re-construct name objects from +/// compressible and incompressible name fields as wire-format data. +/// This is not efficient, and we'll probably want to improve this in a +/// future version. One possibility is to store offset information as well +/// as the name data (at the cost of increasing memory footprint), and +/// to use the pair of data for faster rendering. +class RdataFields { +public: + /// Types of \c RdataFields fields. + /// + /// \c COMPRESSIBLE_NAME and \c INCOMPRESSIBLE_NAME represent a domain + /// name used as a field of an RDATA that can and cannot be compressed + /// per RFC3597. + /// \c DATA means all other types of fields. + enum Type { + DATA, ///< Plain data. + COMPRESSIBLE_NAME, ///< A domain name subject to name compression. + INCOMPRESSIBLE_NAME ///< A domain name that shouldn't be compressed. + }; + + /// Structure that specifies a single \c RdataFields field. + /// + /// This is a straightforward pair of the type and length of a single + /// \c RdataFields field. + /// + /// In some cases an application may want to do deeper inspection of + /// some \c RdataFields field(s). For example, an application may want + /// to construct a \c Name object for each domain name field of an RDATA + /// and use it for some special purpose. + /// The \c FieldSpec structure provides necessary parameters to get access + /// to a specific \c RdataFields field. + /// + /// The following code snippet implements the above example scenario: + /// \code // assume "fields" is of type RdataFields + /// size_t offset = 0; + /// for (int i = 0; i < fields.getFieldCount(); ++i) { + /// const FieldSpec spec = fields.getFieldSpec(i); + /// if (spec.type == RdataFields::COMPRESSIBLE_NAME || + /// spec.type == RdataFields::INCOMPRESSIBLE_NAME) { + /// InputBuffer ibuffer(fields.getData() + offset, spec.len); + /// Name name(ibuffer); + /// // do something with name + /// } + /// offset += spec.len; + /// } \endcode + /// + /// Note that the offset is not included in \c FieldSpec. + /// This is because such deeper inspection would be a relatively rare + /// operation while it is desirable to keep this structure as small as + /// possible for the purpose of space efficiency. + /// Also, if and when an application wants to look into a specific field, + /// it would be quite likely that the application iterates over all fields + /// and does something special for selected fields like the above example. + /// In that case the application can easily and efficiently identify the + /// necessary offset, again, as shown in the above code example. + /// + /// \todo We might find that 16bits per field is generally too much and + /// squeeze the two bit type into it as well, having 14bit length + /// (in the rare case of having too long field, it could be split into + /// multiple ones). That would save 2 bytes per item (one for the type, + /// one for padding). + struct FieldSpec { + FieldSpec(Type type_param, uint16_t len_param) : + type(type_param), len(len_param) + {} + Type type; ///< The type of the field. + uint16_t len; ///< The length of the field in bytes. + }; + + /// + /// \name Constructors and Destructor. + /// + /// \b Note: + /// The copy constructor and the assignment operator are intentionally + /// defined as private, making this class non copyable. + //@{ +private: + RdataFields(const RdataFields& source); + RdataFields& operator=(const RdataFields& source); + +public: + /// Constructor from Rdata. + /// + /// This constructor converts the data of a given \c Rdata object into + /// an \c RdataFields object so that the resulting data can be stored + /// in memory in a space-efficient way. + /// + /// It makes a local copy of the original data and dynamically allocates + /// necessary memory, so is not very efficient. + /// The basic idea is to perform the expensive conversion once and keep + /// using the result as long as possible to improve overall performance + /// in a longer term. + /// + /// If the internal resource allocation fails, a corresponding standard + /// exception will be thrown. + /// The current implementation of this constructor internally calls + /// the Rdata::toWire(AbstractMessageRenderer&) const method + /// for the conversion. + /// If that method throws an exception it will be propagated to the caller + /// of this constructor. + /// + /// \param rdata The RDATA for which the \c RdataFields to be constructed. + RdataFields(const Rdata& rdata); + + /// Constructor from field parameters. + /// + /// The intended usage of this version of constructor is to form a + /// structured representation of \c RDATA encoded by the other + /// constructor so that the resulting object can be used for subsequent + /// operations such as rendering in the wire format. + /// This version is intended to be efficient by not making any copy + /// of variable length data or expensive data inspection. + /// + /// This constructor is basically exception free, except against bogus + /// input parameters. + /// Specifically, the parameters must meet the following conditions; + /// otherwise an exception of class \c InvalidParameter will be thrown. + /// - \c fields can be \c NULL if and only if \c nfields is 0 + /// - \c data can be \c NULL if and only if \c data_length is 0 + /// - the sum of the lengths of \c fields entries must be equal to + /// \c data_length + /// + /// This constructor assumes that the memory region pointed by \c data (if + /// non \c NULL) is encoded as a sequence of valid \c RdataFields fields, + /// and does not perform deep inspection on each field. + /// In particular, for fields of type \c COMPRESSIBLE_NAME or + /// \c INCOMPRESSIBLE_NAME, this constructor assumes the corresponding + /// memory region is a valid representation of domain name. + /// Otherwise, a subsequent method call such as + /// toWire(AbstractMessageRenderer&) const + /// may trigger an unexpected exception. It also expects the fields reside + /// on address that is valid for them (eg. it has valid alignment), see + /// getFieldSpecData() for details. + /// + /// It is the caller's responsibility to ensure this assumption. + /// In general, this constructor is expected to be used for serialized data + /// generated by the other constructor from a valid \c Rdata. + /// The result is not guaranteed if the data is generated in any other + /// ways. + /// + /// The resulting \c RdataFields object does not maintain a copy of + /// \c fields or \c data. It is the caller's responsibility to ensure + /// the memory regions pointed to by these parameters are valid and intact + /// as long as the \c RdataFields object is used. + /// + /// \param fields An array of \c FieldSpec entries. This can be \c NULL. + /// \param nfields The number of entries of \c fields. + /// \param data A pointer to memory region for the entire RDATA. This can + /// be NULL. + /// \param data_length The length of \c data in bytes. + RdataFields(const void* fields, const unsigned int fields_length, + const void* data, const size_t data_length); + + /// The destructor. + ~RdataFields(); + //@} + + /// + /// \name Getter Methods + /// + //@{ + /// \brief Return the length of the entire RDATA encoded in the + /// \c RdataFields in bytes. + /// + /// This method never throws an exception. + unsigned int getDataLength() const { return (data_length_); } + + /// \brief Return a pointer to the RDATA encoded in the \c RdataFields. + /// + /// The RdataFields holds ownership of the data. + /// + /// This method never throws an exception. + const void* getData() const { return (data_); } + + /// \brief Return the number of bytes the buffer returned by + /// getFieldSpecData() will occupy. + /// + /// This method never throws an exception. + unsigned int getFieldSpecDataSize() const { return (nfields_ * + sizeof (*fields_)); } + + /// \brief Return the number of specs fields. + /// + /// It specifies the range of parameter for getFieldSpec(). + /// + /// This method never throws. + unsigned int getFieldCount() const { return (nfields_); } + + /// \brief Return a pointer to a sequence of \c FieldSpec for the + /// \c RdataFields. + /// + /// This should be treated as an opaque internal representation you can + /// just store off somewhere and use it to construct a new RdataFields. + /// from it. If you are really interested, you can typecast it to + /// FieldSpec * (which is what it really is internally). + /// + /// The RdataFields holds ownership of the data. + /// + /// \note You should, however, be aware of alignment issues. The pointer + /// you pass to the constructor must be an address where the FieldSpec + /// can live. If you store it at a wrong address (eg. even one with + /// current implementation on most architectures), it might lead bad + /// things from slow access to SIGBUS. The easiest way is not to + /// interleave the fields with data from getData(). It is OK to place + /// all the fields first (even from multiple RdataFields) and then + /// place all the data after them. + /// + /// This method never throws an exception. + const void* getFieldSpecData() const { + return (fields_); + } + + /// \brief Return the specification of the field identified by the given + /// index. + /// + /// \c field_id is the field index, which must be in the range of + /// [0, getFieldCount()). 0 means the first field, and + /// getFieldCount()-1 means the last. + /// + /// If the given index is not in the valid range, an exception of class + /// \c OutOfRange will be thrown. + /// This method never throws an exception otherwise. + /// + /// \param field_id The index of an \c RdataFields field to be returned. + /// \return A \c FieldSpec structure that contains the information of + /// the \c field_id-th field. + FieldSpec getFieldSpec(const unsigned int field_id) const; + //@} + + /// + /// \name Converter Methods + /// + //@{ + /// \brief Render the RdataFields in the wire format with name compression. + /// + /// This method may require resource allocation in \c renderer. + /// If it fails, a corresponding standard exception will be thrown. + /// It should not throw any other exception as long as the \c RdataFields + /// object was constructed from valid parameters (see the description of + /// constructors). The result is not guaranteed if it's constructed in + /// any other ways. + /// + /// \param renderer DNS message rendering context that encapsulates the + /// output buffer and name compression information. + void toWire(AbstractMessageRenderer& renderer) const; + + /// \brief Render the RdataFields in the wire format without name + /// compression. + /// + /// This method may require resource allocation in \c buffer. + /// If it fails, a corresponding standard exception will be thrown. + /// + /// \param buffer An output buffer to store the wire data. + void toWire(isc::util::OutputBuffer& buffer) const; + //@} + +private: + const FieldSpec* fields_; + unsigned int nfields_; + const uint8_t* data_; + size_t data_length_; + + // hide further details within the implementation and don't create vectors + // every time we don't need them. + struct RdataFieldsDetail; + RdataFieldsDetail* detail_; +}; +} +} +} +#endif // __RDATAFIELDS_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rrclass-placeholder.h b/src/lib/dns/rrclass-placeholder.h index ce9a14191b104739fe7e1971577496e7c5ff656c..ae3ff6fc2650df4bbe16661114c6cde71c7a9932 100644 --- a/src/lib/dns/rrclass-placeholder.h +++ b/src/lib/dns/rrclass-placeholder.h @@ -23,11 +23,14 @@ #include namespace isc { +namespace util { +class InputBuffer; +class OutputBuffer; +} + namespace dns { // forward declarations -class InputBuffer; -class OutputBuffer; class MessageRenderer; /// @@ -132,7 +135,7 @@ public: /// an exception of class \c IncompleteRRClass will be thrown. /// /// \param buffer A buffer storing the wire format data. - explicit RRClass(InputBuffer& buffer); + explicit RRClass(isc::util::InputBuffer& buffer); /// /// We use the default copy constructor intentionally. //@} @@ -177,7 +180,7 @@ public: /// /// \param renderer DNS message rendering context that encapsulates the /// output buffer in which the RRClass is to be stored. - void toWire(OutputBuffer& buffer) const; + void toWire(isc::util::OutputBuffer& buffer) const; //@} /// diff --git a/src/lib/dns/rrclass.cc b/src/lib/dns/rrclass.cc index 04ff59c818ec7718a3467eefb2b0f836b0c05a73..f1bb8d7e07a929ddf3db99090a79e6095dd345b2 100644 --- a/src/lib/dns/rrclass.cc +++ b/src/lib/dns/rrclass.cc @@ -18,13 +18,14 @@ #include -#include +#include #include #include #include using namespace std; using namespace isc::dns; +using namespace isc::util; namespace isc { namespace dns { diff --git a/src/lib/dns/rrparamregistry-placeholder.cc b/src/lib/dns/rrparamregistry-placeholder.cc index 19363a3791fa5e5c6eb694325df32b4c6de89702..5058ca3bb142e28d7cab5db986cc3532162840b4 100644 --- a/src/lib/dns/rrparamregistry-placeholder.cc +++ b/src/lib/dns/rrparamregistry-placeholder.cc @@ -36,6 +36,7 @@ using namespace std; using namespace boost; +using namespace isc::util; using namespace isc::dns::rdata; namespace isc { diff --git a/src/lib/dns/rrparamregistry.h b/src/lib/dns/rrparamregistry.h index a85642354e0a749d4914e968fbe299acb8a4b30b..ae41b5f6bc42786ed99d1b42b52432f402f53a7d 100644 --- a/src/lib/dns/rrparamregistry.h +++ b/src/lib/dns/rrparamregistry.h @@ -102,7 +102,7 @@ public: /// \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; + virtual RdataPtr create(isc::util::InputBuffer& buffer, size_t rdata_len) const = 0; /// /// \brief Create RDATA from another \c Rdata object of the same type. /// @@ -473,7 +473,7 @@ public: /// \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); + isc::util::InputBuffer& buffer, size_t len); /// \brief Create RDATA of a given pair of RR type and class, copying /// of another RDATA of same kind. /// diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc index b931becf192177036d7822f26806350ba02f8f4e..e80afdbc4256e5161225073eb4bcf89c373f890f 100644 --- a/src/lib/dns/rrset.cc +++ b/src/lib/dns/rrset.cc @@ -18,7 +18,7 @@ #include -#include +#include #include #include #include @@ -28,6 +28,7 @@ using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace isc { diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h index 926a58fa3704ac0c9946db285f9b36aab0eb7db9..bf7adc0cf1b3b3591dd4741fb9cfd38755cb3542 100644 --- a/src/lib/dns/rrset.h +++ b/src/lib/dns/rrset.h @@ -26,6 +26,10 @@ #include namespace isc { +namespace util { +class OututBuffer; +} + namespace dns { /// @@ -43,7 +47,6 @@ class Name; class RRType; class RRClass; class RRTTL; -class OututBuffer; class MessageRenderer; class AbstractRRset; class BasicRRset; @@ -316,7 +319,7 @@ public: /// /// \param buffer An output buffer to store the wire data. /// \return The number of RRs rendered. - virtual unsigned int toWire(OutputBuffer& buffer) const = 0; + virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const = 0; //@} /// @@ -620,7 +623,7 @@ public: /// /// This method simply uses the default implementation. /// See \c AbstractRRset::toWire(OutputBuffer&)const. - virtual unsigned int toWire(OutputBuffer& buffer) const; + virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const; //@} /// diff --git a/src/lib/dns/rrttl.cc b/src/lib/dns/rrttl.cc index 78bb35592410a1e8406dc178d255b98f4311ce33..a4c4f83812e44e3590575372b01a84fb114ce397 100644 --- a/src/lib/dns/rrttl.cc +++ b/src/lib/dns/rrttl.cc @@ -17,12 +17,13 @@ #include #include -#include +#include #include #include using namespace std; using namespace isc::dns; +using namespace isc::util; namespace isc { namespace dns { diff --git a/src/lib/dns/rrttl.h b/src/lib/dns/rrttl.h index 695306ac7c4fce5ad31250708f94b5871857184b..17ec8919af0a053152ebbd2d9f0c022f81946c32 100644 --- a/src/lib/dns/rrttl.h +++ b/src/lib/dns/rrttl.h @@ -20,11 +20,14 @@ #include namespace isc { +namespace util { +class InputBuffer; +class OutputBuffer; +} + namespace dns { // forward declarations -class InputBuffer; -class OutputBuffer; class MessageRenderer; /// @@ -91,7 +94,7 @@ public: /// an exception of class \c IncompleteRRTTL will be thrown. /// /// \param buffer A buffer storing the wire format data. - explicit RRTTL(InputBuffer& buffer); + explicit RRTTL(isc::util::InputBuffer& buffer); /// //@} @@ -130,7 +133,7 @@ public: /// standard exception will be thrown. /// /// \param buffer An output buffer to store the wire data. - void toWire(OutputBuffer& buffer) const; + void toWire(isc::util::OutputBuffer& buffer) const; //@} /// diff --git a/src/lib/dns/rrtype-placeholder.h b/src/lib/dns/rrtype-placeholder.h index 76cb29db5acd224bd2ccbf8c27ceb7fa6850a879..1cb028c17776de70af67af6a678de90d3b9be13c 100644 --- a/src/lib/dns/rrtype-placeholder.h +++ b/src/lib/dns/rrtype-placeholder.h @@ -23,12 +23,15 @@ #include namespace isc { +namespace util { +class InputBuffer; +class OutputBuffer; +} + namespace dns { // forward declarations -class InputBuffer; -class OutputBuffer; -class MessageRenderer; +class AbstractMessageRenderer; /// /// \brief A standard DNS module exception that is thrown if an RRType object @@ -145,7 +148,7 @@ public: /// an exception of class \c IncompleteRRType will be thrown. /// /// \param buffer A buffer storing the wire format data. - explicit RRType(InputBuffer& buffer); + explicit RRType(isc::util::InputBuffer& buffer); /// /// We use the default copy constructor intentionally. //@} @@ -178,7 +181,7 @@ public: /// standard exception will be thrown. /// /// \param buffer An output buffer to store the wire data. - void toWire(MessageRenderer& renderer) const; + void toWire(AbstractMessageRenderer& renderer) const; /// \brief Render the \c RRType in the wire format. /// /// This method renders the type code in network byte order into the @@ -189,7 +192,7 @@ public: /// /// \param renderer DNS message rendering context that encapsulates the /// output buffer in which the RRType is to be stored. - void toWire(OutputBuffer& buffer) const; + void toWire(isc::util::OutputBuffer& buffer) const; //@} /// diff --git a/src/lib/dns/rrtype.cc b/src/lib/dns/rrtype.cc index 44377f57d79b6526e581c20de508484e3fd6d399..af077d45ef24bfde36ccf5ff6b18cddcbcbe6edc 100644 --- a/src/lib/dns/rrtype.cc +++ b/src/lib/dns/rrtype.cc @@ -19,14 +19,14 @@ #include -#include +#include #include #include #include using namespace std; +using namespace isc::util; using isc::dns::RRType; -using isc::dns::OutputBuffer; namespace isc { namespace dns { @@ -53,7 +53,7 @@ RRType::toWire(OutputBuffer& buffer) const { } void -RRType::toWire(MessageRenderer& renderer) const { +RRType::toWire(AbstractMessageRenderer& renderer) const { renderer.writeUint16(typecode_); } diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am index 2bd7c87422badff0dcb619ef96fb6e6dd8b2fa1a..fdd6e1eea04813d865f75f61c1ea7f4e7c01b72d 100644 --- a/src/lib/dns/tests/Makefile.am +++ b/src/lib/dns/tests/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = testdata . AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util AM_CPPFLAGS += -DTEST_DATA_SRCDIR=\"$(srcdir)/testdata\" AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/dns/tests/testdata\" AM_CXXFLAGS = $(B10_CXXFLAGS) @@ -17,15 +18,14 @@ 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 += edns_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 += dnssectime_unittest.cc run_unittests_SOURCES += opcode_unittest.cc run_unittests_SOURCES += rcode_unittest.cc run_unittests_SOURCES += rdata_unittest.h rdata_unittest.cc +run_unittests_SOURCES += rdatafields_unittest.cc run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc run_unittests_SOURCES += rdata_txt_unittest.cc rdata_mx_unittest.cc @@ -46,16 +46,13 @@ run_unittests_SOURCES += question_unittest.cc run_unittests_SOURCES += rrparamregistry_unittest.cc run_unittests_SOURCES += masterload_unittest.cc run_unittests_SOURCES += message_unittest.cc -run_unittests_SOURCES += base32hex_unittest.cc -run_unittests_SOURCES += base64_unittest.cc -run_unittests_SOURCES += hex_unittest.cc -run_unittests_SOURCES += sha1_unittest.cc run_unittests_SOURCES += tsigkey_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 = $(GTEST_LDADD) run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la endif diff --git a/src/lib/dns/tests/edns_unittest.cc b/src/lib/dns/tests/edns_unittest.cc index fb9a7c24f298d31b45addd87ca619517dee2e05c..26cc01c343a7d977c9021715203ef40cc116ebb2 100644 --- a/src/lib/dns/tests/edns_unittest.cc +++ b/src/lib/dns/tests/edns_unittest.cc @@ -16,7 +16,7 @@ #include -#include +#include #include #include #include @@ -35,6 +35,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; const uint8_t EDNS::SUPPORTED_VERSION; diff --git a/src/lib/dns/tests/message_unittest.cc b/src/lib/dns/tests/message_unittest.cc index 92adbc975027d976aa25124a0c22976e7804cd83..4031e4f40b7b27971c1d454f802f939a594fa121 100644 --- a/src/lib/dns/tests/message_unittest.cc +++ b/src/lib/dns/tests/message_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include #include @@ -35,6 +35,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; // diff --git a/src/lib/dns/tests/messagerenderer_unittest.cc b/src/lib/dns/tests/messagerenderer_unittest.cc index c3d3edbac12f434d61042b1c29e7d6c799696873..fe790fe837fdf84534114c0fd3157b11841eca1a 100644 --- a/src/lib/dns/tests/messagerenderer_unittest.cc +++ b/src/lib/dns/tests/messagerenderer_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include @@ -23,9 +23,9 @@ #include using isc::UnitTestUtil; -using isc::dns::OutputBuffer; using isc::dns::Name; using isc::dns::MessageRenderer; +using isc::util::OutputBuffer; namespace { class MessageRendererTest : public ::testing::Test { diff --git a/src/lib/dns/tests/name_unittest.cc b/src/lib/dns/tests/name_unittest.cc index 5daba9c1b083910cfa8cc9e2ca9f4fa603380ff3..6434229dd939a5d6f98f3e8cc78ad31ffef37f75 100644 --- a/src/lib/dns/tests/name_unittest.cc +++ b/src/lib/dns/tests/name_unittest.cc @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include @@ -31,6 +31,7 @@ using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; // // XXX: these are defined as class static constants, but some compilers diff --git a/src/lib/dns/tests/question_unittest.cc b/src/lib/dns/tests/question_unittest.cc index 59a4815173dc978b68f1688d0546fb98d3912f10..25fd75b4c6bc1b53b666e3376f01f477b338fe88 100644 --- a/src/lib/dns/tests/question_unittest.cc +++ b/src/lib/dns/tests/question_unittest.cc @@ -17,7 +17,7 @@ #include -#include +#include #include #include #include @@ -32,6 +32,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; namespace { class QuestionTest : public ::testing::Test { diff --git a/src/lib/dns/tests/rdata_cname_unittest.cc b/src/lib/dns/tests/rdata_cname_unittest.cc index e3137a7a271f9a6bb4adb41c7f648d6ee459e7db..d6b02aa49bef714627e35a682b5f00af16ee51d7 100644 --- a/src/lib/dns/tests/rdata_cname_unittest.cc +++ b/src/lib/dns/tests/rdata_cname_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -28,6 +28,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_dname_unittest.cc b/src/lib/dns/tests/rdata_dname_unittest.cc index c2384b6d8bbcc8792a7663fe66f3f0a55871f315..ebd9e0e04fdb84ae2d6fd0ed641e8d5453453e26 100644 --- a/src/lib/dns/tests/rdata_dname_unittest.cc +++ b/src/lib/dns/tests/rdata_dname_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -28,6 +28,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_dnskey_unittest.cc b/src/lib/dns/tests/rdata_dnskey_unittest.cc index e26bf57ff9cf3e81cef3a4a64962c4efa1608d6a..f0596ed989adbf5e05d6c3432ac9daf402115e0f 100644 --- a/src/lib/dns/tests/rdata_dnskey_unittest.cc +++ b/src/lib/dns/tests/rdata_dnskey_unittest.cc @@ -16,7 +16,7 @@ #include -#include +#include #include #include #include @@ -32,6 +32,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_ds_unittest.cc b/src/lib/dns/tests/rdata_ds_unittest.cc index d7e3f885cd32f9cb8b2e9d657c99af0a2c586480..59886208cfb1a286164bd1b21f4fbc17248f20bb 100644 --- a/src/lib/dns/tests/rdata_ds_unittest.cc +++ b/src/lib/dns/tests/rdata_ds_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include #include @@ -29,6 +29,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_in_a_unittest.cc b/src/lib/dns/tests/rdata_in_a_unittest.cc index 73028811461f7454ecb6db3bc70e4e73bb3f57dc..47e2bfa4807178f64f58907ccae280ecf086abb0 100644 --- a/src/lib/dns/tests/rdata_in_a_unittest.cc +++ b/src/lib/dns/tests/rdata_in_a_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -28,6 +28,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_in_aaaa_unittest.cc b/src/lib/dns/tests/rdata_in_aaaa_unittest.cc index c1953d67a12fea5aeb313b869a056acb4dd811c6..6fd4d0ed614b8a3671d37694ce7e8d382f12bf22 100644 --- a/src/lib/dns/tests/rdata_in_aaaa_unittest.cc +++ b/src/lib/dns/tests/rdata_in_aaaa_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -28,6 +28,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_mx_unittest.cc b/src/lib/dns/tests/rdata_mx_unittest.cc index dd7677db8940c686a4abcc5d1ccab165e1c06aba..c4c9757a35363d3d77f9fcfcc4224af345ce4dda 100644 --- a/src/lib/dns/tests/rdata_mx_unittest.cc +++ b/src/lib/dns/tests/rdata_mx_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -27,6 +27,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_ns_unittest.cc b/src/lib/dns/tests/rdata_ns_unittest.cc index 6d4a69e587bc635172808e1784f6fb7aa2620564..b8057831b9d33ebfb0ec1a4a68686435afd712e7 100644 --- a/src/lib/dns/tests/rdata_ns_unittest.cc +++ b/src/lib/dns/tests/rdata_ns_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -28,6 +28,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_nsec3_unittest.cc b/src/lib/dns/tests/rdata_nsec3_unittest.cc index 749e26232499b04de164217ff26c37e6f42434b7..441c6d8f47cf1e208aba1de0da4d06fb563eb786 100644 --- a/src/lib/dns/tests/rdata_nsec3_unittest.cc +++ b/src/lib/dns/tests/rdata_nsec3_unittest.cc @@ -16,9 +16,9 @@ #include -#include +#include +#include #include -#include #include #include #include @@ -34,6 +34,8 @@ using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; +using namespace isc::util::encode; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_nsec3param_unittest.cc b/src/lib/dns/tests/rdata_nsec3param_unittest.cc index 53e91269ca17e8beb8cc072ae3d8d4316a557976..8d802d6f7b71fd4d71938e52a836e593e375c89a 100644 --- a/src/lib/dns/tests/rdata_nsec3param_unittest.cc +++ b/src/lib/dns/tests/rdata_nsec3param_unittest.cc @@ -16,9 +16,9 @@ #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -34,6 +34,8 @@ using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; +using namespace isc::util::encode; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_nsec_unittest.cc b/src/lib/dns/tests/rdata_nsec_unittest.cc index 8286dee53039f219e5507bf40220dfd56be56733..5aa1e9c44468ff8a99903bbe8890720e7d0753b8 100644 --- a/src/lib/dns/tests/rdata_nsec_unittest.cc +++ b/src/lib/dns/tests/rdata_nsec_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include #include @@ -30,6 +30,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_opt_unittest.cc b/src/lib/dns/tests/rdata_opt_unittest.cc index be92b9189de40b495ff4681fa631081cd3a72f02..698d5863eb97f6ef31a28ea03c3f7da29f9933bd 100644 --- a/src/lib/dns/tests/rdata_opt_unittest.cc +++ b/src/lib/dns/tests/rdata_opt_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -27,6 +27,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_ptr_unittest.cc b/src/lib/dns/tests/rdata_ptr_unittest.cc index da13dcb372a0eaf00e6c366b0cef61db1d09325c..7f5de2056bd4057bfe08ec9cba6376f5175c8f40 100644 --- a/src/lib/dns/tests/rdata_ptr_unittest.cc +++ b/src/lib/dns/tests/rdata_ptr_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -28,6 +28,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; // diff --git a/src/lib/dns/tests/rdata_rp_unittest.cc b/src/lib/dns/tests/rdata_rp_unittest.cc index 52285f17c4b8af380bc9a41a16ca8074793cabb6..07f5a932aa1b12d87750cee4187cda40afff828f 100644 --- a/src/lib/dns/tests/rdata_rp_unittest.cc +++ b/src/lib/dns/tests/rdata_rp_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include @@ -25,6 +25,7 @@ using isc::UnitTestUtil; using namespace std; +using namespace isc::util; using namespace isc::dns; using namespace isc::dns::rdata; diff --git a/src/lib/dns/tests/rdata_rrsig_unittest.cc b/src/lib/dns/tests/rdata_rrsig_unittest.cc index 04d9469626cfa9614bd8e1502eb0efbad6f8d321..903021fb5e65d71d8ec172b4d1c92e1aadaad9a5 100644 --- a/src/lib/dns/tests/rdata_rrsig_unittest.cc +++ b/src/lib/dns/tests/rdata_rrsig_unittest.cc @@ -14,8 +14,8 @@ #include -#include -#include +#include +#include #include #include #include @@ -31,6 +31,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_soa_unittest.cc b/src/lib/dns/tests/rdata_soa_unittest.cc index 6858a0ba9bbd75ff6a358fad2db7a0bf1d3657ba..63fe1f70980bcf37ec70565bedd37fa32d003b1b 100644 --- a/src/lib/dns/tests/rdata_soa_unittest.cc +++ b/src/lib/dns/tests/rdata_soa_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -27,6 +27,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_tsig_unittest.cc b/src/lib/dns/tests/rdata_tsig_unittest.cc index 5c9a14f8540c7871788ce9e61e334c49abea1339..76f91a6fcc75a1db4c9e3b7b75df4b0b538b8748 100644 --- a/src/lib/dns/tests/rdata_tsig_unittest.cc +++ b/src/lib/dns/tests/rdata_tsig_unittest.cc @@ -16,7 +16,7 @@ #include -#include +#include #include #include #include @@ -32,6 +32,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_txt_unittest.cc b/src/lib/dns/tests/rdata_txt_unittest.cc index 54993e1baa99c23bf269e498563b4f89d81b7856..e5f8ac9edd87f357c1de39fbc17a160ebf7ed116 100644 --- a/src/lib/dns/tests/rdata_txt_unittest.cc +++ b/src/lib/dns/tests/rdata_txt_unittest.cc @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -28,6 +28,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rdata_unittest.cc b/src/lib/dns/tests/rdata_unittest.cc index 5ce4c03804326dae92ca3c4e200375b1a3445dcd..fa791dc053e83cabfe9160f5139eb15ab21a6e42 100644 --- a/src/lib/dns/tests/rdata_unittest.cc +++ b/src/lib/dns/tests/rdata_unittest.cc @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include @@ -31,6 +31,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace isc { diff --git a/src/lib/dns/tests/rdata_unittest.h b/src/lib/dns/tests/rdata_unittest.h index 748c8d3fa4959ac25f79a8a75ab9c6989b94687b..1bc0fa4497916cd91d75f5038d5c77cbe822abe7 100644 --- a/src/lib/dns/tests/rdata_unittest.h +++ b/src/lib/dns/tests/rdata_unittest.h @@ -15,7 +15,7 @@ #ifndef __RDATA_UNITTEST_H #define __RDATA_UNITTEST_H 1 -#include +#include #include #include #include @@ -23,6 +23,8 @@ #include +using namespace isc::util; + namespace isc { namespace dns { namespace rdata { diff --git a/src/lib/dns/tests/rdatafields_unittest.cc b/src/lib/dns/tests/rdatafields_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..d6192209ff6fa029e82f1fc2196f87b65c749cae --- /dev/null +++ b/src/lib/dns/tests/rdatafields_unittest.cc @@ -0,0 +1,380 @@ +// 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. + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using isc::UnitTestUtil; +using namespace std; +using namespace isc::dns; +using namespace isc::dns::rdata; +using isc::util::OutputBuffer; +using isc::util::InputBuffer; + +namespace { +class RdataFieldsTest : public ::testing::Test { +protected: + RdataFieldsTest() : obuffer(0), renderer_buffer(0), + renderer(renderer_buffer), + ns_name("example.com"), + other_name("www.example.com") + {} + void constructCommonTests(const RdataFields& fields, + const uint8_t* const expected_data, + const size_t expected_data_len); + void constructCommonTestsNS(const RdataFields& fields); + void constructCommonTestsTXT(const RdataFields& fields); + void constructCommonTestsRRSIG(const RdataFields& fields); + void constructCommonTestsOPT(const RdataFields& fields); + OutputBuffer obuffer; + OutputBuffer renderer_buffer; + MessageRenderer renderer; + const Name ns_name; + const Name other_name; + vector expected_wire; + vector fields_wire; +}; + +const uint8_t in_a_data[] = { 192, 0, 2, 1 }; +// binary representation of example.com. +const uint8_t ns_data[] = { 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00 }; + +// +// IN/A RDATA: fixed length, single data field +// +void +RdataFieldsTest::constructCommonTests(const RdataFields& fields, + const uint8_t* const expected_data, + const size_t expected_data_len) +{ + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, expected_data, + expected_data_len, fields.getData(), + fields.getDataLength()); + EXPECT_EQ(sizeof(RdataFields::FieldSpec), fields.getFieldSpecDataSize()); + EXPECT_EQ(1, fields.getFieldCount()); + EXPECT_EQ(RdataFields::DATA, fields.getFieldSpec(0).type); + EXPECT_EQ(4, fields.getFieldSpec(0).len); + + fields.toWire(obuffer); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, expected_data, + expected_data_len, obuffer.getData(), + obuffer.getLength()); + + fields.toWire(renderer); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, expected_data, + expected_data_len, renderer.getData(), + renderer.getLength()); +} + +TEST_F(RdataFieldsTest, constructFromRdata) { + const RdataFields fields(in::A("192.0.2.1")); + constructCommonTests(fields, in_a_data, sizeof(in_a_data)); +} + +TEST_F(RdataFieldsTest, constructFromParams) { + const RdataFields::FieldSpec spec(RdataFields::DATA, 4); + const RdataFields fields(&spec, sizeof(spec), in_a_data, + sizeof(in_a_data)); + constructCommonTests(fields, in_a_data, sizeof(in_a_data)); +} + +// +// NS RDATA: containing a compressible name. +// +void +RdataFieldsTest::constructCommonTestsNS(const RdataFields& fields) { + EXPECT_EQ(sizeof(RdataFields::FieldSpec), fields.getFieldSpecDataSize()); + EXPECT_EQ(1, fields.getFieldCount()); + EXPECT_EQ(RdataFields::COMPRESSIBLE_NAME, fields.getFieldSpec(0).type); + EXPECT_EQ(ns_name.getLength(), fields.getFieldSpec(0).len); + + expected_wire.clear(); + UnitTestUtil::readWireData("rdatafields1.wire", expected_wire); + other_name.toWire(obuffer); + fields.toWire(obuffer); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], + expected_wire.size(), obuffer.getData(), + obuffer.getLength()); + + expected_wire.clear(); + UnitTestUtil::readWireData("rdatafields2.wire", expected_wire); + other_name.toWire(renderer); + fields.toWire(renderer); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], + expected_wire.size(), renderer.getData(), + renderer.getLength()); +} + +TEST_F(RdataFieldsTest, constructFromRdataNS) { + const RdataFields fields_ns((generic::NS(ns_name))); + constructCommonTestsNS(fields_ns); +} + +TEST_F(RdataFieldsTest, constructFromParamsNS) { + const RdataFields::FieldSpec spec(RdataFields::COMPRESSIBLE_NAME, + sizeof(ns_data)); + const RdataFields fields_ns(&spec, sizeof(spec), ns_data, sizeof(ns_data)); + constructCommonTestsNS(fields_ns); +} + +// +// TXT RDATA: multiple fields, lengths vary +// +void +RdataFieldsTest::constructCommonTestsTXT(const RdataFields& fields) { + // Since all fields are plain data, they are handled as a single data + // field. + EXPECT_EQ(sizeof(RdataFields::FieldSpec), fields.getFieldSpecDataSize()); + EXPECT_EQ(1, fields.getFieldCount()); + EXPECT_EQ(RdataFields::DATA, fields.getFieldSpec(0).type); + EXPECT_EQ(expected_wire.size(), fields.getFieldSpec(0).len); + + fields.toWire(obuffer); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], + expected_wire.size(), obuffer.getData(), + obuffer.getLength()); + + fields.toWire(renderer); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], + expected_wire.size(), renderer.getData(), + renderer.getLength()); +} + +TEST_F(RdataFieldsTest, constructFromRdataTXT) { + UnitTestUtil::readWireData("rdatafields3.wire", expected_wire); + InputBuffer ibuffer(&expected_wire[0], expected_wire.size()); + const uint16_t rdlen = ibuffer.readUint16(); + const RdataFields fields(generic::TXT(ibuffer, rdlen)); + + // drop the RDLEN part + expected_wire.erase(expected_wire.begin(), expected_wire.begin() + 2); + + constructCommonTestsTXT(fields); +} + +TEST_F(RdataFieldsTest, constructFromParamsTXT) { + UnitTestUtil::readWireData("rdatafields3.wire", expected_wire); + expected_wire.erase(expected_wire.begin(), expected_wire.begin() + 2); + const RdataFields::FieldSpec spec(RdataFields::DATA, expected_wire.size()); + const RdataFields fields(&spec, sizeof(spec), &expected_wire[0], + expected_wire.size()); + constructCommonTestsTXT(fields); +} + +// +// RRSIG: multiple fields, with an incompressible name +// +void +RdataFieldsTest::constructCommonTestsRRSIG(const RdataFields& fields) { + // In terms of RdataFields RRSIG RDATA consists of 3 fields: + // - 18-byte data field (from the "type covered" field to "key tag" field) + // - an incompressible name field (for the signer's name field). + // this is a variable length field. In this test it's a 13-byte field. + // - a variable-length data field for the signature. In this tests + // it's a 15-byte field. + EXPECT_EQ(3 * sizeof(RdataFields::FieldSpec), + fields.getFieldSpecDataSize()); + EXPECT_EQ(3, fields.getFieldCount()); + EXPECT_EQ(RdataFields::DATA, fields.getFieldSpec(0).type); + EXPECT_EQ(18, fields.getFieldSpec(0).len); + EXPECT_EQ(RdataFields::INCOMPRESSIBLE_NAME, fields.getFieldSpec(1).type); + EXPECT_EQ(13, fields.getFieldSpec(1).len); + EXPECT_EQ(RdataFields::DATA, fields.getFieldSpec(2).type); + EXPECT_EQ(15, fields.getFieldSpec(2).len); + + expected_wire.clear(); + UnitTestUtil::readWireData("rdatafields5.wire", expected_wire); + Name("com").toWire(obuffer); + obuffer.writeUint16(fields.getDataLength()); + fields.toWire(obuffer); + other_name.toWire(obuffer); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], + expected_wire.size(), obuffer.getData(), + obuffer.getLength()); + + expected_wire.clear(); + UnitTestUtil::readWireData("rdatafields6.wire", expected_wire); + Name("com").toWire(renderer); + renderer.writeUint16(fields.getDataLength()); + fields.toWire(renderer); // the signer field won't be compressed + other_name.toWire(renderer); // but will be used as a compression target + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], + expected_wire.size(), renderer.getData(), + renderer.getLength()); +} + +TEST_F(RdataFieldsTest, constructFromRdataRRSIG) { + UnitTestUtil::readWireData("rdatafields4.wire", expected_wire); + InputBuffer ibuffer(&expected_wire[0], expected_wire.size()); + const uint16_t rdlen = ibuffer.readUint16(); + const RdataFields fields(generic::RRSIG(ibuffer, rdlen)); + + // drop the RDLEN part + expected_wire.erase(expected_wire.begin(), expected_wire.begin() + 2); + + constructCommonTestsRRSIG(fields); +} + +TEST_F(RdataFieldsTest, constructFromParamsRRSIG) { + UnitTestUtil::readWireData("rdatafields4.wire", fields_wire); + fields_wire.erase(fields_wire.begin(), fields_wire.begin() + 2); + + const RdataFields::FieldSpec specs[] = { + RdataFields::FieldSpec(RdataFields::DATA, 18), + RdataFields::FieldSpec(RdataFields::INCOMPRESSIBLE_NAME, 13), + RdataFields::FieldSpec(RdataFields::DATA, 15) + }; + const RdataFields fields(specs, sizeof(specs), &fields_wire[0], + fields_wire.size()); + constructCommonTestsRRSIG(fields); +} + +TEST_F(RdataFieldsTest, convertRdatatoParams) { + // Confirm we can restore the original data from the serialized data. + // We use RRSIG as a relatively complicated field structure. + UnitTestUtil::readWireData("rdatafields4.wire", expected_wire); + InputBuffer ibuffer(&expected_wire[0], expected_wire.size()); + const uint16_t rdlen = ibuffer.readUint16(); + const RdataFields fields(generic::RRSIG(ibuffer, rdlen)); + + expected_wire.erase(expected_wire.begin(), expected_wire.begin() + 2); + + // Copy the data in separate storage + vector spec_store(fields.getFieldSpecDataSize()); + void* cp_spec = &spec_store[0]; + memcpy(cp_spec, fields.getFieldSpecData(), spec_store.size()); + vector data_store(fields.getDataLength()); + memcpy(&data_store[0], fields.getData(), fields.getDataLength()); + + // Restore the data in the form of RdataFields + const RdataFields fields_byparams(cp_spec, fields.getFieldSpecDataSize(), + &data_store[0], fields.getDataLength()); + + // Check it's valid + constructCommonTestsRRSIG(fields_byparams); +} + +// +// OPT: an empty RDATA +// +void +RdataFieldsTest::constructCommonTestsOPT(const RdataFields& fields) { + EXPECT_EQ(0, fields.getFieldSpecDataSize()); + EXPECT_EQ(0, fields.getFieldCount()); + EXPECT_EQ(0, fields.getDataLength()); + EXPECT_EQ((const uint8_t*) NULL, fields.getData()); + fields.toWire(obuffer); + EXPECT_EQ(0, obuffer.getLength()); + fields.toWire(renderer); + EXPECT_EQ(0, renderer.getLength()); +} + +TEST_F(RdataFieldsTest, constructFromRdataOPT) { + InputBuffer ibuffer(NULL, 0); + const RdataFields fields(generic::OPT(ibuffer, 0)); + constructCommonTestsOPT(fields); +} + +TEST_F(RdataFieldsTest, constructFromParamsOPT) { + const RdataFields fields(NULL, 0, NULL, 0); + constructCommonTestsOPT(fields); +} + +// Invalid input to the "from parameter" constructor: sum of the field lengths +// is not equal to the data length. +TEST_F(RdataFieldsTest, invalidFieldLength) { + UnitTestUtil::readWireData("rdatafields4.wire", fields_wire); + fields_wire.erase(fields_wire.begin(), fields_wire.begin() + 2); + + const RdataFields::FieldSpec specs[] = { + RdataFields::FieldSpec(RdataFields::DATA, 18), + RdataFields::FieldSpec(RdataFields::INCOMPRESSIBLE_NAME, 13), + RdataFields::FieldSpec(RdataFields::DATA, 14) + }; + // sum of field len < data len + EXPECT_THROW(RdataFields(specs, 3, &fields_wire[0], fields_wire.size()), + isc::InvalidParameter); + // sum of field len > data len + EXPECT_THROW(RdataFields(specs, 3, &fields_wire[0], + fields_wire.size() - 2), + isc::InvalidParameter); +} + +// Invalid input to the "from parameter" constructor: NULL vs length mismatch +TEST_F(RdataFieldsTest, mismatchFieldLengthAndData) { + const unsigned char dummy_data = 0; + const RdataFields::FieldSpec dummy_spec(RdataFields::DATA, 1); + + EXPECT_THROW(RdataFields(NULL, 1, &dummy_data, 1), isc::InvalidParameter); + EXPECT_THROW(RdataFields(&dummy_spec, 0, NULL, 0), isc::InvalidParameter); + EXPECT_THROW(RdataFields(&dummy_spec, 1, NULL, 1), isc::InvalidParameter); + EXPECT_THROW(RdataFields(NULL, 0, &dummy_data, 0), isc::InvalidParameter); +} + +// Bogus input to getFieldSpec() +TEST_F(RdataFieldsTest, getFieldSpecWithBadFieldId) { + const RdataFields fields_in_a(in::A("192.0.2.1")); + EXPECT_THROW(fields_in_a.getFieldSpec(1), isc::OutOfRange); +} + +// Tests for unexpected methods in RdataFieldComposerTest. Confirm +// a call to these methods triggers an exception. Expected methods are +// tested via other tests above. +class DummyRdata : public Rdata { +public: + enum Mode { CLEAR, SKIP, TRIM }; + explicit DummyRdata(Mode mode) : mode_(mode) {} + DummyRdata(const DummyRdata& source) : Rdata(), mode_(source.mode_) {} + virtual ~DummyRdata() {} + virtual void toWire(AbstractMessageRenderer& renderer) const { + // call the unexpected method corresponding to the test mode. + // method parameters don't matter. + switch (mode_) { + case CLEAR: + renderer.clear(); + break; + case SKIP: + renderer.skip(2); + break; + case TRIM: + renderer.trim(2); + break; + } + } + + // These are defined only to make the compiler happy. We don't use them + // for the test. + virtual string toText() const { return (""); } + virtual void toWire(OutputBuffer&) const {} + virtual int compare(const Rdata&) const { return (0); } +private: + const int mode_; +}; + +TEST(RdataFieldComposerTest, unusedMethods) { + EXPECT_THROW(RdataFields(DummyRdata(DummyRdata::CLEAR)), isc::Unexpected); +} +} diff --git a/src/lib/dns/tests/rrclass_unittest.cc b/src/lib/dns/tests/rrclass_unittest.cc index 4eeb1e07fe8a23d159c03d4c919fd4ba8827a93e..15f9a8c6e176c2019008323864716f36c697b260 100644 --- a/src/lib/dns/tests/rrclass_unittest.cc +++ b/src/lib/dns/tests/rrclass_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include @@ -23,6 +23,7 @@ using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; namespace { class RRClassTest : public ::testing::Test { diff --git a/src/lib/dns/tests/rrparamregistry_unittest.cc b/src/lib/dns/tests/rrparamregistry_unittest.cc index a75eed5a9b4a6976383e066bc12c7a86a2f2d041..d2bec5c0d40ee458aaa97def4cc334c14a9e73ac 100644 --- a/src/lib/dns/tests/rrparamregistry_unittest.cc +++ b/src/lib/dns/tests/rrparamregistry_unittest.cc @@ -27,6 +27,7 @@ using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc index c704cc815c545dce783ade3d123d4e9f2e29d191..f9513411c73dd735a09ac5cf69bcd599f5be5e1e 100644 --- a/src/lib/dns/tests/rrset_unittest.cc +++ b/src/lib/dns/tests/rrset_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include #include @@ -32,6 +32,7 @@ using isc::UnitTestUtil; using namespace std; using namespace isc::dns; +using namespace isc::util; using namespace isc::dns::rdata; namespace { diff --git a/src/lib/dns/tests/rrttl_unittest.cc b/src/lib/dns/tests/rrttl_unittest.cc index b8f5ac241b81a48ba22a88612a597ffcbb850eda..fe75eb62e5982c38cbfe609c8130e6354fa219da 100644 --- a/src/lib/dns/tests/rrttl_unittest.cc +++ b/src/lib/dns/tests/rrttl_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include @@ -23,6 +23,7 @@ using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; namespace { class RRTTLTest : public ::testing::Test { diff --git a/src/lib/dns/tests/rrtype_unittest.cc b/src/lib/dns/tests/rrtype_unittest.cc index 6da7381a58a8f1d9e40f227dadec2d3564e8a178..12f6001f924998c9c2130e826fb265e6aa9ac9a8 100644 --- a/src/lib/dns/tests/rrtype_unittest.cc +++ b/src/lib/dns/tests/rrtype_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include #include @@ -23,6 +23,7 @@ using namespace std; using namespace isc; using namespace isc::dns; +using namespace isc::util; namespace { class RRTypeTest : public ::testing::Test { diff --git a/src/lib/dns/tests/testdata/Makefile.am b/src/lib/dns/tests/testdata/Makefile.am index 1dc1c003cc91bc85a59e4292627fdb3fdff75076..31771bb6cbc2f4cab9b62e88cb9f578630c88b19 100644 --- a/src/lib/dns/tests/testdata/Makefile.am +++ b/src/lib/dns/tests/testdata/Makefile.am @@ -4,6 +4,8 @@ BUILT_SOURCES = edns_toWire1.wire edns_toWire2.wire edns_toWire3.wire BUILT_SOURCES += edns_toWire4.wire BUILT_SOURCES += message_fromWire10.wire message_fromWire11.wire BUILT_SOURCES += name_toWire5.wire name_toWire6.wire +BUILT_SOURCES += rdatafields1.wire rdatafields2.wire rdatafields3.wire +BUILT_SOURCES += rdatafields4.wire rdatafields5.wire rdatafields6.wire BUILT_SOURCES += rdata_nsec_fromWire4.wire rdata_nsec_fromWire5.wire BUILT_SOURCES += rdata_nsec_fromWire6.wire rdata_nsec_fromWire7.wire BUILT_SOURCES += rdata_nsec_fromWire8.wire rdata_nsec_fromWire9.wire @@ -52,6 +54,8 @@ EXTRA_DIST += name_fromWire13 name_fromWire14 EXTRA_DIST += name_toWire1 name_toWire2 name_toWire3 name_toWire4 EXTRA_DIST += name_toWire5.spec name_toWire6.spec EXTRA_DIST += question_fromWire question_toWire1 question_toWire2 +EXTRA_DIST += rdatafields1.spec rdatafields2.spec rdatafields3.spec +EXTRA_DIST += rdatafields4.spec rdatafields5.spec rdatafields6.spec EXTRA_DIST += rdata_cname_fromWire rdata_dname_fromWire rdata_dnskey_fromWire EXTRA_DIST += rdata_ds_fromWire rdata_in_a_fromWire rdata_in_aaaa_fromWire EXTRA_DIST += rdata_mx_fromWire rdata_mx_toWire1 rdata_mx_toWire2 diff --git a/src/lib/dns/tests/testdata/rdatafields1.spec b/src/lib/dns/tests/testdata/rdatafields1.spec new file mode 100644 index 0000000000000000000000000000000000000000..6e105fbe6cf6f759740ab5de8758660efc0a77cf --- /dev/null +++ b/src/lib/dns/tests/testdata/rdatafields1.spec @@ -0,0 +1,10 @@ +# +# A sequence of names that could be compressed (but not compressed) +# + +[custom] +sections: name/1:name/2 +[name/1] +name: www.example.com +[name/2] +name: example.com diff --git a/src/lib/dns/tests/testdata/rdatafields2.spec b/src/lib/dns/tests/testdata/rdatafields2.spec new file mode 100644 index 0000000000000000000000000000000000000000..920dc956e6c1cb57e173f0242388fe3f78782614 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdatafields2.spec @@ -0,0 +1,11 @@ +# +# A sequence of names that can be compressed. +# + +[custom] +sections: name/1:name/2 +[name/1] +name: www.example.com +[name/2] +name: '' +pointer: 4 diff --git a/src/lib/dns/tests/testdata/rdatafields3.spec b/src/lib/dns/tests/testdata/rdatafields3.spec new file mode 100644 index 0000000000000000000000000000000000000000..b37fca3483f2b7e8e9686c80bcb2e83c13ec72b6 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdatafields3.spec @@ -0,0 +1,11 @@ +# +# TXT RDATA with multiple character-strings. +# + +[custom] +sections: txt +[txt] +nstring: 3 +string0: 'first string' +string1: 'second string' +string2: 'last string' diff --git a/src/lib/dns/tests/testdata/rdatafields4.spec b/src/lib/dns/tests/testdata/rdatafields4.spec new file mode 100644 index 0000000000000000000000000000000000000000..24b59aaeb305bede357094e604c632064d28d5e5 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdatafields4.spec @@ -0,0 +1,7 @@ +# +# Simple form of RRSIG (all fields use the default of generator script) +# + +[custom] +sections: rrsig +[rrsig] diff --git a/src/lib/dns/tests/testdata/rdatafields5.spec b/src/lib/dns/tests/testdata/rdatafields5.spec new file mode 100644 index 0000000000000000000000000000000000000000..2c7828250e8e2435ffb27bfc55cfa37bf69a01e2 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdatafields5.spec @@ -0,0 +1,12 @@ +# +# Names and RDATA (RRSIG) with an incompressible name. All names are +# rendered without compression. +# + +[custom] +sections: name/1:rrsig:name/2 +[name/1] +name: com +[rrsig] +[name/2] +name: www.example.com diff --git a/src/lib/dns/tests/testdata/rdatafields6.spec b/src/lib/dns/tests/testdata/rdatafields6.spec new file mode 100644 index 0000000000000000000000000000000000000000..f9f0da18f7c8759b0c8a6643aaf8964ccb2f6142 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdatafields6.spec @@ -0,0 +1,13 @@ +# +# Names and RDATA (RRSIG) with an incompressible name. The name in RRSIG +# isn't compressed, but it's used as the compression target. +# + +[custom] +sections: name/1:rrsig:name/2 +[name/1] +name: com +[rrsig] +[name/2] +name: www +pointer: 25 diff --git a/src/lib/dns/util/README b/src/lib/dns/util/README deleted file mode 100644 index 1b9d1e8f9f09e8e37b95ff1e1ab8e436d92899a8..0000000000000000000000000000000000000000 --- a/src/lib/dns/util/README +++ /dev/null @@ -1,31 +0,0 @@ -This "util" directory is provided for utility header files and -implementations that are internally used in the DNS library -(libdns++). - -The functionality provided in these tools is generally available in -other external or perhaps system supplied libraries. The basic -development policy of BIND 10 is to avoid "reinventing wheels" unless -they belong to the exact technology area that BIND 10 targets (e.g., -DNS). However, libdns++ is a very core part of BIND 10, and is also -intended to be used as a public library, so dependency from libdns++ -to external libraries should be minimized. The utilities in this -directory are provided balancing two policies and as a kind of -compromise. - -The header files in this directory are therefore not intended to be -installed. Likewise, classes and public functions defined in this -directory are not intended to be used outside libdns++, although we -cannot prohibit it at the language level. - -They are not even expected to be used in other modules of BIND 10 than -libdns++ based on the basic policy explained above. Other modules -should only rely on the DNS specific interface that may internally -rely on these utility interfaces, or should use external libraries if -the other module really needs to use the utility feature directly. -There seem to be some violations as of this writing, but we should -eventually fix it. A notable example is the SHA1 interfaces. They -are defined here in the context of NSEC3 processing, but, in fact, -they are not even used from any of the other libdns++ classes or -functions. The SHA1 related interfaces should be moved to the -application that needs it or the application should only access it -through DNS specific interfaces defined in libdns++. diff --git a/src/lib/log/Makefile.am b/src/lib/log/Makefile.am index d941b0131c21b408dd4bb0fb9bdf9b7b1d69bc89..57705648d3ef1d04d8b1b62c7811ff090dd01bb6 100644 --- a/src/lib/log/Makefile.am +++ b/src/lib/log/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = . compiler tests AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util CLEANFILES = *.gcno *.gcda @@ -10,7 +11,6 @@ lib_LTLIBRARIES = liblog.la liblog_la_SOURCES = liblog_la_SOURCES += debug_levels.h logger_levels.h liblog_la_SOURCES += dummylog.h dummylog.cc -liblog_la_SOURCES += filename.h filename.cc liblog_la_SOURCES += logger.cc logger.h liblog_la_SOURCES += logger_impl.cc logger_impl.h liblog_la_SOURCES += logger_support.cc logger_support.h @@ -21,7 +21,6 @@ liblog_la_SOURCES += message_initializer.cc message_initializer.h liblog_la_SOURCES += message_reader.cc message_reader.h liblog_la_SOURCES += message_types.h liblog_la_SOURCES += root_logger_name.cc root_logger_name.h -liblog_la_SOURCES += strutil.h strutil.cc EXTRA_DIST = README EXTRA_DIST += messagedef.mes @@ -39,3 +38,4 @@ if USE_CLANGPP liblog_la_CXXFLAGS += -Wno-error endif liblog_la_CPPFLAGS = $(AM_CPPFLAGS) +liblog_la_LIBADD = $(top_builddir)/src/lib/util/libutil.la diff --git a/src/lib/log/compiler/Makefile.am b/src/lib/log/compiler/Makefile.am index 9343793f7c56b6c6467336813fa038f6a78396b1..d51ba054c1959ea1484696816d7e7ceacc0d3b51 100644 --- a/src/lib/log/compiler/Makefile.am +++ b/src/lib/log/compiler/Makefile.am @@ -2,6 +2,7 @@ SUBDIRS = . AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util AM_CPPFLAGS += $(BOOST_INCLUDES) AM_CXXFLAGS = $(B10_CXXFLAGS) @@ -15,4 +16,5 @@ CLEANFILES = *.gcno *.gcda noinst_PROGRAMS = message message_SOURCES = message.cc message_LDADD = $(top_builddir)/src/lib/log/liblog.la +message_LDADD += $(top_builddir)/src/lib/util/libutil.la diff --git a/src/lib/log/compiler/message.cc b/src/lib/log/compiler/message.cc index 6f9c4e0e2de0485e1b30fa23893f9594f06c9e64..ef4bafd573531e556e3c6c361e1db73de2194539 100644 --- a/src/lib/log/compiler/message.cc +++ b/src/lib/log/compiler/message.cc @@ -25,17 +25,19 @@ #include #include -#include +#include +#include + #include #include #include #include -#include #include using namespace std; using namespace isc::log; +using namespace isc::util; static const char* VERSION = "1.0-0"; @@ -105,7 +107,7 @@ currentTime() { // Convert to string and strip out the trailing newline string current_time = buffer; - return isc::strutil::trim(current_time); + return isc::util::str::trim(current_time); } @@ -125,7 +127,7 @@ sentinel(Filename& file) { string name = file.name(); string ext = file.extension(); string sentinel_text = "__" + name + "_" + ext.substr(1); - isc::strutil::uppercase(sentinel_text); + isc::util::str::uppercase(sentinel_text); return sentinel_text; } @@ -206,7 +208,7 @@ splitNamespace(string ns) { // ... and return the vector of namespace components split on the single // colon. - return isc::strutil::tokens(ns, ":"); + return isc::util::str::tokens(ns, ":"); } @@ -535,7 +537,7 @@ main(int argc, char* argv[]) { text += global.getText(e.id()); // Format with arguments - text = isc::strutil::format(text, e.arguments()); + text = isc::util::str::format(text, e.arguments()); cerr << text << "\n"; return 1; diff --git a/src/lib/log/logger.cc b/src/lib/log/logger.cc index a2465deabe31cf314880c14f3cf2ead89f5bf884..99dc3a1f166d35869df0541956a6fd579d60eafd 100644 --- a/src/lib/log/logger.cc +++ b/src/lib/log/logger.cc @@ -20,7 +20,8 @@ #include #include #include -#include + +#include using namespace std; diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc index 4b19360e313cca73e57640c1a0992e29245a0552..41153e9affd0df5fb2c02cbc6328c3a1ccb343dd 100644 --- a/src/lib/log/logger_impl.cc +++ b/src/lib/log/logger_impl.cc @@ -26,7 +26,8 @@ #include #include #include -#include + +#include using namespace std; diff --git a/src/lib/log/logger_impl_log4cxx.cc b/src/lib/log/logger_impl_log4cxx.cc index 404fd035e78dd955610dc897cf777c2425f78e82..afe2d56ee41a853a4e1f0e1a479708cf25c8e467 100644 --- a/src/lib/log/logger_impl_log4cxx.cc +++ b/src/lib/log/logger_impl_log4cxx.cc @@ -27,9 +27,10 @@ #include #include #include -#include #include +#include + using namespace std; namespace isc { diff --git a/src/lib/log/message_reader.cc b/src/lib/log/message_reader.cc index 4402b0ea91031114450abbf6a51e0ca8d08b6f92..72813467458f5b0b60e99eebeefed24de0fcf11c 100644 --- a/src/lib/log/message_reader.cc +++ b/src/lib/log/message_reader.cc @@ -21,7 +21,7 @@ #include #include #include -#include +#include using namespace std; @@ -69,7 +69,7 @@ void MessageReader::processLine(const string& line, MessageReader::Mode mode) { // Get rid of leading and trailing spaces - string text = isc::strutil::trim(line); + string text = isc::util::str::trim(line); if (text.empty()) { ; // Ignore blank lines @@ -93,10 +93,10 @@ MessageReader::parseDirective(const std::string& text) { // Break into tokens - vector tokens = isc::strutil::tokens(text); + vector tokens = isc::util::str::tokens(text); // Uppercase directive and branch on valid ones - isc::strutil::uppercase(tokens[0]); + isc::util::str::uppercase(tokens[0]); if (tokens[0] == string("$PREFIX")) { parsePrefix(tokens); } else if (tokens[0] == string("$NAMESPACE")) { @@ -123,7 +123,7 @@ MessageReader::parsePrefix(const vector& tokens) { // As a style, we are going to have the symbols in uppercase string prefix = tokens[1]; - isc::strutil::uppercase(prefix); + isc::util::str::uppercase(prefix); // Token is potentially valid providing it only contains alphabetic // and numeric characters (and underscores) and does not start with a diff --git a/src/lib/log/tests/Makefile.am b/src/lib/log/tests/Makefile.am index 18457065eed77aac8fad06073a04d1e77d5cc371..b9fe150f9298dd7b89123825be65bff6c34d27ed 100644 --- a/src/lib/log/tests/Makefile.am +++ b/src/lib/log/tests/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = . AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util AM_CXXFLAGS = $(B10_CXXFLAGS) if USE_STATIC_LINK @@ -15,13 +16,11 @@ TESTS = if HAVE_GTEST TESTS += run_unittests run_unittests_SOURCES = root_logger_name_unittest.cc -run_unittests_SOURCES += filename_unittest.cc run_unittests_SOURCES += logger_unittest.cc run_unittests_SOURCES += message_dictionary_unittest.cc run_unittests_SOURCES += message_reader_unittest.cc run_unittests_SOURCES += message_initializer_unittest.cc run_unittests_SOURCES += message_initializer_unittest_2.cc -run_unittests_SOURCES += strutil_unittest.cc run_unittests_SOURCES += run_unittests.cc run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) @@ -29,6 +28,7 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) run_unittests_LDADD = $(GTEST_LDADD) run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la endif TESTS += logger_support_test @@ -36,6 +36,7 @@ logger_support_test_SOURCES = logger_support_test.cc logger_support_test_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) logger_support_test_LDFLAGS = $(AM_LDFLAGS) logger_support_test_LDADD = $(top_builddir)/src/lib/log/liblog.la +logger_support_test_LDADD += $(top_builddir)/src/lib/util/libutil.la noinst_PROGRAMS = $(TESTS) diff --git a/src/lib/nsas/Makefile.am b/src/lib/nsas/Makefile.am index 43300f6b97609866706131b87ec43c89d31b449a..5f05f1b22d868de4343a684456efba557c68aee9 100644 --- a/src/lib/nsas/Makefile.am +++ b/src/lib/nsas/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = . tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG) AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas AM_CPPFLAGS += $(SQLITE_CFLAGS) AM_CXXFLAGS = $(B10_CXXFLAGS) @@ -25,9 +26,7 @@ libnsas_la_SOURCES += asiolink.h libnsas_la_SOURCES += hash.cc hash.h libnsas_la_SOURCES += hash_deleter.h libnsas_la_SOURCES += hash_key.cc hash_key.h -libnsas_la_SOURCES += locks.h libnsas_la_SOURCES += hash_table.h -libnsas_la_SOURCES += lru_list.h libnsas_la_SOURCES += nameserver_address_store.cc nameserver_address_store.h libnsas_la_SOURCES += nameserver_address.h nameserver_address.cc libnsas_la_SOURCES += nameserver_entry.cc nameserver_entry.h @@ -36,7 +35,6 @@ libnsas_la_SOURCES += nsas_entry.h nsas_types.h libnsas_la_SOURCES += zone_entry.cc zone_entry.h libnsas_la_SOURCES += fetchable.h libnsas_la_SOURCES += address_request_callback.h -libnsas_la_SOURCES += random_number_generator.h libnsas_la_SOURCES += glue_hints.h glue_hints.cc CLEANFILES = *.gcno *.gcda diff --git a/src/lib/nsas/glue_hints.cc b/src/lib/nsas/glue_hints.cc index d4c653aa4309a7522b02b7856d1c921c74f06efe..02c27eee28bcce0110ff9a9ab99cc847296c9990 100644 --- a/src/lib/nsas/glue_hints.cc +++ b/src/lib/nsas/glue_hints.cc @@ -58,7 +58,7 @@ namespace { const std::string ns_name = rrset->getName().toText(); RdataIteratorPtr rdi = rrset->getRdataIterator(); while (!rdi->isLast()) { - AddressEntry entry(asiolink::IOAddress(rdi->getCurrent().toText())); + AddressEntry entry(isc::asiolink::IOAddress(rdi->getCurrent().toText())); boost::shared_ptr ns_entry(new NameserverEntry(ns_name, rrset->getClass())); NameserverAddress ns_address(ns_entry, entry, V4_ONLY); addresses.push_back(ns_address); diff --git a/src/lib/nsas/hash_deleter.h b/src/lib/nsas/hash_deleter.h index 29a32d7ce51accd26f5236f07db190900362ff2f..27f066e9fd63308a49172e10eaaa89be7ddca750 100644 --- a/src/lib/nsas/hash_deleter.h +++ b/src/lib/nsas/hash_deleter.h @@ -16,8 +16,9 @@ #define __HASH_DELETER_H #include +#include + #include "hash_table.h" -#include "lru_list.h" namespace isc { namespace nsas { @@ -31,7 +32,7 @@ namespace nsas { /// hash table without the need to be declared as "friend" or the need /// to define accessor methods. template -class HashDeleter : public LruList::Dropped { +class HashDeleter : public isc::util::LruList::Dropped { public: /// \brief Constructor diff --git a/src/lib/nsas/hash_table.h b/src/lib/nsas/hash_table.h index c4a9913e635a25cc3fd30f832946f6e845584ca9..c028fa48b3fbcafd53eb9e6f92e73a507845e431 100644 --- a/src/lib/nsas/hash_table.h +++ b/src/lib/nsas/hash_table.h @@ -19,7 +19,8 @@ #include -#include "locks.h" +#include + #include "hash.h" #include "hash_key.h" @@ -47,7 +48,7 @@ struct HashTableSlot { typedef typename std::list >::iterator iterator; ///< Iterator over elements with same hash - typedef isc::locks::upgradable_mutex mutex_type; + typedef isc::util::locks::upgradable_mutex mutex_type; ///< Mutex protecting this slot //@} @@ -114,11 +115,11 @@ public: /// //@{ typedef typename - isc::locks::sharable_lock::mutex_type> + isc::util::locks::sharable_lock::mutex_type> sharable_lock; ///< Type for a scope-limited read-lock typedef typename - isc::locks::scoped_lock::mutex_type> + isc::util::locks::scoped_lock::mutex_type> scoped_lock; ///< Type for a scope-limited write-lock //@} diff --git a/src/lib/nsas/nameserver_address_store.cc b/src/lib/nsas/nameserver_address_store.cc index e92c17742d9c140f730e330ebf5da0cda709fb41..3cef38db5a5a8577d04a19ce43271309199f1c69 100644 --- a/src/lib/nsas/nameserver_address_store.cc +++ b/src/lib/nsas/nameserver_address_store.cc @@ -20,10 +20,10 @@ #include #include +#include +#include -#include "locks.h" #include "hash_table.h" -#include "lru_list.h" #include "hash_deleter.h" #include "nsas_entry_compare.h" #include "nameserver_entry.h" @@ -50,9 +50,9 @@ NameserverAddressStore::NameserverAddressStore( zonehashsize)), nameserver_hash_(new HashTable( new NsasEntryCompare, nshashsize)), - zone_lru_(new LruList((3 * zonehashsize), + zone_lru_(new isc::util::LruList((3 * zonehashsize), new HashDeleter(*zone_hash_))), - nameserver_lru_(new LruList((3 * nshashsize), + nameserver_lru_(new isc::util::LruList((3 * nshashsize), new HashDeleter(*nameserver_hash_))), resolver_(resolver.get()) { } @@ -70,7 +70,7 @@ newZone( isc::resolve::ResolverInterface* resolver, const string* zone, const RRClass* class_code, const boost::shared_ptr >* ns_hash, - const boost::shared_ptr >* ns_lru) + const boost::shared_ptr >* ns_lru) { boost::shared_ptr result(new ZoneEntry(resolver, *zone, *class_code, *ns_hash, *ns_lru)); diff --git a/src/lib/nsas/nameserver_address_store.h b/src/lib/nsas/nameserver_address_store.h index d54be848d7c364c515b2d6aa962ce3528131693c..148052ddc8e04887bf4be15d199d676585af6725 100644 --- a/src/lib/nsas/nameserver_address_store.h +++ b/src/lib/nsas/nameserver_address_store.h @@ -32,11 +32,14 @@ namespace dns { class RRClass; } +namespace util { +template class LruList; +} + namespace nsas { class ResolverInterface; template class HashTable; -template class LruList; class ZoneEntry; class NameserverEntry; class AddressRequestCallback; @@ -112,8 +115,8 @@ protected: boost::shared_ptr > nameserver_hash_; // ... and the LRU lists - boost::shared_ptr > zone_lru_; - boost::shared_ptr > nameserver_lru_; + boost::shared_ptr > zone_lru_; + boost::shared_ptr > nameserver_lru_; // The resolver we use private: isc::resolve::ResolverInterface* resolver_; diff --git a/src/lib/nsas/nameserver_entry.cc b/src/lib/nsas/nameserver_entry.cc index 40d5cd72787ef668268e9d7b1481b2e663e79cae..4035f791867c821ffafc796c1b8554ff37115ee4 100644 --- a/src/lib/nsas/nameserver_entry.cc +++ b/src/lib/nsas/nameserver_entry.cc @@ -41,7 +41,7 @@ #include "nameserver_address.h" #include "nameserver_entry.h" -using namespace asiolink; +using namespace isc::asiolink; using namespace isc::nsas; using namespace isc::dns; using namespace std; @@ -52,7 +52,7 @@ namespace nsas { namespace { // Just shorter type alias -typedef isc::locks::scoped_lock Lock; +typedef isc::util::locks::scoped_lock Lock; } diff --git a/src/lib/nsas/nameserver_entry.h b/src/lib/nsas/nameserver_entry.h index 99d7ff512f835575122d363f762f7caef78d6c0f..0f214c68474033d20b9e4c62f49f944221c272d7 100644 --- a/src/lib/nsas/nameserver_entry.h +++ b/src/lib/nsas/nameserver_entry.h @@ -25,11 +25,12 @@ #include +#include + #include "address_entry.h" #include "asiolink.h" #include "nsas_types.h" #include "hash_key.h" -#include "lru_list.h" #include "fetchable.h" #include "nsas_entry.h" #include "nameserver_address.h" @@ -246,7 +247,7 @@ public: //@} private: - mutable isc::locks::recursive_mutex mutex_;///< Mutex protecting this object + mutable isc::util::locks::recursive_mutex mutex_;///< Mutex protecting this object std::string name_; ///< Canonical name of the nameserver isc::dns::RRClass classCode_; ///< Class of the nameserver /** diff --git a/src/lib/nsas/nsas_entry.h b/src/lib/nsas/nsas_entry.h index f739e8db0f417eef4fb30f221566c1652b152f65..9cbed115dfe850755544ceb1f9a2d3c71c66cf6b 100644 --- a/src/lib/nsas/nsas_entry.h +++ b/src/lib/nsas/nsas_entry.h @@ -19,10 +19,10 @@ #include #include +#include #include "hash_key.h" #include "hash_table.h" -#include "lru_list.h" namespace isc { namespace nsas { @@ -66,7 +66,7 @@ public: /// This class is inherited from boost::enable_shared_from_this class /// So within a member function a shared_ptr to current object can be obtained template -class NsasEntry : public boost::enable_shared_from_this { +class NsasEntry : public boost::enable_shared_from_this { public: /// \brief Default Constructor @@ -93,7 +93,7 @@ public: /// Sets the iterator of an object and, as a side effect, marks it as valid. /// /// \param iterator Iterator of this element in the list - virtual void setLruIterator(typename LruList::iterator iterator) { + virtual void setLruIterator(typename isc::util::LruList::iterator iterator) { iterator_ = iterator; valid_ = true; } @@ -103,7 +103,7 @@ public: /// \return iterator Iterator of this element in the list. /// /// \exception InvalidLruIterator Thrown if the iterator is not valid. - virtual typename LruList::iterator getLruIterator() const { + virtual typename isc::util::LruList::iterator getLruIterator() const { if (! valid_) { isc_throw(InvalidLruIterator, "pointer of element into LRU list was not valid"); @@ -127,7 +127,7 @@ public: } private: - typename LruList::iterator iterator_; ///< Handle into the LRU List + typename isc::util::LruList::iterator iterator_; ///< Handle into the LRU List bool valid_; ///< true if handle is valid }; diff --git a/src/lib/nsas/tests/Makefile.am b/src/lib/nsas/tests/Makefile.am index 9d9e61c8868dfaf0c96b4fb67ff3a1ea5aa3e63e..56f36d152a074bc939eaa99ff1e4ed9a04b4dd3c 100644 --- a/src/lib/nsas/tests/Makefile.am +++ b/src/lib/nsas/tests/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = . AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG) AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas AM_CXXFLAGS = $(B10_CXXFLAGS) @@ -33,7 +34,6 @@ run_unittests_SOURCES += hash_deleter_unittest.cc run_unittests_SOURCES += hash_key_unittest.cc run_unittests_SOURCES += hash_table_unittest.cc run_unittests_SOURCES += hash_unittest.cc -run_unittests_SOURCES += lru_list_unittest.cc run_unittests_SOURCES += nameserver_address_unittest.cc run_unittests_SOURCES += nameserver_address_store_unittest.cc run_unittests_SOURCES += nameserver_entry_unittest.cc @@ -41,7 +41,6 @@ run_unittests_SOURCES += nsas_entry_compare_unittest.cc run_unittests_SOURCES += nsas_test.h run_unittests_SOURCES += zone_entry_unittest.cc run_unittests_SOURCES += fetchable_unittest.cc -run_unittests_SOURCES += random_number_generator_unittest.cc run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) @@ -53,6 +52,7 @@ run_unittests_LDADD += -lboost_thread endif run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la diff --git a/src/lib/nsas/tests/address_entry_unittest.cc b/src/lib/nsas/tests/address_entry_unittest.cc index 02fef51f67116b4ee08cd01f3ad92ddf5ec63eba..60aa3cce78163146abfbbd0bb5b3e68e3a07c732 100644 --- a/src/lib/nsas/tests/address_entry_unittest.cc +++ b/src/lib/nsas/tests/address_entry_unittest.cc @@ -32,7 +32,7 @@ static std::string V4B_TEXT("5.6.7.8"); static std::string V6A_TEXT("2001:dead:beef::"); static std::string V6B_TEXT("1984:1985::1986:1987"); -using namespace asiolink; +using namespace isc::asiolink; using namespace std; using namespace isc::nsas; diff --git a/src/lib/nsas/tests/hash_deleter_unittest.cc b/src/lib/nsas/tests/hash_deleter_unittest.cc index 97fecbe022b10f38431c233c406be950adedd361..c370857454d617af534e207ebee10e7211930cd4 100644 --- a/src/lib/nsas/tests/hash_deleter_unittest.cc +++ b/src/lib/nsas/tests/hash_deleter_unittest.cc @@ -22,11 +22,11 @@ #include #include +#include #include "../nsas_entry.h" #include "../hash_table.h" #include "../hash_key.h" -#include "../lru_list.h" #include "../hash_deleter.h" #include "nsas_test.h" @@ -34,6 +34,7 @@ using namespace std; using namespace isc::dns; +using namespace isc::util; namespace isc { namespace nsas { diff --git a/src/lib/nsas/tests/nameserver_address_store_unittest.cc b/src/lib/nsas/tests/nameserver_address_store_unittest.cc index 9133daf170879c333716e8a3468e0384f8203624..abbac1db9ee69a739a92e1b370911b5e900a5844 100644 --- a/src/lib/nsas/tests/nameserver_address_store_unittest.cc +++ b/src/lib/nsas/tests/nameserver_address_store_unittest.cc @@ -12,34 +12,36 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include - -/// \brief Test Deleter Objects +/// \brief Nameserver Address Store Tests /// -/// This file contains tests for the "deleter" classes within the nameserver -/// address store. These act to delete zones from the zone hash table when -/// the element reaches the top of the LRU list. +/// This file contains tests for the nameserver address store as a whole. -#include -#include -#include +#include +#include +#include +#include -#include -#include -#include #include +#include +#include +#include -#include -#include +#include +#include +#include +#include +#include + +#include "../address_request_callback.h" #include "../nameserver_address_store.h" -#include "../nsas_entry_compare.h" #include "../nameserver_entry.h" +#include "../nsas_entry_compare.h" #include "../zone_entry.h" -#include "../address_request_callback.h" #include "nsas_test.h" using namespace isc::dns; +using namespace isc::util; using namespace std; namespace isc { @@ -66,43 +68,62 @@ public: virtual ~DerivedNsas() {} - /// \brief Add Nameserver Entry to Hash and LRU Tables + /// \brief Add Nameserver Entry to hash and LRU tables + /// + /// \param entry Nameserver Entry to add. void AddNameserverEntry(boost::shared_ptr& entry) { HashKey h = entry->hashKey(); nameserver_hash_->add(entry, h); nameserver_lru_->add(entry); } - /// \brief Add Zone Entry to Hash and LRU Tables + /// \brief Add Zone Entry to hash and LRU tables + /// + /// \param entry Zone Entry to add. void AddZoneEntry(boost::shared_ptr& entry) { HashKey h = entry->hashKey(); zone_hash_->add(entry, h); zone_lru_->add(entry); } - /** - * \short Just wraps the common lookup - * - * It calls the lookup and provides the authority section - * if it is asked for by the resolver. - */ + + /// \brief Wrap the common lookup + /// + /// Calls the lookup and provides the authority section if it is asked + /// for by the resolver. + /// + /// \param name Name of zone for which an address is required + /// \param class_code Class of the zone + /// \param authority Pointer to authority section RRset to which NS + /// records will be added. + /// \param callback Callback object used to pass result back to caller void lookupAndAnswer(const string& name, const RRClass& class_code, - RRsetPtr authority, - boost::shared_ptr callback) + RRsetPtr authority, + boost::shared_ptr callback) { + // Note how many requests are in the resolver's queue size_t size(resolver_->requests.size()); + + // Lookup the name. This should generate a request for NS records. NameserverAddressStore::lookup(name, class_code, callback, ANY_OK); - // It asked something, the only thing it can ask is the NS list if (size < resolver_->requests.size()) { + + // It asked something, the only thing it can ask is the NS list. + // Once answered, drop the request so no-one else sees it resolver_->provideNS(size, authority); - // Once answered, drop the request so noone else sees it resolver_->requests.erase(resolver_->requests.begin() + size); + } else { - ADD_FAILURE() << "Not asked for NS"; + + // The test resolver's requests queue has not increased in size, + // so the lookup did not generate a request. + ADD_FAILURE() << "Lookup did not generate a request for NS records"; } } + private: - boost::shared_ptr resolver_; -}; + boost::shared_ptr resolver_; + ///< Resolver used to answer generated requests +}; @@ -110,6 +131,7 @@ private: class NameserverAddressStoreTest : public TestWithRdata { protected: + /// \brief Constructor NameserverAddressStoreTest() : authority_(new RRset(Name("example.net."), RRClass::IN(), RRType::NS(), RRTTL(128))), @@ -117,8 +139,8 @@ protected: RRType::NS(), RRTTL(128))), resolver_(new TestResolver) { - // Constructor - initialize a set of nameserver and zone objects. For - // convenience, these are stored in vectors. + // Initialize a set of nameserver and zone objects. For convenience, + // these are stored in vectors. for (int i = 1; i <= 9; ++i) { std::string name = "nameserver" + boost::lexical_cast( i); @@ -144,57 +166,70 @@ protected: NSASCallback::results.clear(); } + /// \brief Internal callback object + /// + /// Callback object. It just records whether the success() or + /// unreachable() methods were called and if success, a copy of the + /// Nameserver object. (The data is held in a static object that will + /// outlive the lifetime of the callback object.) + struct NSASCallback : public AddressRequestCallback { + typedef pair Result; + static vector results; + + virtual void success(const NameserverAddress& address) { + results.push_back(Result(true, address)); + } + virtual void unreachable() { + results.push_back(Result(false, NameserverAddress())); + } + }; + + /// \brief Return pointer to callback object + boost::shared_ptr getCallback() { + return (boost::shared_ptr(new NSASCallback)); + } + + // Member variables + // Vector of pointers to nameserver and zone entries. std::vector > nameservers_; std::vector > zones_; - RRsetPtr authority_, empty_authority_; + // Authority sections used in the tests + RRsetPtr authority_; + RRsetPtr empty_authority_; + // ... and the resolver boost::shared_ptr resolver_; - - class NSASCallback : public AddressRequestCallback { - public: - typedef pair Result; - static vector results; - virtual void success(const NameserverAddress& address) { - results.push_back(Result(true, address)); - } - virtual void unreachable() { - results.push_back(Result(false, NameserverAddress())); - } - }; - - boost::shared_ptr getCallback() { - return (boost::shared_ptr(new NSASCallback)); - } }; +/// Definition of the static results object vector NameserverAddressStoreTest::NSASCallback::results; /// \brief Remove Zone Entry from Hash Table /// -/// Check that when an entry reaches the top of the zone LRU list, it is removed from the -/// hash table as well. +/// Check that when an entry reaches the top of the zone LRU list, it is removed +/// from the hash table as well. TEST_F(NameserverAddressStoreTest, ZoneDeletionCheck) { - // Create a NSAS with a hash size of three and a LRU size of 9 (both zone and - // nameserver tables). + // Create a NSAS with a hash size of three and a LRU size of 9 (both zone + // and nameserver tables). DerivedNsas nsas(resolver_, 2, 2); - // Add six entries to the tables. After addition the reference count of each element - // should be 3 - one for the entry in the zones_ vector, and one each for the entries - // in the LRU list and hash table. + // Add six entries to the tables. After addition the reference count of + // each element should be 3 - one for the entry in the zones_ vector, and + // one each for the entries in the LRU list and hash table. for (int i = 1; i <= 6; ++i) { EXPECT_EQ(1, zones_[i].use_count()); nsas.AddZoneEntry(zones_[i]); EXPECT_EQ(3, zones_[i].use_count()); } - // Adding another entry should cause the first one to drop off the LRU list, which - // should also trigger the deletion of the entry from the hash table. This should - // reduce its use count to 1. + // Adding another entry should cause the first one to drop off the LRU list, + // which should also trigger the deletion of the entry from the hash table. + // This should reduce its use count to 1. EXPECT_EQ(1, zones_[7].use_count()); nsas.AddZoneEntry(zones_[7]); EXPECT_EQ(3, zones_[7].use_count()); @@ -205,26 +240,26 @@ TEST_F(NameserverAddressStoreTest, ZoneDeletionCheck) { /// \brief Remove Entry from Hash Table /// -/// Check that when an entry reaches the top of the LRU list, it is removed from the -/// hash table as well. +/// Check that when an entry reaches the top of the LRU list, it is removed from +/// the hash table as well. TEST_F(NameserverAddressStoreTest, NameserverDeletionCheck) { - // Create a NSAS with a hash size of three and a LRU size of 9 (both zone and - // nameserver tables). + // Create a NSAS with a hash size of three and a LRU size of 9 (both zone + // and nameserver tables). DerivedNsas nsas(resolver_, 2, 2); - // Add six entries to the tables. After addition the reference count of each element - // should be 3 - one for the entry in the nameservers_ vector, and one each for the entries - // in the LRU list and hash table. + // Add six entries to the tables. After addition the reference count of + // each element should be 3 - one for the entry in the nameservers_ vector, + // and one each for the entries in the LRU list and hash table. for (int i = 1; i <= 6; ++i) { EXPECT_EQ(1, nameservers_[i].use_count()); nsas.AddNameserverEntry(nameservers_[i]); EXPECT_EQ(3, nameservers_[i].use_count()); } - // Adding another entry should cause the first one to drop off the LRU list, which - // should also trigger the deletion of the entry from the hash table. This should - // reduce its use count to 1. + // Adding another entry should cause the first one to drop off the LRU list, + // which should also trigger the deletion of the entry from the hash table. + // This should reduce its use count to 1. EXPECT_EQ(1, nameservers_[7].use_count()); nsas.AddNameserverEntry(nameservers_[7]); EXPECT_EQ(3, nameservers_[7].use_count()); @@ -237,14 +272,17 @@ TEST_F(NameserverAddressStoreTest, NameserverDeletionCheck) { /// Check if it asks correct questions and it keeps correct internal state. TEST_F(NameserverAddressStoreTest, emptyLookup) { DerivedNsas nsas(resolver_, 10, 10); + // Ask it a question nsas.lookupAndAnswer("example.net.", RRClass::IN(), authority_, getCallback()); + // It should ask for IP addresses for ns.example.com. EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), 0, 1)); // Ask another question for the same zone nsas.lookup("example.net.", RRClass::IN(), getCallback()); + // It should ask no more questions now EXPECT_EQ(2, resolver_->requests.size()); @@ -252,6 +290,7 @@ TEST_F(NameserverAddressStoreTest, emptyLookup) { authority_->setName(Name("example.com.")); nsas.lookupAndAnswer("example.com.", RRClass::IN(), authority_, getCallback()); + // It still should ask nothing EXPECT_EQ(2, resolver_->requests.size()); @@ -271,11 +310,14 @@ TEST_F(NameserverAddressStoreTest, emptyLookup) { /// It should not ask anything and say it is unreachable right away. TEST_F(NameserverAddressStoreTest, zoneWithoutNameservers) { DerivedNsas nsas(resolver_, 10, 10); + // Ask it a question nsas.lookupAndAnswer("example.net.", RRClass::IN(), empty_authority_, getCallback()); + // There should be no questions, because there's nothing to ask EXPECT_EQ(0, resolver_->requests.size()); + // And there should be one "unreachable" answer for the query ASSERT_EQ(1, NSASCallback::results.size()); EXPECT_FALSE(NSASCallback::results[0].first); @@ -288,9 +330,11 @@ TEST_F(NameserverAddressStoreTest, zoneWithoutNameservers) { /// without further asking. TEST_F(NameserverAddressStoreTest, unreachableNS) { DerivedNsas nsas(resolver_, 10, 10); + // Ask it a question nsas.lookupAndAnswer("example.net.", RRClass::IN(), authority_, getCallback()); + // It should ask for IP addresses for example.com. EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), 0, 1)); @@ -298,6 +342,7 @@ TEST_F(NameserverAddressStoreTest, unreachableNS) { authority_->setName(Name("example.com.")); nsas.lookupAndAnswer("example.com.", RRClass::IN(), authority_, getCallback()); + // It should ask nothing more now EXPECT_EQ(2, resolver_->requests.size()); @@ -307,12 +352,14 @@ TEST_F(NameserverAddressStoreTest, unreachableNS) { // We should have 2 answers now EXPECT_EQ(2, NSASCallback::results.size()); + // When we ask one same and one other zone with the same nameserver, // it should generate no questions and answer right away nsas.lookup("example.net.", RRClass::IN(), getCallback()); authority_->setName(Name("example.org.")); nsas.lookupAndAnswer("example.org.", RRClass::IN(), authority_, getCallback()); + // There should be 4 negative answers now EXPECT_EQ(4, NSASCallback::results.size()); BOOST_FOREACH(const NSASCallback::Result& result, NSASCallback::results) { @@ -325,18 +372,23 @@ TEST_F(NameserverAddressStoreTest, unreachableNS) { /// Does some asking, on a set of zones that share some nameservers, with /// slower answering, evicting data, etc. TEST_F(NameserverAddressStoreTest, CombinedTest) { + // Create small caches, so we get some evictions DerivedNsas nsas(resolver_, 1, 1); + // Ask for example.net. It has single nameserver out of the zone nsas.lookupAndAnswer("example.net.", RRClass::IN(), authority_, getCallback()); + // It should ask for the nameserver IP addresses EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), 0, 1)); EXPECT_EQ(0, NSASCallback::results.size()); + // But we do not answer it right away. We create a new zone and // let this nameserver entry get out. rrns_->addRdata(rdata::generic::NS("example.cz")); nsas.lookupAndAnswer(EXAMPLE_CO_UK, RRClass::IN(), rrns_, getCallback()); + // It really should ask something, one of the nameservers // (or both) ASSERT_GT(resolver_->requests.size(), 2); @@ -346,8 +398,8 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) { EXPECT_NO_THROW(resolver_->asksIPs(name, 2, 3)); EXPECT_EQ(0, NSASCallback::results.size()); - size_t request_count(resolver_->requests.size()); // This should still be in the hash table, so try it asks no more questions + size_t request_count(resolver_->requests.size()); nsas.lookup("example.net.", RRClass::IN(), getCallback()); EXPECT_EQ(request_count, resolver_->requests.size()); EXPECT_EQ(0, NSASCallback::results.size()); @@ -355,6 +407,7 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) { // We respond to one of the 3 nameservers EXPECT_NO_THROW(resolver_->answer(2, name, RRType::A(), rdata::in::A("192.0.2.1"))); + // That should trigger one answer EXPECT_EQ(1, NSASCallback::results.size()); EXPECT_TRUE(NSASCallback::results[0].first); @@ -362,6 +415,7 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) { NSASCallback::results[0].second.getAddress().toText()); EXPECT_NO_THROW(resolver_->answer(3, name, RRType::AAAA(), rdata::in::AAAA("2001:bd8::1"))); + // And there should be yet another query ASSERT_GT(resolver_->requests.size(), 4); EXPECT_NE(name, resolver_->requests[4].first->getName()); @@ -379,9 +433,9 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) { EXPECT_EQ(request_count + 2, resolver_->requests.size()); EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), request_count, request_count + 1)); - // Now, we answer both queries for the same address - // and three (one for the original, one for this one) more answers should - // arrive + + // Now, we answer both queries for the same address and three (one for the + // original, one for this one) more answers should arrive NSASCallback::results.clear(); EXPECT_NO_THROW(resolver_->answer(0, Name("ns.example.com."), RRType::A(), rdata::in::A("192.0.2.2"))); @@ -394,5 +448,113 @@ TEST_F(NameserverAddressStoreTest, CombinedTest) { } } +// Check that we can update the RTT associated with nameservers successfully. +// Also checks that we can't set the RTT to zero (which would cause problems +// with selection algorithm). +TEST_F(NameserverAddressStoreTest, updateRTT) { + + // Initialization. + string zone_name = "example.net."; + string ns_name = "ns.example.com."; + vector address; + address.push_back("192.0.2.1"); + address.push_back("192.0.2.2"); + + uint32_t HIGH_RTT = 10000; // 1E4; When squared, the result fits in 32 bits + + DerivedNsas nsas(resolver_, 103, 107); // Arbitrary cache sizes + + // Ensure that location holding the addresses returned is empty. We'll + // be using this throughout the tests. As the full name is a bit of a + // mouthful, set up an alias. + vector& results = + NameserverAddressStoreTest::NSASCallback::results; + results.clear(); + + // Initialize the test resolver with the answer for the A record query + // for ns.example.com (the nameserver set for example.net in the class + // initialization). We'll set two addresses. + Name ns_example_com(ns_name); + RRsetPtr ns_address = boost::shared_ptr(new RRset( + ns_example_com, RRClass::IN(), RRType::A(), RRTTL(300))); + BOOST_FOREACH(string addr, address) { + ns_address->addRdata(rdata::in::A(addr)); + } + + // All set. Ask for example.net. + boost::shared_ptr callback = getCallback(); + nsas.lookupAndAnswer(zone_name, RRClass::IN(), authority_, getCallback()); + + // This should generate two requests - one for A and one for AAAA. + EXPECT_EQ(2, resolver_->requests.size()); + + // Provide an answer that has two A records. This should generate one + // result. + EXPECT_NO_THROW(resolver_->answer(0, ns_address)); + EXPECT_EQ(1, results.size()); + + // We expect the lookup to be successful. Check that the address is one of + // the two we've set and that the RTT associated with this nameserver is + // non-zero. + EXPECT_EQ(true, results[0].first); + vector::iterator addr1 = find(address.begin(), address.end(), + results[0].second.getAddress().toText()); + EXPECT_TRUE(addr1 != address.end()); + + // The RTT we got should be non-zero and less than the high value we are + // using for the test. + uint32_t rtt1 = results[0].second.getAddressEntry().getRTT(); + EXPECT_NE(0, rtt1); + EXPECT_LT(rtt1, HIGH_RTT); + + // Update the address with a very high RTT. Owning to the way the NSAS is + // written, we can update the RTT but cannot read the new value back from + // the new object. + results[0].second.updateRTT(HIGH_RTT); + + // Get another nameserver. As the probability of returning a particular + // address is proporational to 1/t^2, we should get the second address + // since the first now has a larger RTT. However, this is not guaranteed + // - this is a probability (albeit small) of getting the first again. We'll + // allow three chances of getting the "wrong" address before we declare + // an error. + int attempt = 0; + vector::iterator addr2 = addr1; + for (attempt = 0; (attempt < 3) && (*addr1 == *addr2); ++attempt) { + results.clear(); + nsas.lookup(zone_name, RRClass::IN(), + getCallback(), ANY_OK); + addr2 = find(address.begin(), address.end(), + results[0].second.getAddress().toText()); + } + EXPECT_LT(attempt, 3); + + // Ensure that the RTT is non-zero. + // obtained earlier. + uint32_t rtt2 = results[0].second.getAddressEntry().getRTT(); + EXPECT_NE(0, rtt2); + + // The test has shown that the code can return the two nameservers. Now + // try to set the RTT for the last one returned to zero. As there is a + // smoothing effect in the calculations which damps out an abrupt change + // in the RTT, the underlying RTT will not be set to zero immediately. So + // loop a large number of times, each time setting it to zero. + // + // Between each setting of the RTT, we have to retrieve the nameserver from + // the NSAS again. This means that we _could_ occasionally get the address + // of the one whose RTT we have raised to HIGH_RTT. We overcome this by + // looping a _very_ large number of times. Ultimately the RTT of both + // addresses should decay to a small value. + for (int i = 0; i < 2000; ++i) { // 1000 times for each nameserver + results.clear(); + nsas.lookup(zone_name, RRClass::IN(), getCallback(), ANY_OK); + EXPECT_EQ(1, results.size()); + uint32_t rtt3 = results[0].second.getAddressEntry().getRTT(); + EXPECT_NE(0, rtt3); + results[0].second.updateRTT(0); + } +} + + } // namespace nsas } // namespace isc diff --git a/src/lib/nsas/tests/nameserver_address_unittest.cc b/src/lib/nsas/tests/nameserver_address_unittest.cc index 457e61c5c043264ddca6e54e9c93175c43110141..e3bc5de8e231b6089abca1bac65e4bf86d019518 100644 --- a/src/lib/nsas/tests/nameserver_address_unittest.cc +++ b/src/lib/nsas/tests/nameserver_address_unittest.cc @@ -58,7 +58,7 @@ public: boost::shared_ptr& getNameserverEntry() { return ns_; } // Return the IOAddress corresponding to the index in rrv4_ - asiolink::IOAddress getAddressAtIndex(uint32_t index) { + isc::asiolink::IOAddress getAddressAtIndex(uint32_t index) { return ns_.get()->getAddressAtIndex(index, V4_ONLY); } @@ -107,7 +107,7 @@ TEST_F(NameserverAddressTest, Address) { boost::shared_ptr empty_ne((NameserverEntry*)NULL); // It will throw an NullNameserverEntryPointer exception with the empty NameserverEntry shared pointer ASSERT_THROW({NameserverAddress empty_ns_address(empty_ne, - asiolink::IOAddress("127.0.0.1"), V4_ONLY);}, + isc::asiolink::IOAddress("127.0.0.1"), V4_ONLY);}, NullNameserverEntryPointer); } diff --git a/src/lib/nsas/tests/nameserver_entry_unittest.cc b/src/lib/nsas/tests/nameserver_entry_unittest.cc index 4225e871ef2c25177ddf5c8d17bfac7c31b6db4a..7e9f6750bfc4f4bd56674293cb8d256f16203bfc 100644 --- a/src/lib/nsas/tests/nameserver_entry_unittest.cc +++ b/src/lib/nsas/tests/nameserver_entry_unittest.cc @@ -39,7 +39,7 @@ #include "nsas_test.h" using namespace isc::nsas; -using namespace asiolink; +using namespace isc::asiolink; using namespace std; using namespace isc::dns; using namespace rdata; @@ -513,6 +513,11 @@ TEST_F(NameserverEntryTest, UpdateRTT) { // The rtt should be close to stable rtt value EXPECT_TRUE((stable_rtt - new_rtt) < (new_rtt - init_rtt)); + + // Finally, try updating the RTT to a very large value (large enough for + // RTT^2 - used in the internal calculation - to exceed a 32-bit value). + EXPECT_NO_THROW(vec[0].updateRTT(1000000000)); // 10^9 + } } // namespace diff --git a/src/lib/nsas/tests/nsas_test.h b/src/lib/nsas/tests/nsas_test.h index 7500fc7792181587d41d2159c2526cfcffb256a7..033df8101b3c49d16154c128ae6d09a95358327a 100644 --- a/src/lib/nsas/tests/nsas_test.h +++ b/src/lib/nsas/tests/nsas_test.h @@ -26,8 +26,8 @@ #include +#include #include -#include #include #include #include @@ -40,6 +40,7 @@ using namespace isc::dns::rdata; using namespace isc::dns; +using namespace isc::util; namespace { MessagePtr @@ -124,7 +125,7 @@ public: virtual void toWire(OutputBuffer& buffer) const; /// \brief render the \Rdata in the wire format to a \c MessageRenderer - virtual void toWire(MessageRenderer& renderer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; /// \brief Comparison Method virtual int compare(const Rdata& other) const; @@ -140,7 +141,7 @@ void RdataTest::toWire(OutputBuffer&) const { } template -void RdataTest::toWire(MessageRenderer&) const { +void RdataTest::toWire(AbstractMessageRenderer&) const { } template @@ -320,20 +321,26 @@ class TestResolver : public isc::resolve::ResolverInterface { /* * Sends a simple answer to a query. - * Provide index of a query and the address to pass. + * 1) Provide index of a query and the address(es) to pass. + * 2) Provide index of query and components of address to pass. */ - void answer(size_t index, const Name& name, const RRType& type, - const rdata::Rdata& rdata, size_t TTL = 100) - { + void answer(size_t index, RRsetPtr& set) { if (index >= requests.size()) { throw NoSuchRequest(); } + requests[index].second->success(createResponseMessage(set)); + } + + void answer(size_t index, const Name& name, const RRType& type, + const rdata::Rdata& rdata, size_t TTL = 100) + { RRsetPtr set(new RRset(name, RRClass::IN(), type, RRTTL(TTL))); set->addRdata(rdata); - requests[index].second->success(createResponseMessage(set)); + answer(index, set); } + void provideNS(size_t index, RRsetPtr nameservers) { diff --git a/src/lib/nsas/tests/zone_entry_unittest.cc b/src/lib/nsas/tests/zone_entry_unittest.cc index 34f995c03c35fc01af8f9300f58804d0d66b09de..198229978e06d35617badc76bc9bdfb6b1c13059 100644 --- a/src/lib/nsas/tests/zone_entry_unittest.cc +++ b/src/lib/nsas/tests/zone_entry_unittest.cc @@ -33,9 +33,10 @@ #include "nsas_test.h" using namespace isc::nsas; -using namespace asiolink; +using namespace isc::asiolink; using namespace std; using namespace isc::dns; +using namespace isc::util; namespace { diff --git a/src/lib/nsas/zone_entry.cc b/src/lib/nsas/zone_entry.cc index 3af70a8d1a83ef69f563e07d9139c9169e2e9901..1c5df03bfe2bfa07999235e2c3e4d45844a6b1ee 100644 --- a/src/lib/nsas/zone_entry.cc +++ b/src/lib/nsas/zone_entry.cc @@ -31,7 +31,9 @@ using namespace std; namespace isc { -using namespace dns; +using namespace isc::dns; +using namespace isc::util; +using namespace isc::util::random; namespace nsas { @@ -51,7 +53,7 @@ ZoneEntry::ZoneEntry( namespace { // Shorter aliases for frequently used types -typedef isc::locks::scoped_lock Lock; // Local lock, nameservers not locked +typedef isc::util::locks::scoped_lock Lock; // Local lock, nameservers not locked typedef boost::shared_ptr CallbackPtr; /* diff --git a/src/lib/nsas/zone_entry.h b/src/lib/nsas/zone_entry.h index 92ac75ac37ff24d5ae3e13e4110c17d438b480df..f772784aba06d7f6f598492afa35b40a51f982c1 100644 --- a/src/lib/nsas/zone_entry.h +++ b/src/lib/nsas/zone_entry.h @@ -25,13 +25,14 @@ #include -#include "locks.h" +#include +#include + #include "hash_key.h" #include "nsas_entry.h" #include "asiolink.h" #include "fetchable.h" #include "nsas_types.h" -#include "random_number_generator.h" #include "glue_hints.h" namespace isc { @@ -72,7 +73,7 @@ public: ZoneEntry(isc::resolve::ResolverInterface* resolver, const std::string& name, const isc::dns::RRClass& class_code, boost::shared_ptr > nameserver_table, - boost::shared_ptr > nameserver_lru); + boost::shared_ptr > nameserver_lru); /// \return Name of the zone std::string getName() const { @@ -132,7 +133,7 @@ protected: time_t expiry_; ///< Expiry time of this entry, 0 means not set //}@ private: - mutable isc::locks::recursive_mutex mutex_;///< Mutex protecting this zone entry + mutable isc::util::locks::recursive_mutex mutex_;///< Mutex protecting this zone entry std::string name_; ///< Canonical zone name isc::dns::RRClass class_code_; ///< Class code /** @@ -161,7 +162,7 @@ private: // We store the nameserver table and lru, so we can look up when there's // update boost::shared_ptr > nameserver_table_; - boost::shared_ptr > nameserver_lru_; + boost::shared_ptr > nameserver_lru_; // Resolver callback class, documentation with the class declaration class ResolverCallback; // It has direct access to us @@ -182,7 +183,7 @@ private: void insertCallback(NameserverPtr nameserver, AddressFamily family); // A random generator for this zone entry // TODO: A more global one? Per thread one? - WeightedRandomIntegerGenerator address_selector; + isc::util::random::WeightedRandomIntegerGenerator address_selector; }; } // namespace nsas diff --git a/src/lib/python/isc/config/cfgmgr.py b/src/lib/python/isc/config/cfgmgr.py index 8561378ed81f16180c97346c1470bfaceb27d72b..88a93e17b07b88924f615893570b054ac858ea9b 100644 --- a/src/lib/python/isc/config/cfgmgr.py +++ b/src/lib/python/isc/config/cfgmgr.py @@ -170,6 +170,10 @@ class ConfigManager: self.data_path = data_path self.database_filename = database_filename self.module_specs = {} + # Virtual modules are the ones which have no process running. The + # checking of validity is done by functions presented here instead + # of some other process + self.virtual_modules = {} self.config = ConfigManagerData(data_path, database_filename) if session: self.cc = session @@ -187,11 +191,20 @@ class ConfigManager: """Adds a ModuleSpec""" self.module_specs[spec.get_module_name()] = spec + def set_virtual_module(self, spec, check_func): + """Adds a virtual module with its spec and checking function.""" + self.module_specs[spec.get_module_name()] = spec + self.virtual_modules[spec.get_module_name()] = check_func + def remove_module_spec(self, module_name): """Removes the full ModuleSpec for the given module_name. + Also removes the virtual module check function if it + was present. Does nothing if the module was not present.""" if module_name in self.module_specs: del self.module_specs[module_name] + if module_name in self.virtual_modules: + del self.virtual_modules[module_name] def get_module_spec(self, module_name = None): """Returns the full ModuleSpec for the module with the given @@ -299,24 +312,48 @@ class ConfigManager: # todo: use api (and check the data against the definition?) old_data = copy.deepcopy(self.config.data) conf_part = data.find_no_exc(self.config.data, module_name) + update_cmd = None + use_part = None if conf_part: data.merge(conf_part, cmd) - update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE, - conf_part) - seq = self.cc.group_sendmsg(update_cmd, module_name) - try: - answer, env = self.cc.group_recvmsg(False, seq) - except isc.cc.SessionTimeout: - answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name) + use_part = conf_part else: conf_part = data.set(self.config.data, module_name, {}) data.merge(conf_part[module_name], cmd) - # send out changed info - update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE, - conf_part[module_name]) + use_part = conf_part[module_name] + + # The command to send + update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE, + use_part) + + # TODO: This design might need some revisiting. We might want some + # polymorphism instead of branching. But it just might turn out it + # will get solved by itself when we move everything to virtual modules + # (which is possible solution to the offline configuration problem) + # or when we solve the incorect behaviour here when a config is + # rejected (spying modules don't know it was rejected and some modules + # might have been commited already). + if module_name in self.virtual_modules: + # The module is virtual, so call it to get the answer + try: + error = self.virtual_modules[module_name](use_part) + if error is None: + answer = ccsession.create_answer(0) + # OK, it is successful, send the notify, but don't wait + # for answer + seq = self.cc.group_sendmsg(update_cmd, module_name) + else: + answer = ccsession.create_answer(1, error) + # Make sure just a validating plugin don't kill the whole manager + except Exception as excp: + # Provide answer + answer = ccsession.create_answer(1, "Exception: " + str(excp)) + else: + # Real module, send it over the wire to it + # send out changed info and wait for answer seq = self.cc.group_sendmsg(update_cmd, module_name) - # replace 'our' answer with that of the module try: + # replace 'our' answer with that of the module answer, env = self.cc.group_recvmsg(False, seq) except isc.cc.SessionTimeout: answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name) diff --git a/src/lib/python/isc/config/tests/cfgmgr_test.py b/src/lib/python/isc/config/tests/cfgmgr_test.py index 9534e14094cd252120f07569d4421a1495478de0..b06db317974b0655136575bf37e6757c2da103d4 100644 --- a/src/lib/python/isc/config/tests/cfgmgr_test.py +++ b/src/lib/python/isc/config/tests/cfgmgr_test.py @@ -135,6 +135,8 @@ class TestConfigManager(unittest.TestCase): self.assert_(module_spec.get_module_name() not in self.cm.module_specs) self.cm.set_module_spec(module_spec) self.assert_(module_spec.get_module_name() in self.cm.module_specs) + self.assert_(module_spec.get_module_name() not in + self.cm.virtual_modules) def test_remove_module_spec(self): module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec") @@ -143,6 +145,30 @@ class TestConfigManager(unittest.TestCase): self.assert_(module_spec.get_module_name() in self.cm.module_specs) self.cm.remove_module_spec(module_spec.get_module_name()) self.assert_(module_spec.get_module_name() not in self.cm.module_specs) + self.assert_(module_spec.get_module_name() not in + self.cm.virtual_modules) + + def test_add_remove_virtual_module(self): + module_spec = isc.config.module_spec.module_spec_from_file( + self.data_path + os.sep + "spec1.spec") + check_func = lambda: True + # Make sure it's not in there before + self.assert_(module_spec.get_module_name() not in self.cm.module_specs) + self.assert_(module_spec.get_module_name() not in + self.cm.virtual_modules) + # Add it there + self.cm.set_virtual_module(module_spec, check_func) + # Check it's in there + self.assert_(module_spec.get_module_name() in self.cm.module_specs) + self.assertEqual(self.cm.module_specs[module_spec.get_module_name()], + module_spec) + self.assertEqual(self.cm.virtual_modules[module_spec.get_module_name()], + check_func) + # Remove it again + self.cm.remove_module_spec(module_spec.get_module_name()) + self.assert_(module_spec.get_module_name() not in self.cm.module_specs) + self.assert_(module_spec.get_module_name() not in + self.cm.virtual_modules) def test_get_module_spec(self): module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec") @@ -312,6 +338,51 @@ class TestConfigManager(unittest.TestCase): }, {'result': [0]}) + def test_set_config_virtual(self): + """Test that if the module is virtual, we don't send it over the + message bus, but call the checking function. + """ + # We run the same three times, with different return values + def single_test(value, returnFunc, expectedResult): + # Because closures can't assign to closed-in variables, we pass + # it trough self + self.called_with = None + def check_test(new_data): + self.called_with = new_data + return returnFunc() + + # Register our virtual module + self.cm.set_virtual_module(self.spec, check_test) + # The fake session will throw now if it tries to read a response. + # Handy, we don't need to find a complicated way to check for it. + result = self.cm._handle_set_config_module(self.spec. + get_module_name(), + {'item1': value}) + # Check the correct result is passed and our function was called + # With correct data + self.assertEqual(self.called_with['item1'], value) + self.assertEqual(result, {'result': expectedResult}) + if expectedResult[0] == 0: + # Check it provided the correct notification + self.assertEqual(len(self.fake_session.message_queue), 1) + self.assertEqual({'command': [ 'config_update', + {'item1': value}]}, + self.fake_session.get_message('Spec2', None)) + # and the queue should now be empty again + self.assertEqual(len(self.fake_session.message_queue), 0) + else: + # It shouldn't send anything on error + self.assertEqual(len(self.fake_session.message_queue), 0) + + # Success + single_test(5, lambda: None, [0]) + # Graceful error + single_test(6, lambda: "Just error", [1, "Just error"]) + # Exception from the checker + def raiser(): + raise Exception("Just exception") + single_test(7, raiser, [1, "Exception: Just exception"]) + def test_set_config_all(self): my_ok_answer = { 'result': [ 0 ] } diff --git a/src/lib/python/isc/notify/tests/Makefile.am b/src/lib/python/isc/notify/tests/Makefile.am index c5f016505d1b676a921d86c93da78e8aa8e99f1e..07129ec76b6e56a0045f5b01d04030675ce93b86 100644 --- a/src/lib/python/isc/notify/tests/Makefile.am +++ b/src/lib/python/isc/notify/tests/Makefile.am @@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS) # required by loadable python modules. LIBRARY_PATH_PLACEHOLDER = if SET_ENV_LIBRARY_PATH -LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH) +LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH) endif # test using command-line arguments, so use check-local target instead of TESTS diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc index 0ee5813318809e1c4dcaaf81c826c6d16e0a0671..c0d5ee64fb1d3c9003cd1c5e98c57f65ed7672af 100644 --- a/src/lib/resolve/recursive_query.cc +++ b/src/lib/resolve/recursive_query.cc @@ -35,15 +35,18 @@ #include #include -#include -#include +#include +#include #include #include using isc::log::dlog; using namespace isc::dns; +using namespace isc::util; +using namespace isc::asiolink; -namespace asiolink { +namespace isc { +namespace asiodns { typedef std::vector > AddressVector; @@ -57,19 +60,19 @@ RecursiveQuery::RecursiveQuery(DNSService& dns_service, const std::vector >& upstream, const std::vector >& upstream_root, int query_timeout, int client_timeout, int lookup_timeout, - unsigned retries) : + unsigned retries) + : dns_service_(dns_service), nsas_(nsas), cache_(cache), upstream_(new AddressVector(upstream)), upstream_root_(new AddressVector(upstream_root)), test_server_("", 0), query_timeout_(query_timeout), client_timeout_(client_timeout), - lookup_timeout_(lookup_timeout), retries_(retries) + lookup_timeout_(lookup_timeout), retries_(retries), rtt_recorder_() { } // Set the test server - only used for unit testing. - void RecursiveQuery::setTestServer(const std::string& address, uint16_t port) { dlog("Setting test server to " + address + "(" + @@ -78,6 +81,11 @@ RecursiveQuery::setTestServer(const std::string& address, uint16_t port) { test_server_.second = port; } +// Set the RTT recorder - only used for testing +void +RecursiveQuery::setRttRecorder(boost::shared_ptr& recorder) { + rtt_recorder_ = recorder; +} namespace { @@ -223,6 +231,10 @@ private: // event; we can cancel the NSAS callback safely. size_t outstanding_events_; + // RTT Recorder. Used for testing, the RTTs of queries are + // sent to this object as well as being used to update the NSAS. + boost::shared_ptr rtt_recorder_; + // perform a single lookup; first we check the cache to see // if we have a response for our query stored already. if // so, call handlerecursiveresponse(), if not, we call send() @@ -481,7 +493,9 @@ public: int query_timeout, int client_timeout, int lookup_timeout, unsigned retries, isc::nsas::NameserverAddressStore& nsas, - isc::cache::ResolverCache& cache) : + isc::cache::ResolverCache& cache, + boost::shared_ptr& recorder) + : io_(io), question_(question), answer_message_(answer_message), @@ -502,7 +516,8 @@ public: cur_zone_("."), nsas_callback_(new ResolverNSASCallback(this)), nsas_callback_out_(false), - outstanding_events_(0) + outstanding_events_(0), + rtt_recorder_(recorder) { // Setup the timer to stop trying (lookup_timeout) if (lookup_timeout >= 0) { @@ -619,9 +634,11 @@ public: rtt = 1000 * (cur_time.tv_sec - current_ns_qsent_time.tv_sec); rtt += (cur_time.tv_usec - current_ns_qsent_time.tv_usec) / 1000; } - dlog("RTT: " + boost::lexical_cast(rtt)); current_ns_address.updateRTT(rtt); + if (rtt_recorder_) { + rtt_recorder_->addRtt(rtt); + } try { Message incoming(Message::PARSE); @@ -739,7 +756,8 @@ RecursiveQuery::resolve(const QuestionPtr& question, new RunningQuery(io, *question, answer_message, upstream_, test_server_, buffer, callback, query_timeout_, client_timeout_, - lookup_timeout_, retries_, nsas_, cache_); + lookup_timeout_, retries_, nsas_, + cache_, rtt_recorder_); } } } @@ -792,11 +810,10 @@ RecursiveQuery::resolve(const Question& question, new RunningQuery(io, question, answer_message, upstream_, test_server_, buffer, crs, query_timeout_, client_timeout_, lookup_timeout_, retries_, - nsas_, cache_); + nsas_, cache_, rtt_recorder_); } } } - - -} // namespace asiolink +} // namespace asiodns +} // namespace isc diff --git a/src/lib/resolve/recursive_query.h b/src/lib/resolve/recursive_query.h index 1180d5599fd2fcd7a987cd02dcf9101e03ffa4b5..c082426b4af574196219f93c041f1731c5086f2c 100644 --- a/src/lib/resolve/recursive_query.h +++ b/src/lib/resolve/recursive_query.h @@ -15,18 +15,49 @@ #ifndef __RECURSIVE_QUERY_H #define __RECURSIVE_QUERY_H 1 -#include -#include -#include +#include +#include +#include #include #include -namespace asiolink { -/// \brief The \c RecursiveQuery class provides a layer of abstraction around -/// the ASIO code that carries out an upstream query. +namespace isc { +namespace asiodns { + +/// \brief RTT Recorder +/// +/// Used for testing, this class will hold the set of round-trip times to +/// nameservers for the current recursive query. +/// +/// A pointer to an object of this class is passed to RecursiveQuery which in +/// turn passes it to the created RunningQuery class. When a running query +/// completes, its RTT is passed to the RTT Recorder object. +class RttRecorder { +public: + /// \brief Record Time + /// + /// Adds a round-trip time to the internal vector of times. + /// + /// \param RTT to record. + void addRtt(uint32_t rtt) { + rtt_.push_back(rtt); + } + + /// \brief Return RTT Vector + std::vector getRtt() const { + return rtt_; + } + +private: + std::vector rtt_; ///< Stored round-trip times +}; + + +/// \brief Recursive Query /// -/// This design is very preliminary; currently it is only capable of -/// handling simple forward requests to a single resolver. +/// The \c RecursiveQuery class provides a layer of abstraction around +/// the ASIO code that carries out an upstream query. + class RecursiveQuery { /// /// \name Constructors @@ -56,17 +87,25 @@ public: isc::nsas::NameserverAddressStore& nsas, isc::cache::ResolverCache& cache, const std::vector >& - upstream, + upstream, const std::vector >& - upstream_root, + upstream_root, int query_timeout = 2000, int client_timeout = 4000, int lookup_timeout = 30000, unsigned retries = 3); //@} + /// \brief Set Round-Trip Time Recorder + /// + /// Sets the RTT recorder object. This is not accessed directly, instead + /// it is passed to created RunningQuery objects. + /// + /// \param recorder Pointer to the RTT recorder object used to hold RTTs. + void setRttRecorder(boost::shared_ptr& recorder); + /// \brief Initiate resolving - /// + /// /// When sendQuery() is called, a (set of) message(s) is sent /// asynchronously. If upstream servers are set, one is chosen /// and the response (if any) from that server will be returned. @@ -99,7 +138,7 @@ public: /// \param server A pointer to the \c DNSServer object handling the client void resolve(const isc::dns::Question& question, isc::dns::MessagePtr answer_message, - isc::dns::OutputBufferPtr buffer, + isc::util::OutputBufferPtr buffer, DNSServer* server); /// \brief Set Test Server @@ -113,7 +152,7 @@ public: /// \param address IP address of the test server. /// \param port Port number of the test server void setTestServer(const std::string& address, uint16_t port); - + private: DNSService& dns_service_; isc::nsas::NameserverAddressStore& nsas_; @@ -127,7 +166,9 @@ private: int client_timeout_; int lookup_timeout_; unsigned retries_; + boost::shared_ptr rtt_recorder_; ///< Round-trip time recorder }; -} // namespace asiolink +} // namespace asiodns +} // namespace isc #endif // __RECURSIVE_QUERY_H diff --git a/src/lib/resolve/resolver_callback.h b/src/lib/resolve/resolver_callback.h index 4244f195ed0afd4fa8a32bc981fd80d6022701ad..79138e832b1ef71efb918b028a896baadf57b23e 100644 --- a/src/lib/resolve/resolver_callback.h +++ b/src/lib/resolve/resolver_callback.h @@ -15,7 +15,7 @@ #ifndef _ISC_RESOLVER_CALLBACK_H #define _ISC_RESOLVER_CALLBACK_H 1 -#include +#include #include #include @@ -33,7 +33,7 @@ namespace resolve { /// as the server itself should also have a reference. class ResolverCallbackServer : public ResolverInterface::Callback { public: - ResolverCallbackServer(asiolink::DNSServer* server) : + ResolverCallbackServer(asiodns::DNSServer* server) : server_(server->clone()) {} ~ResolverCallbackServer() { delete server_; }; @@ -41,7 +41,7 @@ public: void failure(); private: - asiolink::DNSServer* server_; + asiodns::DNSServer* server_; }; } //namespace resolve diff --git a/src/lib/resolve/tests/Makefile.am b/src/lib/resolve/tests/Makefile.am index a403272920365505dce4e27386c4821abb3e6187..edea7cd5a8825c929c0931f7a190e57686905b93 100644 --- a/src/lib/resolve/tests/Makefile.am +++ b/src/lib/resolve/tests/Makefile.am @@ -27,6 +27,7 @@ run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la +run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la run_unittests_LDADD += $(top_builddir)/src/lib/resolve/libresolve.la run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la diff --git a/src/lib/resolve/tests/recursive_query_unittest.cc b/src/lib/resolve/tests/recursive_query_unittest.cc index ab1ffa322904ad3f9464194587a3f64777f80a20..3338893651c1a734f7dc3d213da882f384bcdd59 100644 --- a/src/lib/resolve/tests/recursive_query_unittest.cc +++ b/src/lib/resolve/tests/recursive_query_unittest.cc @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include @@ -45,17 +45,19 @@ // If we need to test something at the level of underlying ASIO and need // their definition, that test should go to asiolink/internal/tests. #include +#include #include #include #include #include -#include #include using isc::UnitTestUtil; using namespace std; -using namespace asiolink; +using namespace isc::asiodns; +using namespace isc::asiolink; using namespace isc::dns; +using namespace isc::util; namespace { const char* const TEST_SERVER_PORT = "53535"; @@ -316,10 +318,10 @@ protected: private: // Currently unused; these will be used for testing // asynchronous lookup calls via the asyncLookup() method - boost::shared_ptr io_message_; + boost::shared_ptr io_message_; isc::dns::MessagePtr message_; isc::dns::MessagePtr answer_message_; - isc::dns::OutputBufferPtr respbuf_; + isc::util::OutputBufferPtr respbuf_; // Callback functions provided by the caller const SimpleCallback* checkin_; diff --git a/src/lib/resolve/tests/recursive_query_unittest_2.cc b/src/lib/resolve/tests/recursive_query_unittest_2.cc index 643c5a3aa2fecf827c14205bfac8e89eaec1d0a1..3e62336d5e223cb2046db2afca96e9409bbeea47 100644 --- a/src/lib/resolve/tests/recursive_query_unittest_2.cc +++ b/src/lib/resolve/tests/recursive_query_unittest_2.cc @@ -17,13 +17,16 @@ #include #include #include +#include #include #include #include -#include +#include +#include + #include #include #include @@ -35,19 +38,21 @@ #include #include -#include -#include +#include +#include +#include #include #include -#include #include #include #include using namespace asio; using namespace asio::ip; +using namespace isc::asiolink; using namespace isc::dns; using namespace isc::dns::rdata; +using namespace isc::util; using namespace isc::resolve; using namespace std; @@ -71,7 +76,8 @@ using namespace std; /// directed to one or other of the "servers" in the RecursiveQueryTest2 class, /// regardless of the glue returned in referrals. -namespace asiolink { +namespace isc { +namespace asiodns { const std::string TEST_ADDRESS = "127.0.0.1"; ///< Servers are on this address const uint16_t TEST_PORT = 5301; ///< ... and this port @@ -649,13 +655,17 @@ TEST_F(RecursiveQueryTest2, Resolve) { boost::bind(&RecursiveQueryTest2::tcpAcceptHandler, this, _1, 0)); - // Set up the RecursiveQuery object. + // Set up the RecursiveQuery object. We will also test that it correctly records + // RTT times by setting up a RTT recorder object as well. std::vector > upstream; // Empty std::vector > upstream_root; // Empty RecursiveQuery query(dns_service_, *nsas_, cache_, upstream, upstream_root); query.setTestServer(TEST_ADDRESS, TEST_PORT); + boost::shared_ptr recorder(new RttRecorder()); + query.setRttRecorder(recorder); + // Set up callback to receive notification that the query has completed. isc::resolve::ResolverInterface::CallbackPtr resolver_callback(new ResolverCallback(service_)); @@ -672,6 +682,17 @@ TEST_F(RecursiveQueryTest2, Resolve) { ResolverCallback* rc = static_cast(resolver_callback.get()); EXPECT_TRUE(rc->getRun()); EXPECT_TRUE(rc->getStatus()); + + // Finally, check that all the RTTs were "reasonable" (defined here as + // being below 2 seconds). This is an explicit check to test that the + // variables in the RTT calculation are at least being initialized; if they + // weren't, we would expect some absurdly high answers. + vector rtt = recorder->getRtt(); + EXPECT_GT(rtt.size(), 0); + for (int i = 0; i < rtt.size(); ++i) { + EXPECT_LT(rtt[i], 2000); + } } -} // namespace asiolink +} // namespace asiodns +} // namespace isc diff --git a/src/lib/resolve/tests/resolver_callback_unittest.cc b/src/lib/resolve/tests/resolver_callback_unittest.cc index 666b853449a78578fd8d0f22c36a0c50177e5c4f..e94f13d56b93f1ebdcb827c7594a29d3b1aa33c3 100644 --- a/src/lib/resolve/tests/resolver_callback_unittest.cc +++ b/src/lib/resolve/tests/resolver_callback_unittest.cc @@ -13,7 +13,7 @@ // PERFORMANCE OF THIS SOFTWARE. #include -#include +#include #include using namespace isc::resolve; @@ -22,7 +22,7 @@ using namespace isc::resolve; // We want to check if resume is called // Since the server will get cloned(), we want the clones to share // our bools for whether resume got called and with what value -class DummyServer : public asiolink::DNSServer { +class DummyServer : public isc::asiodns::DNSServer { public: DummyServer(DummyServer* orig) { resume_called_ = orig->getResumeCalled(); @@ -31,10 +31,10 @@ public: DummyServer(bool* resume_called, bool* resume_value) : resume_called_(resume_called), resume_value_(resume_value) {} - + bool* getResumeCalled() { return resume_called_; } bool* getResumeValue() { return resume_value_; } - + DNSServer* clone() { DummyServer* n = new DummyServer(this); return n; diff --git a/src/lib/server_common/portconfig.cc b/src/lib/server_common/portconfig.cc index 1251ba1f569a496ad42e0fa8278ba79390a374e9..7b2b3ddc27066dc35888ad5efec684c87a5d6479 100644 --- a/src/lib/server_common/portconfig.cc +++ b/src/lib/server_common/portconfig.cc @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include @@ -23,7 +23,8 @@ using namespace std; using namespace isc::data; -using namespace asiolink; +using namespace isc::asiolink; +using namespace isc::asiodns; using isc::log::dlog; namespace isc { @@ -82,7 +83,7 @@ setAddresses(DNSService& service, const AddressList& addresses) { void installListenAddresses(const AddressList& newAddresses, AddressList& addressStore, - asiolink::DNSService& service) + isc::asiodns::DNSService& service) { try { dlog("Setting listen addresses:"); diff --git a/src/lib/server_common/portconfig.h b/src/lib/server_common/portconfig.h index bcb85286ba383889c46485932db1c17b54a61a3a..e4e7bf6570511e26a6d11ad71966694f01799a4e 100644 --- a/src/lib/server_common/portconfig.h +++ b/src/lib/server_common/portconfig.h @@ -25,9 +25,11 @@ /* * Some forward declarations. */ -namespace asiolink { +namespace isc { +namespace asiodns { class DNSService; } +} namespace isc { namespace server_common { @@ -112,7 +114,7 @@ parseAddresses(isc::data::ConstElementPtr addresses, void installListenAddresses(const AddressList& newAddresses, AddressList& addressStore, - asiolink::DNSService& dnsService); + asiodns::DNSService& dnsService); } } diff --git a/src/lib/server_common/tests/Makefile.am b/src/lib/server_common/tests/Makefile.am index 55ccc85a4f93cb3ce2df01be33cca7b70c93a557..a04a8843126dfaa6b898bb50763e05410f81d83f 100644 --- a/src/lib/server_common/tests/Makefile.am +++ b/src/lib/server_common/tests/Makefile.am @@ -12,7 +12,7 @@ endif # Some versions of GCC warn about some versions of Boost regarding # missing initializer for members in its posix_time. # https://svn.boost.org/trac/boost/ticket/3477 -# But older GCC compilers don't have the flag. +# But older GCC compilers don't have the flag. AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG) if USE_CLANGPP @@ -35,6 +35,7 @@ run_unittests_LDADD = $(GTEST_LDADD) run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la +run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la endif diff --git a/src/lib/server_common/tests/portconfig_unittest.cc b/src/lib/server_common/tests/portconfig_unittest.cc index 569450319432ff68177c12ba1fa7272fa470b0d3..65963eb31c2ce165ee1c048a97d6d1aa57fa4d34 100644 --- a/src/lib/server_common/tests/portconfig_unittest.cc +++ b/src/lib/server_common/tests/portconfig_unittest.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,7 +26,8 @@ using namespace isc::server_common::portconfig; using namespace isc::data; using namespace isc; using namespace std; -using namespace asiolink; +using namespace isc::asiolink; +using namespace isc::asiodns; namespace { diff --git a/src/lib/testutils/mockups.h b/src/lib/testutils/mockups.h index 4bec83da3f202a1091973d7a21fca534551f0b65..2441ad798bebeaf77d0708792a2a25c33b3c63b7 100644 --- a/src/lib/testutils/mockups.h +++ b/src/lib/testutils/mockups.h @@ -19,7 +19,7 @@ #include -#include +#include // A minimal mock configuration session. Most the methods are // stubbed out, except for a very basic group_sendmsg() and @@ -94,7 +94,7 @@ private: }; // A nonoperative DNSServer object to be used in calls to processMessage(). -class MockServer : public asiolink::DNSServer { +class MockServer : public isc::asiodns::DNSServer { public: MockServer() : done_(false) {} void operator()(asio::error_code, size_t) {} diff --git a/src/lib/testutils/srv_test.cc b/src/lib/testutils/srv_test.cc index d5da8a0c3b710d1739fbd91aadfaa9595fbf4689..1d79d71f3428d928c01ce8aa9e5ce078cfa256d7 100644 --- a/src/lib/testutils/srv_test.cc +++ b/src/lib/testutils/srv_test.cc @@ -27,7 +27,8 @@ #include using namespace isc::dns; -using namespace asiolink; +using namespace isc::util; +using namespace isc::asiolink; namespace isc { namespace testutils { @@ -205,7 +206,7 @@ SrvTestBase::ednsBadVers() { opcode.getCode(), QR_FLAG, 1, 0, 0, 1); EXPECT_FALSE(parse_message->getEDNS()); // EDNS isn't added at this point - isc::dns::InputBuffer ib(response_obuffer->getData(), + InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength()); isc::dns::Message parsed(isc::dns::Message::PARSE); parsed.fromWire(ib); diff --git a/src/lib/testutils/srv_test.h b/src/lib/testutils/srv_test.h index 7361a769636889cc4c118b6b9734a0cdbee5c373..a848ffc9650d5cfb304582dc4b6e2e462d6bd70b 100644 --- a/src/lib/testutils/srv_test.h +++ b/src/lib/testutils/srv_test.h @@ -12,7 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include +#include #include #include #include @@ -99,9 +99,9 @@ protected: asiolink::IOSocket* io_sock; asiolink::IOMessage* io_message; const asiolink::IOEndpoint* endpoint; - isc::dns::OutputBuffer request_obuffer; + isc::util::OutputBuffer request_obuffer; isc::dns::MessageRenderer request_renderer; - isc::dns::OutputBufferPtr response_obuffer; + isc::util::OutputBufferPtr response_obuffer; std::vector data; }; } // end of namespace testutils diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am index 3e74708405b06d9426ac88d096e49e256c9004d1..77a3e4a1edf0a154c8196ee0957f1790a857727a 100644 --- a/src/lib/util/Makefile.am +++ b/src/lib/util/Makefile.am @@ -1,3 +1,28 @@ -SUBDIRS = io unittests io/tests +SUBDIRS = . tests unittests io # The io/tests is hack, because otherwise we can not order these directories # properly. Unittests use io and io/tests use unittest. + +AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/exceptions -I$(top_builddir)/src/lib/exceptions +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CXXFLAGS = $(B10_CXXFLAGS) + +lib_LTLIBRARIES = libutil.la +libutil_la_SOURCES = filename.h filename.cc +libutil_la_SOURCES += locks.h lru_list.h +libutil_la_SOURCES += strutil.h strutil.cc +libutil_la_SOURCES += buffer.h io_utilities.h +libutil_la_SOURCES += time_utilities.h time_utilities.cc +libutil_la_SOURCES += hash/sha1.h hash/sha1.cc +libutil_la_SOURCES += encode/base16_from_binary.h +libutil_la_SOURCES += encode/base32hex.h encode/base64.h +libutil_la_SOURCES += encode/base32hex_from_binary.h +libutil_la_SOURCES += encode/base_n.cc encode/hex.h +libutil_la_SOURCES += encode/binary_from_base32hex.h +libutil_la_SOURCES += encode/binary_from_base16.h +libutil_la_SOURCES += random/qid_gen.h random/qid_gen.cc +libutil_la_SOURCES += random/random_number_generator.h + +libutil_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la +CLEANFILES = *.gcno *.gcda diff --git a/src/lib/dns/buffer.h b/src/lib/util/buffer.h similarity index 99% rename from src/lib/dns/buffer.h rename to src/lib/util/buffer.h index 46a9bf4e1375b4416f738516890d15a603aca3bf..b7a8e283fa2f22c3df08711b6d75311a8dc4e342 100644 --- a/src/lib/dns/buffer.h +++ b/src/lib/util/buffer.h @@ -28,7 +28,7 @@ #include namespace isc { -namespace dns { +namespace util { /// /// \brief A standard DNS module exception that is thrown if an out-of-range @@ -515,8 +515,8 @@ private: typedef boost::shared_ptr InputBufferPtr; typedef boost::shared_ptr OutputBufferPtr; -} -} +} // namespace util +} // namespace isc #endif // __BUFFER_H // Local Variables: diff --git a/src/lib/dns/util/base16_from_binary.h b/src/lib/util/encode/base16_from_binary.h similarity index 100% rename from src/lib/dns/util/base16_from_binary.h rename to src/lib/util/encode/base16_from_binary.h diff --git a/src/lib/dns/util/base32hex.h b/src/lib/util/encode/base32hex.h similarity index 95% rename from src/lib/dns/util/base32hex.h rename to src/lib/util/encode/base32hex.h index cba172ed8753b6bc0025dc99c148ddcd1c023f06..d7129d74a65de897c523170230aaacf8b731a853 100644 --- a/src/lib/dns/util/base32hex.h +++ b/src/lib/util/encode/base32hex.h @@ -26,7 +26,8 @@ // namespace isc { -namespace dns { +namespace util { +namespace encode { /// \brief Encode binary data in the base32hex format. /// @@ -51,8 +52,10 @@ std::string encodeBase32Hex(const std::vector& binary); /// \param input A text encoded in the base32hex format. /// \param result A vector in which the decoded %data is to be stored. void decodeBase32Hex(const std::string& input, std::vector& result); -} -} + +} // namespace encode +} // namespace util +} // namespace isc #endif // __BASE32HEX_H diff --git a/src/lib/dns/util/base32hex_from_binary.h b/src/lib/util/encode/base32hex_from_binary.h similarity index 100% rename from src/lib/dns/util/base32hex_from_binary.h rename to src/lib/util/encode/base32hex_from_binary.h diff --git a/src/lib/dns/util/base64.h b/src/lib/util/encode/base64.h similarity index 96% rename from src/lib/dns/util/base64.h rename to src/lib/util/encode/base64.h index 46e10a69ea0eb8988453ea05c445b0db789a7518..6b1b3465845e264d95ac95cbf02830c4e30aeac6 100644 --- a/src/lib/dns/util/base64.h +++ b/src/lib/util/encode/base64.h @@ -26,7 +26,8 @@ // namespace isc { -namespace dns { +namespace util { +namespace encode { /// \brief Encode binary data in the base64 format. /// @@ -66,8 +67,10 @@ std::string encodeBase64(const std::vector& binary); /// \param input A text encoded in the base64 format. /// \param result A vector in which the decoded %data is to be stored. void decodeBase64(const std::string& input, std::vector& result); -} -} + +} // namespace encode +} // namespace util +} // namespace isc #endif // __BASE64_H diff --git a/src/lib/dns/util/base_n.cc b/src/lib/util/encode/base_n.cc similarity index 97% rename from src/lib/dns/util/base_n.cc rename to src/lib/util/encode/base_n.cc index 9d0c777b0044be6aa7bbcbe2077e33f58df249ea..e79f11d11f0373ce0f37e3cc9441d87d16013cca 100644 --- a/src/lib/dns/util/base_n.cc +++ b/src/lib/util/encode/base_n.cc @@ -23,22 +23,21 @@ #include #include -#include -#include - -#include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include - using namespace std; using namespace boost::archive::iterators; namespace isc { -namespace dns { +namespace util { +namespace encode { // In the following anonymous namespace, we provide a generic framework // to encode/decode baseN format. We use the following tools: @@ -394,5 +393,6 @@ decodeHex(const string& input, vector& result) { Base16Transformer::decode("base16", input, result); } -} -} +} // namespace encode +} // namespace util +} // namespace isc diff --git a/src/lib/dns/util/binary_from_base16.h b/src/lib/util/encode/binary_from_base16.h similarity index 100% rename from src/lib/dns/util/binary_from_base16.h rename to src/lib/util/encode/binary_from_base16.h diff --git a/src/lib/dns/util/binary_from_base32hex.h b/src/lib/util/encode/binary_from_base32hex.h similarity index 100% rename from src/lib/dns/util/binary_from_base32hex.h rename to src/lib/util/encode/binary_from_base32hex.h diff --git a/src/lib/dns/util/hex.h b/src/lib/util/encode/hex.h similarity index 95% rename from src/lib/dns/util/hex.h rename to src/lib/util/encode/hex.h index e2626bf1d7e998da0eb0e3614e7235c439f9d6e5..5c806fcfaada4b7aa57a0bb2a4e10dda3473c172 100644 --- a/src/lib/dns/util/hex.h +++ b/src/lib/util/encode/hex.h @@ -26,7 +26,8 @@ // namespace isc { -namespace dns { +namespace util { +namespace encode { /// \brief Encode binary data in the base16 ('hex') format. /// /// The underlying implementation is shared with \c encodeBase64, and most of @@ -52,8 +53,10 @@ std::string encodeHex(const std::vector& binary); /// \param input A text encoded in the base16 format. /// \param result A vector in which the decoded %data is to be stored. void decodeHex(const std::string& input, std::vector& result); -} -} + +} // namespace encode +} // namespace util +} // namespace isc #endif // __HEX_H diff --git a/src/lib/log/filename.cc b/src/lib/util/filename.cc similarity index 93% rename from src/lib/log/filename.cc rename to src/lib/util/filename.cc index 91835afebcebc0d026456353cb24d70023a04d6d..1f2e5db43c671901f59e3a3c1db897ab586b84a8 100644 --- a/src/lib/log/filename.cc +++ b/src/lib/util/filename.cc @@ -18,14 +18,13 @@ #include -#include -#include +#include using namespace std; namespace isc { -namespace log { +namespace util { // Split string into components. Any backslashes are assumed to have // been replaced by forward slashes. @@ -91,9 +90,9 @@ Filename::expandWithDefault(const string& defname) const { string def_extension(""); // Normalize the input string. - string copy_defname = isc::strutil::trim(defname); + string copy_defname = isc::util::str::trim(defname); #ifdef WIN32 - isc::strutil::normalizeSlash(copy_defname); + isc::util::str::normalizeSlash(copy_defname); #endif // Split into the components @@ -117,9 +116,9 @@ Filename::useAsDefault(const string& name) const { string name_extension(""); // Normalize the input string. - string copy_name = isc::strutil::trim(name); + string copy_name = isc::util::str::trim(name); #ifdef WIN32 - isc::strutil::normalizeSlash(copy_name); + isc::util::str::normalizeSlash(copy_name); #endif // Split into the components diff --git a/src/lib/log/filename.h b/src/lib/util/filename.h similarity index 97% rename from src/lib/log/filename.h rename to src/lib/util/filename.h index e3cda1684fabcb49967df92a58ddc4f87f2197f2..984ecb08d56e3a099ac8c8b6a66c353eb05a394a 100644 --- a/src/lib/log/filename.h +++ b/src/lib/util/filename.h @@ -17,10 +17,10 @@ #include -#include +#include namespace isc { -namespace log { +namespace util { /// \brief Class to Manipulate Filenames /// @@ -69,9 +69,9 @@ public: /// /// \param name New name to replaced currently stored name void setName(const std::string& name) { - full_name_ = isc::strutil::trim(name); + full_name_ = isc::util::str::trim(name); #ifdef WIN32 - isc::strutil::normalizeSlash(full_name_); + isc::util::str::normalizeSlash(full_name_); #endif split(full_name_, directory_, name_, extension_); } @@ -155,7 +155,7 @@ private: std::string extension_; ///< Extension part }; -} // namespace log +} // namespace util } // namespace isc #endif // __FILENAME_H diff --git a/src/lib/dns/util/sha1.cc b/src/lib/util/hash/sha1.cc similarity index 99% rename from src/lib/dns/util/sha1.cc rename to src/lib/util/hash/sha1.cc index 62e885b34dc318c3d60095b84604eeb72e08a73c..091e29316a0d1dd7c46be627f5f89fdb335e3e58 100644 --- a/src/lib/dns/util/sha1.cc +++ b/src/lib/util/hash/sha1.cc @@ -50,7 +50,11 @@ * without express or implied warranty of any kind. * */ -#include +#include + +namespace isc { +namespace util { +namespace hash { /* Local Function Prototyptes */ static void SHA1Finalize(SHA1Context *, uint8_t Pad_Byte); @@ -482,3 +486,7 @@ SHA1ProcessMessageBlock(SHA1Context *context) { context->Message_Block_Index = 0; } + +} // namespace hash +} // namespace util +} // namespace isc diff --git a/src/lib/dns/util/sha1.h b/src/lib/util/hash/sha1.h similarity index 96% rename from src/lib/dns/util/sha1.h rename to src/lib/util/hash/sha1.h index f0f45f35bccf39b062761d70f9cafb63eb147a3b..6089ca8eaeb50733d61f650a45efd54b8e4c22b9 100644 --- a/src/lib/dns/util/sha1.h +++ b/src/lib/util/hash/sha1.h @@ -34,6 +34,10 @@ #define _SHA1_H_ #include + +namespace isc { +namespace util { +namespace hash { /* * If you do not have the ISO standard stdint.h header file, then you * must typdef the following: @@ -81,4 +85,7 @@ extern int SHA1FinalBits(SHA1Context *, const uint8_t bits, unsigned int bitcount); extern int SHA1Result(SHA1Context *, uint8_t Message_Digest[SHA1_HASHSIZE]); +} // namespace hash +} // namespace util +} // namespace isc #endif diff --git a/src/lib/util/io/Makefile.am b/src/lib/util/io/Makefile.am index b2653d8b34e7136fb13b18674e4a4c56230a7ccc..9f06ef9f789d6fa7c2157c4bead04e6c8764f07b 100644 --- a/src/lib/util/io/Makefile.am +++ b/src/lib/util/io/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = . tests + AM_CXXFLAGS = $(B10_CXXFLAGS) lib_LTLIBRARIES = libutil_io.la diff --git a/src/lib/asiolink/asiolink_utilities.h b/src/lib/util/io_utilities.h similarity index 87% rename from src/lib/asiolink/asiolink_utilities.h rename to src/lib/util/io_utilities.h index 659e6a0908727bb0653cd0f8b81f126c0fdd653c..ecab3cea757c328e2e87daf19eb64c527828015a 100644 --- a/src/lib/asiolink/asiolink_utilities.h +++ b/src/lib/util/io_utilities.h @@ -12,16 +12,17 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#ifndef __ASIOLINK_UTILITIES_H -#define __ASIOLINK_UTILITIES_H +#ifndef __IO_UTILITIES_H +#define __IO_UTILITIES_H #include -namespace asiolink { +namespace isc { +namespace util { /// \brief Read Unsigned 16-Bit Integer from Buffer /// -/// This is essentially a copy of the isc::dns::InputBuffer::readUint16. It +/// This is essentially a copy of the isc::util::InputBuffer::readUint16. It /// should really be moved into a separate library. /// /// \param buffer Data buffer at least two bytes long of which the first two @@ -41,7 +42,7 @@ readUint16(const void* buffer) { /// \brief Write Unisgned 16-Bit Integer to Buffer /// -/// This is essentially a copy of isc::dns::OutputBuffer::writeUint16. It +/// This is essentially a copy of isc::util::OutputBuffer::writeUint16. It /// should really be moved into a separate library. /// /// \param value 16-bit value to convert @@ -56,6 +57,7 @@ writeUint16(uint16_t value, void* buffer) { byte_buffer[1] = static_cast(value & 0x00ffU); } -} // namespace asiolink +} // namespace util +} // namespace isc #endif // __ASIOLINK_UTILITIES_H diff --git a/src/lib/nsas/locks.h b/src/lib/util/locks.h similarity index 95% rename from src/lib/nsas/locks.h rename to src/lib/util/locks.h index 695ad563c2d1753419da4e20bc0542b99e665f6b..971c413a6f85e478effb16d61a7dfc06d7d0a204 100644 --- a/src/lib/nsas/locks.h +++ b/src/lib/util/locks.h @@ -33,6 +33,7 @@ #ifndef USE_BOOST_THREADS namespace isc { +namespace util { namespace locks { class mutex { @@ -59,8 +60,9 @@ public: void unlock() {} }; -} -} +} // namespace locks +} // namespace util +} // namespace isc #else // USE_BOOST_THREADS @@ -83,6 +85,7 @@ public: #include namespace isc { +namespace util { namespace locks { typedef boost::mutex mutex; @@ -102,8 +105,9 @@ public: scoped_lock(T& mtype) : boost::interprocess::scoped_lock(mtype) { } }; -} -} +} // namespace locks +} // namespace util +} // namespace isc #endif // USE_BOOST_THREADS diff --git a/src/lib/nsas/lru_list.h b/src/lib/util/lru_list.h similarity index 95% rename from src/lib/nsas/lru_list.h rename to src/lib/util/lru_list.h index b057bafa2418aec4f538214c0ff5727ba0233c9a..797c3c91707deb54a78aeb6575f7ec9d4062c35a 100644 --- a/src/lib/nsas/lru_list.h +++ b/src/lib/util/lru_list.h @@ -21,10 +21,10 @@ #include #include -#include "locks.h" +#include namespace isc { -namespace nsas { +namespace util { /// \brief LRU List /// @@ -146,7 +146,7 @@ public: } private: - isc::locks::mutex mutex_; ///< List protection + locks::mutex mutex_; ///< List protection std::list > lru_; ///< The LRU list itself uint32_t max_size_; ///< Max size of the list uint32_t count_; ///< Count of elements @@ -158,7 +158,7 @@ template void LruList::add(boost::shared_ptr& element) { // Protect list against concurrent access - isc::locks::scoped_lock lock(mutex_); + locks::scoped_lock lock(mutex_); // Add the entry and set its pointer field to point into the list. // insert() is used to get the pointer. @@ -207,7 +207,7 @@ void LruList::remove(boost::shared_ptr& element) { if (element->iteratorValid()) { // Is valid, so protect list against concurrent access - isc::locks::scoped_lock lock(mutex_); + locks::scoped_lock lock(mutex_); lru_.erase(element->getLruIterator()); // Remove element from list element->invalidateIterator(); // Invalidate pointer @@ -223,7 +223,7 @@ void LruList::touch(boost::shared_ptr& element) { if (element->iteratorValid()) { // Protect list against concurrent access - isc::locks::scoped_lock lock(mutex_); + locks::scoped_lock lock(mutex_); // Move the element to the end of the list. lru_.splice(lru_.end(), lru_, element->getLruIterator()); @@ -239,7 +239,7 @@ void LruList::touch(boost::shared_ptr& element) { template void LruList::clear() { // Protect list against concurrent access - isc::locks::scoped_lock lock(mutex_); + locks::scoped_lock lock(mutex_); // ... and update the count while we have the mutex. count_ = 0; @@ -254,7 +254,7 @@ void LruList::clear() { lru_.clear(); } -} // namespace nsas +} // namespace util } // namespace isc #endif // __LRU_LIST_H diff --git a/src/lib/asiolink/qid_gen.cc b/src/lib/util/random/qid_gen.cc similarity index 88% rename from src/lib/asiolink/qid_gen.cc rename to src/lib/util/random/qid_gen.cc index 4063b39511ed22f8457be4e564d1bf90ee92e078..43041addcff09b675d564fbed355b4ed212a60a5 100644 --- a/src/lib/asiolink/qid_gen.cc +++ b/src/lib/util/random/qid_gen.cc @@ -18,15 +18,15 @@ // (and other parts where we need randomness, perhaps another thing // for a general libutil?) -#include +#include #include -namespace { - asiolink::QidGenerator qid_generator_instance; -} +namespace isc { +namespace util { +namespace random { -namespace asiolink { +QidGenerator qid_generator_instance; QidGenerator& QidGenerator::getInstance() { @@ -46,9 +46,12 @@ QidGenerator::seed() { generator_.seed((tv.tv_sec * 1000000) + tv.tv_usec); } -isc::dns::qid_t +uint16_t QidGenerator::generateQid() { return (vgen_()); } -} // namespace asiolink + +} // namespace random +} // namespace util +} // namespace isc diff --git a/src/lib/asiolink/qid_gen.h b/src/lib/util/random/qid_gen.h similarity index 95% rename from src/lib/asiolink/qid_gen.h rename to src/lib/util/random/qid_gen.h index a5caa17d83ef7d7dd69ce8d6696ec28f5818ef97..1af43c1fad8bc7beb901997c17b3b51f5977977b 100644 --- a/src/lib/asiolink/qid_gen.h +++ b/src/lib/util/random/qid_gen.h @@ -21,13 +21,13 @@ #ifndef __QID_GEN_H #define __QID_GEN_H -#include #include #include #include - -namespace asiolink { +namespace isc { +namespace util { +namespace random { /// This class generates Qids for outgoing queries /// @@ -55,7 +55,7 @@ public: /// Generate a Qid /// /// \return A random Qid - isc::dns::qid_t generateQid(); + uint16_t generateQid(); /// \brief Seeds the QidGenerator (based on the current time) /// @@ -80,6 +80,8 @@ private: }; -} // namespace asiolink +} // namespace random +} // namespace util +} // namespace isc #endif // __QID_GEN_H diff --git a/src/lib/nsas/random_number_generator.h b/src/lib/util/random/random_number_generator.h similarity index 98% rename from src/lib/nsas/random_number_generator.h rename to src/lib/util/random/random_number_generator.h index 8884d0e7bdef2b7ff40ccd0dd22b9a508659ea0f..485ea7a2e5e333e105a368f248308ffdb6c25c43 100644 --- a/src/lib/nsas/random_number_generator.h +++ b/src/lib/util/random/random_number_generator.h @@ -27,7 +27,8 @@ #include namespace isc { -namespace nsas { +namespace util { +namespace random { class InvalidLimits : public isc::BadValue { public: @@ -200,8 +201,8 @@ private: size_t min_; ///< The minimum integer that will be generated }; -} // namespace dns +} // namespace random +} // namespace util } // namespace isc - #endif//__NSAS_RANDOM_NUMBER_GENERATOR_H diff --git a/src/lib/log/strutil.cc b/src/lib/util/strutil.cc similarity index 97% rename from src/lib/log/strutil.cc rename to src/lib/util/strutil.cc index 65fb0cdad222e73b550b232dfe902933336453f1..161f9acd65f25e82dbb978361d0dcc113e687a77 100644 --- a/src/lib/log/strutil.cc +++ b/src/lib/util/strutil.cc @@ -15,12 +15,13 @@ #include #include -#include +#include using namespace std; namespace isc { -namespace strutil { +namespace util { +namespace str { // Normalize slashes @@ -131,5 +132,6 @@ format(const std::string& format, const std::vector& args) { return (result); } -} // namespace log +} // namespace str +} // namespace util } // namespace isc diff --git a/src/lib/log/strutil.h b/src/lib/util/strutil.h similarity index 97% rename from src/lib/log/strutil.h rename to src/lib/util/strutil.h index 087410f8ae1191d476671cc9af6f5d3a8c9997da..e044c15ff5568fd0edef0c7011a3a24336fe4682 100644 --- a/src/lib/log/strutil.h +++ b/src/lib/util/strutil.h @@ -21,7 +21,8 @@ #include namespace isc { -namespace strutil { +namespace util { +namespace str { /// \brief A Set of C++ Utilities for Manipulating Strings @@ -97,7 +98,7 @@ inline char toUpper(char chr) { /// \param text String to be upper-cased. inline void uppercase(std::string& text) { std::transform(text.begin(), text.end(), text.begin(), - isc::strutil::toUpper); + isc::util::str::toUpper); } /// \brief Lowercase Character @@ -121,7 +122,7 @@ inline char toLower(char chr) { /// \param text String to be lower-cased. inline void lowercase(std::string& text) { std::transform(text.begin(), text.end(), text.begin(), - isc::strutil::toLower); + isc::util::str::toLower); } @@ -139,7 +140,8 @@ std::string format(const std::string& format, const std::vector& args); -} // namespace strutil +} // namespace str +} // namespace util } // namespace isc #endif // __STRUTIL_H diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..7b97202d0b518765f6c47834a4554bd30f847869 --- /dev/null +++ b/src/lib/util/tests/Makefile.am @@ -0,0 +1,41 @@ +SUBDIRS = . + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/exceptions -I$(top_builddir)/src/lib/exceptions +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CXXFLAGS = $(B10_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +CLEANFILES = *.gcno *.gcda + +TESTS = +if HAVE_GTEST +TESTS += run_unittests +run_unittests_SOURCES = +run_unittests_SOURCES += filename_unittest.cc +run_unittests_SOURCES += strutil_unittest.cc +run_unittests_SOURCES += run_unittests.cc +run_unittests_SOURCES += base32hex_unittest.cc +run_unittests_SOURCES += base64_unittest.cc +run_unittests_SOURCES += hex_unittest.cc +run_unittests_SOURCES += sha1_unittest.cc +run_unittests_SOURCES += buffer_unittest.cc +run_unittests_SOURCES += time_utilities_unittest.cc +run_unittests_SOURCES += random_number_generator_unittest.cc +run_unittests_SOURCES += lru_list_unittest.cc +run_unittests_SOURCES += io_utilities_unittest.cc +run_unittests_SOURCES += qid_gen_unittest.cc + +run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) +run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) + +run_unittests_LDADD = $(GTEST_LDADD) +run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la +run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la +endif + +noinst_PROGRAMS = $(TESTS) diff --git a/src/lib/dns/tests/base32hex_unittest.cc b/src/lib/util/tests/base32hex_unittest.cc similarity index 98% rename from src/lib/dns/tests/base32hex_unittest.cc rename to src/lib/util/tests/base32hex_unittest.cc index 253d310f548d6ae9a3a9e2695bcab4c3ddca135c..bf796277b8ccd0e3a8de3b07806f6d535a20badf 100644 --- a/src/lib/dns/tests/base32hex_unittest.cc +++ b/src/lib/util/tests/base32hex_unittest.cc @@ -21,13 +21,13 @@ #include -#include +#include #include using namespace std; using namespace isc; -using namespace isc::dns; +using namespace isc::util::encode; namespace { diff --git a/src/lib/dns/tests/base64_unittest.cc b/src/lib/util/tests/base64_unittest.cc similarity index 97% rename from src/lib/dns/tests/base64_unittest.cc rename to src/lib/util/tests/base64_unittest.cc index 733379322c9b8e74785632fa3f4f13c23dca68f1..c2b27859708e782236a02df69eec0ba7e22949ab 100644 --- a/src/lib/dns/tests/base64_unittest.cc +++ b/src/lib/util/tests/base64_unittest.cc @@ -18,13 +18,13 @@ #include -#include +#include #include using namespace std; using namespace isc; -using namespace isc::dns; +using namespace isc::util::encode; namespace { diff --git a/src/lib/dns/tests/buffer_unittest.cc b/src/lib/util/tests/buffer_unittest.cc similarity index 90% rename from src/lib/dns/tests/buffer_unittest.cc rename to src/lib/util/tests/buffer_unittest.cc index 097391280f69a1bb281906b1507afe0960321dee..0cd1823846f8600a7eb5cf7fdfd9d8748d5dbd25 100644 --- a/src/lib/dns/tests/buffer_unittest.cc +++ b/src/lib/util/tests/buffer_unittest.cc @@ -14,7 +14,7 @@ #include -#include +#include #include @@ -22,8 +22,8 @@ using namespace isc; namespace { -using isc::dns::InputBuffer; -using isc::dns::OutputBuffer; +using isc::util::InputBuffer; +using isc::util::OutputBuffer; class BufferTest : public ::testing::Test { protected: @@ -64,20 +64,20 @@ TEST_F(BufferTest, inputBufferRead) { } TEST_F(BufferTest, inputBufferException) { - EXPECT_THROW(ibuffer.setPosition(6), isc::dns::InvalidBufferPosition); + EXPECT_THROW(ibuffer.setPosition(6), isc::util::InvalidBufferPosition); ibuffer.setPosition(sizeof(testdata)); - EXPECT_THROW(ibuffer.readUint8(), isc::dns::InvalidBufferPosition); + EXPECT_THROW(ibuffer.readUint8(), isc::util::InvalidBufferPosition); ibuffer.setPosition(sizeof(testdata) - 1); - EXPECT_THROW(ibuffer.readUint16(), isc::dns::InvalidBufferPosition); + EXPECT_THROW(ibuffer.readUint16(), isc::util::InvalidBufferPosition); ibuffer.setPosition(sizeof(testdata) - 3); - EXPECT_THROW(ibuffer.readUint32(), isc::dns::InvalidBufferPosition); + EXPECT_THROW(ibuffer.readUint32(), isc::util::InvalidBufferPosition); ibuffer.setPosition(sizeof(testdata) - 4); EXPECT_THROW(ibuffer.readData(vdata, sizeof(vdata)), - isc::dns::InvalidBufferPosition); + isc::util::InvalidBufferPosition); } TEST_F(BufferTest, outputBufferExtend) { @@ -145,15 +145,15 @@ TEST_F(BufferTest, outputBufferWriteat) { EXPECT_EQ(3, *(cp + 3)); EXPECT_THROW(obuffer.writeUint8At(data16, 5), - isc::dns::InvalidBufferPosition); + isc::util::InvalidBufferPosition); EXPECT_THROW(obuffer.writeUint8At(data16, 4), - isc::dns::InvalidBufferPosition); + isc::util::InvalidBufferPosition); EXPECT_THROW(obuffer.writeUint16At(data16, 3), - isc::dns::InvalidBufferPosition); + isc::util::InvalidBufferPosition); EXPECT_THROW(obuffer.writeUint16At(data16, 4), - isc::dns::InvalidBufferPosition); + isc::util::InvalidBufferPosition); EXPECT_THROW(obuffer.writeUint16At(data16, 5), - isc::dns::InvalidBufferPosition); + isc::util::InvalidBufferPosition); } TEST_F(BufferTest, outputBufferSkip) { @@ -182,7 +182,7 @@ TEST_F(BufferTest, outputBufferReadat) { for (int i = 0; i < sizeof(testdata); i ++) { EXPECT_EQ(testdata[i], obuffer[i]); } - EXPECT_THROW(obuffer[sizeof(testdata)], isc::dns::InvalidBufferPosition); + EXPECT_THROW(obuffer[sizeof(testdata)], isc::util::InvalidBufferPosition); } TEST_F(BufferTest, outputBufferClear) { diff --git a/src/lib/log/tests/filename_unittest.cc b/src/lib/util/tests/filename_unittest.cc similarity index 99% rename from src/lib/log/tests/filename_unittest.cc rename to src/lib/util/tests/filename_unittest.cc index f3032eb04aec571255925d52051fe4b836193caf..33e645641325723887c24f4bea68c5d08856e3e1 100644 --- a/src/lib/log/tests/filename_unittest.cc +++ b/src/lib/util/tests/filename_unittest.cc @@ -16,10 +16,10 @@ #include -#include +#include using namespace isc; -using namespace isc::log; +using namespace isc::util; using namespace std; class FilenameTest : public ::testing::Test { diff --git a/src/lib/dns/tests/hex_unittest.cc b/src/lib/util/tests/hex_unittest.cc similarity index 98% rename from src/lib/dns/tests/hex_unittest.cc rename to src/lib/util/tests/hex_unittest.cc index 6f82b17f625e116734bc2e173b71a6435f4563f4..52bcceabf9caad7e06fdeccb1c5aea2cf3b523e8 100644 --- a/src/lib/dns/tests/hex_unittest.cc +++ b/src/lib/util/tests/hex_unittest.cc @@ -19,13 +19,13 @@ #include -#include +#include #include using namespace std; using namespace isc; -using namespace isc::dns; +using namespace isc::util::encode; namespace { const string hex_txt("DEADBEEFDECADE"); diff --git a/src/lib/asiolink/tests/asiolink_utilities_unittest.cc b/src/lib/util/tests/io_utilities_unittest.cc similarity index 90% rename from src/lib/asiolink/tests/asiolink_utilities_unittest.cc rename to src/lib/util/tests/io_utilities_unittest.cc index 51f565f87f177d6a9fe13971c3b1637ef267d8af..4aad560f5ce9a099a5360b1ad059acb8c1db1dcf 100644 --- a/src/lib/asiolink/tests/asiolink_utilities_unittest.cc +++ b/src/lib/util/tests/io_utilities_unittest.cc @@ -21,17 +21,16 @@ #include -#include -#include +#include +#include -using namespace asiolink; -using namespace isc::dns; +using namespace isc::util; TEST(asioutil, readUint16) { // Reference buffer uint8_t data[2]; - isc::dns::InputBuffer buffer(data, sizeof(data)); + InputBuffer buffer(data, sizeof(data)); // Avoid possible compiler warnings by only setting uint8_t variables to // uint8_t values. @@ -51,7 +50,7 @@ TEST(asioutil, readUint16) { TEST(asioutil, writeUint16) { // Reference buffer - isc::dns::OutputBuffer buffer(2); + OutputBuffer buffer(2); uint8_t test[2]; // Avoid possible compiler warnings by only setting uint16_t variables to diff --git a/src/lib/nsas/tests/lru_list_unittest.cc b/src/lib/util/tests/lru_list_unittest.cc similarity index 66% rename from src/lib/nsas/tests/lru_list_unittest.cc rename to src/lib/util/tests/lru_list_unittest.cc index e2868269136629cce1f57e9d74d8651e2071a6d6..bfb3b4dc186fe71e667b32acc1d3c252d88fd835 100644 --- a/src/lib/nsas/tests/lru_list_unittest.cc +++ b/src/lib/util/tests/lru_list_unittest.cc @@ -14,33 +14,143 @@ #include +#include #include #include #include #include +#include #include #include +#include -#include "../nsas_entry.h" -#include "../lru_list.h" - -#include "nsas_test.h" +#include using namespace std; namespace isc { -namespace nsas { +namespace util { + +/// \brief Invalid Iterator +/// +/// Thrown if an attempt was made to access the iterator - the pointer into +/// the LRU list where this element is located - when it is marked as invalid. +class InvalidLruIterator : public isc::Exception { +public: + InvalidLruIterator(const char* file, size_t line, const char* what) : + Exception(file, line, what) + {} +}; + +template +class TestEntryT : public boost::enable_shared_from_this { +public: + + /// \brief Constructor + /// + /// \param name Name that will be used for the object. This will form + /// part of the key. + /// \param class_code Class associated with the object. + TestEntryT() : valid_(false) + {} + + /// \brief Virtual Destructor + virtual ~TestEntryT() + {} + + /// \brief Sets the iterator of the object + /// + /// Sets the iterator of an object and, as a side effect, marks it as valid. + /// + /// \param iterator Iterator of this element in the list + virtual void setLruIterator(typename LruList::iterator iterator) { + iterator_ = iterator; + valid_ = true; + } + + /// \brief Return Iterator + /// + /// \return iterator Iterator of this element in the list. + /// + /// \exception InvalidLruIterator Thrown if the iterator is not valid. + virtual typename LruList::iterator getLruIterator() const { + /*if (! valid_) { + isc_throw(InvalidLruIterator, + "pointer of element into LRU list was not valid"); + }*/ + return iterator_; + } + + /// \brief Iterator Valid + /// + /// \return true if the stored iterator is valid. + virtual bool iteratorValid() const { + return valid_; + } + + /// \brief Invalidate Iterator + /// + /// Marks the iterator as invalid; it can oly be set valid again by a call + /// to setLruIterator. + virtual void invalidateIterator() { + valid_ = false; + } + +private: + typename LruList::iterator iterator_; ///< Handle into the LRU List + bool valid_; ///< true if handle is valid +}; + +class TestEntry : public TestEntryT { +public: + TestEntry(std::string name, const int & code) : + name_(name), code_(code) + {} + + /// \brief Get the Name + /// + /// \return Name given to this object + virtual std::string getName() const { + return name_; + } + + /// \brief Set the Name + /// + /// \param name New name of the object + virtual void setName(const std::string& name) { + name_ = name; + } + + /// \brief Get the Class + /// + /// \return Class code assigned to this object + virtual const int& getCode() const { + return code_; + } + + /// \brief Set the Class + /// + /// \param code New code of the object + virtual void setCode(const int& code) { + code_ = code; + } + +private: + std::string name_; ///< Name of the object + int code_; ///< Class of the object + +}; /// \brief Dropped Functor Class /// /// Functor object is called when an object is dropped from the LRU list. /// To prove that it has run, this function does nothing more than set the -/// MS bit on the 16-bit class value. +/// MS bit on the 16-bit code value. class Dropped : public LruList::Dropped { public: virtual void operator()(TestEntry* entry) const { - entry->setClass(RRClass(entry->getClass().getCode() | 0x8000)); + entry->setCode(entry->getCode() | 0x8000); } }; @@ -49,13 +159,13 @@ public: class LruListTest : public ::testing::Test { protected: LruListTest() : - entry1_(new TestEntry("alpha", RRClass::IN())), - entry2_(new TestEntry("beta", RRClass::CH())), - entry3_(new TestEntry("gamma", RRClass::HS())), - entry4_(new TestEntry("delta", RRClass::IN())), - entry5_(new TestEntry("epsilon", RRClass::HS())), - entry6_(new TestEntry("zeta", RRClass::CH())), - entry7_(new TestEntry("eta", RRClass::IN())) + entry1_(new TestEntry("alpha", 1)), + entry2_(new TestEntry("beta", 3)), + entry3_(new TestEntry("gamma", 4)), + entry4_(new TestEntry("delta", 1)), + entry5_(new TestEntry("epsilon", 4)), + entry6_(new TestEntry("zeta", 3)), + entry7_(new TestEntry("eta", 1)) {} virtual ~LruListTest() @@ -233,22 +343,22 @@ TEST_F(LruListTest, Dropped) { lru.add(entry2_); lru.add(entry3_); - EXPECT_EQ(RRClass::IN(), entry1_->getClass()); - EXPECT_EQ(RRClass::CH(), entry2_->getClass()); + EXPECT_EQ(1, entry1_->getCode()); + EXPECT_EQ(3, entry2_->getCode()); // Add another entry and check that the handler runs. - EXPECT_EQ(0, (entry1_->getClass().getCode() & 0x8000)); + EXPECT_EQ(0, (entry1_->getCode() & 0x8000)); lru.add(entry4_); - EXPECT_NE(0, (entry1_->getClass().getCode() & 0x8000)); + EXPECT_NE(0, (entry1_->getCode() & 0x8000)); - EXPECT_EQ(0, (entry2_->getClass().getCode() & 0x8000)); + EXPECT_EQ(0, (entry2_->getCode() & 0x8000)); lru.add(entry5_); - EXPECT_NE(0, (entry2_->getClass().getCode() & 0x8000)); + EXPECT_NE(0, (entry2_->getCode() & 0x8000)); // Delete an entry and check that the handler does not run. - EXPECT_EQ(0, (entry3_->getClass().getCode() & 0x8000)); + EXPECT_EQ(0, (entry3_->getCode() & 0x8000)); lru.remove(entry3_); - EXPECT_EQ(0, (entry3_->getClass().getCode() & 0x8000)); + EXPECT_EQ(0, (entry3_->getCode() & 0x8000)); } // Clear functor tests: tests whether all the elements in @@ -263,19 +373,19 @@ TEST_F(LruListTest, Clear) { lru.add(entry2_); lru.add(entry3_); - EXPECT_EQ(RRClass::IN(), entry1_->getClass()); - EXPECT_EQ(RRClass::CH(), entry2_->getClass()); - EXPECT_EQ(RRClass::HS(), entry3_->getClass()); + EXPECT_EQ(1, entry1_->getCode()); + EXPECT_EQ(3, entry2_->getCode()); + EXPECT_EQ(4, entry3_->getCode()); - EXPECT_EQ(0, (entry1_->getClass().getCode() & 0x8000)); - EXPECT_EQ(0, (entry2_->getClass().getCode() & 0x8000)); - EXPECT_EQ(0, (entry3_->getClass().getCode() & 0x8000)); + EXPECT_EQ(0, (entry1_->getCode() & 0x8000)); + EXPECT_EQ(0, (entry2_->getCode() & 0x8000)); + EXPECT_EQ(0, (entry3_->getCode() & 0x8000)); // Clear the lru list, and check the drop handler run lru.clear(); - EXPECT_NE(0, (entry1_->getClass().getCode() & 0x8000)); - EXPECT_NE(0, (entry2_->getClass().getCode() & 0x8000)); - EXPECT_NE(0, (entry3_->getClass().getCode() & 0x8000)); + EXPECT_NE(0, (entry1_->getCode() & 0x8000)); + EXPECT_NE(0, (entry2_->getCode() & 0x8000)); + EXPECT_NE(0, (entry3_->getCode() & 0x8000)); EXPECT_EQ(0, lru.size()); } diff --git a/src/lib/asiolink/tests/qid_gen_unittest.cc b/src/lib/util/tests/qid_gen_unittest.cc similarity index 87% rename from src/lib/asiolink/tests/qid_gen_unittest.cc rename to src/lib/util/tests/qid_gen_unittest.cc index 3ad8a03c512201721ff4a9cf0f0f417854b55408..60c81aeb5be22541dcfc99a831b792cbf7dc2cc2 100644 --- a/src/lib/asiolink/tests/qid_gen_unittest.cc +++ b/src/lib/util/tests/qid_gen_unittest.cc @@ -32,15 +32,16 @@ #include -#include -#include +#include + +using namespace isc::util::random; // Tests the operation of the Qid generator // Check that getInstance returns a singleton TEST(QidGenerator, singleton) { - asiolink::QidGenerator& g1 = asiolink::QidGenerator::getInstance(); - asiolink::QidGenerator& g2 = asiolink::QidGenerator::getInstance(); + QidGenerator& g1 = QidGenerator::getInstance(); + QidGenerator& g2 = QidGenerator::getInstance(); EXPECT_TRUE(&g1 == &g2); } @@ -50,8 +51,8 @@ TEST(QidGenerator, generate) { // do full statistical checking here. Let's just call it the xkcd // test (http://xkcd.com/221/), and check if three consecutive // generates are not all the same. - isc::dns::qid_t one, two, three; - asiolink::QidGenerator& gen = asiolink::QidGenerator::getInstance(); + uint16_t one, two, three; + QidGenerator& gen = QidGenerator::getInstance(); one = gen.generateQid(); two = gen.generateQid(); three = gen.generateQid(); diff --git a/src/lib/nsas/tests/random_number_generator_unittest.cc b/src/lib/util/tests/random_number_generator_unittest.cc similarity index 98% rename from src/lib/nsas/tests/random_number_generator_unittest.cc rename to src/lib/util/tests/random_number_generator_unittest.cc index 85cbcbf7572dcc9be8bba40fad1a43d59e0fd7d1..23d5b8879c7bcd4e406d16bac9bdbe7f729715ea 100644 --- a/src/lib/nsas/tests/random_number_generator_unittest.cc +++ b/src/lib/util/tests/random_number_generator_unittest.cc @@ -21,10 +21,11 @@ #include #include -#include "random_number_generator.h" +#include namespace isc { -namespace nsas { +namespace util { +namespace random { using namespace std; @@ -305,5 +306,6 @@ TEST_F(WeightedRandomIntegerGeneratorTest, ResetProbabilities) { ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); } -} // namespace nsas +} // namespace random +} // namespace util } // namespace isc diff --git a/src/lib/util/tests/run_unittests.cc b/src/lib/util/tests/run_unittests.cc new file mode 100644 index 0000000000000000000000000000000000000000..bd3c4c9af98068aa5be46f59e10cf6e62c4b7d5d --- /dev/null +++ b/src/lib/util/tests/run_unittests.cc @@ -0,0 +1,21 @@ +// Copyright (C) 2011 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. + +#include + +int +main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return (RUN_ALL_TESTS()); +} diff --git a/src/lib/dns/tests/sha1_unittest.cc b/src/lib/util/tests/sha1_unittest.cc similarity index 96% rename from src/lib/dns/tests/sha1_unittest.cc rename to src/lib/util/tests/sha1_unittest.cc index 79bc37d155c9b7de51e79a8e8603011cb464a349..6d6234945fa2516dfd4b635987ea0163ecfd4c20 100644 --- a/src/lib/dns/tests/sha1_unittest.cc +++ b/src/lib/util/tests/sha1_unittest.cc @@ -15,17 +15,15 @@ #include #include -#include +#include #include -#include - -using isc::UnitTestUtil; using namespace std; -using namespace isc::dns; -namespace { +namespace isc { +namespace util { +namespace hash { class Sha1Test : public ::testing::Test { protected: Sha1Test() {} @@ -104,5 +102,8 @@ TEST_F(Sha1Test, Test4) { EXPECT_EQ(digest[i], expected[i]); } } -} + +} // namespace hash +} // namespace util +} // namespace isc diff --git a/src/lib/log/tests/strutil_unittest.cc b/src/lib/util/tests/strutil_unittest.cc similarity index 68% rename from src/lib/log/tests/strutil_unittest.cc rename to src/lib/util/tests/strutil_unittest.cc index b3fceefe20a7eba27f3aacd55d831331d1f45576..cd3a9ca811be63488551d4b1bb0379bbbb9fea39 100644 --- a/src/lib/log/tests/strutil_unittest.cc +++ b/src/lib/util/tests/strutil_unittest.cc @@ -16,9 +16,10 @@ #include -#include +#include using namespace isc; +using namespace isc::util; using namespace std; class StringUtilTest : public ::testing::Test { @@ -34,15 +35,15 @@ protected: TEST_F(StringUtilTest, Slash) { string instring = ""; - isc::strutil::normalizeSlash(instring); + isc::util::str::normalizeSlash(instring); EXPECT_EQ("", instring); instring = "C:\\A\\B\\C.D"; - isc::strutil::normalizeSlash(instring); + isc::util::str::normalizeSlash(instring); EXPECT_EQ("C:/A/B/C.D", instring); instring = "// \\ //"; - isc::strutil::normalizeSlash(instring); + isc::util::str::normalizeSlash(instring); EXPECT_EQ("// / //", instring); } @@ -51,19 +52,19 @@ TEST_F(StringUtilTest, Slash) { TEST_F(StringUtilTest, Trim) { // Empty and full string. - EXPECT_EQ("", isc::strutil::trim("")); - EXPECT_EQ("abcxyz", isc::strutil::trim("abcxyz")); + EXPECT_EQ("", isc::util::str::trim("")); + EXPECT_EQ("abcxyz", isc::util::str::trim("abcxyz")); // Trim right-most blanks - EXPECT_EQ("ABC", isc::strutil::trim("ABC ")); - EXPECT_EQ("ABC", isc::strutil::trim("ABC\t\t \n\t")); + EXPECT_EQ("ABC", isc::util::str::trim("ABC ")); + EXPECT_EQ("ABC", isc::util::str::trim("ABC\t\t \n\t")); // Left-most blank trimming - EXPECT_EQ("XYZ", isc::strutil::trim(" XYZ")); - EXPECT_EQ("XYZ", isc::strutil::trim("\t\t \tXYZ")); + EXPECT_EQ("XYZ", isc::util::str::trim(" XYZ")); + EXPECT_EQ("XYZ", isc::util::str::trim("\t\t \tXYZ")); // Right and left, with embedded spaces - EXPECT_EQ("MN \t OP", isc::strutil::trim("\t\tMN \t OP \t")); + EXPECT_EQ("MN \t OP", isc::util::str::trim("\t\tMN \t OP \t")); } // Check tokenization. Note that ASSERT_EQ is used to check the size of the @@ -76,49 +77,49 @@ TEST_F(StringUtilTest, Tokens) { // Default delimiters // Degenerate cases - result = isc::strutil::tokens(""); // Empty string + result = isc::util::str::tokens(""); // Empty string EXPECT_EQ(0, result.size()); - result = isc::strutil::tokens(" \n "); // String is all delimiters + result = isc::util::str::tokens(" \n "); // String is all delimiters EXPECT_EQ(0, result.size()); - result = isc::strutil::tokens("abc"); // String has no delimiters + result = isc::util::str::tokens("abc"); // String has no delimiters ASSERT_EQ(1, result.size()); EXPECT_EQ(string("abc"), result[0]); // String containing leading and/or trailing delimiters, no embedded ones. - result = isc::strutil::tokens("\txyz"); // One leading delimiter + result = isc::util::str::tokens("\txyz"); // One leading delimiter ASSERT_EQ(1, result.size()); EXPECT_EQ(string("xyz"), result[0]); - result = isc::strutil::tokens("\t \nxyz"); // Multiple leading delimiters + result = isc::util::str::tokens("\t \nxyz"); // Multiple leading delimiters ASSERT_EQ(1, result.size()); EXPECT_EQ(string("xyz"), result[0]); - result = isc::strutil::tokens("xyz\n"); // One trailing delimiter + result = isc::util::str::tokens("xyz\n"); // One trailing delimiter ASSERT_EQ(1, result.size()); EXPECT_EQ(string("xyz"), result[0]); - result = isc::strutil::tokens("xyz \t"); // Multiple trailing + result = isc::util::str::tokens("xyz \t"); // Multiple trailing ASSERT_EQ(1, result.size()); EXPECT_EQ(string("xyz"), result[0]); - result = isc::strutil::tokens("\t xyz \n"); // Leading and trailing + result = isc::util::str::tokens("\t xyz \n"); // Leading and trailing ASSERT_EQ(1, result.size()); EXPECT_EQ(string("xyz"), result[0]); // Embedded delimiters - result = isc::strutil::tokens("abc\ndef"); // 2 tokens, one separator + result = isc::util::str::tokens("abc\ndef"); // 2 tokens, one separator ASSERT_EQ(2, result.size()); EXPECT_EQ(string("abc"), result[0]); EXPECT_EQ(string("def"), result[1]); - result = isc::strutil::tokens("abc\t\t\ndef"); // 2 tokens, 3 separators + result = isc::util::str::tokens("abc\t\t\ndef"); // 2 tokens, 3 separators ASSERT_EQ(2, result.size()); EXPECT_EQ(string("abc"), result[0]); EXPECT_EQ(string("def"), result[1]); - result = isc::strutil::tokens("abc\n \tdef\t\tghi"); + result = isc::util::str::tokens("abc\n \tdef\t\tghi"); ASSERT_EQ(3, result.size()); // Multiple tokens, many delims EXPECT_EQ(string("abc"), result[0]); EXPECT_EQ(string("def"), result[1]); @@ -126,14 +127,14 @@ TEST_F(StringUtilTest, Tokens) { // Embedded and non-embedded delimiters - result = isc::strutil::tokens("\t\t \nabc\n \tdef\t\tghi \n\n"); + result = isc::util::str::tokens("\t\t \nabc\n \tdef\t\tghi \n\n"); ASSERT_EQ(3, result.size()); // Multiple tokens, many delims EXPECT_EQ(string("abc"), result[0]); EXPECT_EQ(string("def"), result[1]); EXPECT_EQ(string("ghi"), result[2]); // Non-default delimiter - result = isc::strutil::tokens("alpha/beta/ /gamma//delta/epsilon/", "/"); + result = isc::util::str::tokens("alpha/beta/ /gamma//delta/epsilon/", "/"); ASSERT_EQ(6, result.size()); EXPECT_EQ(string("alpha"), result[0]); EXPECT_EQ(string("beta"), result[1]); @@ -143,7 +144,7 @@ TEST_F(StringUtilTest, Tokens) { EXPECT_EQ(string("epsilon"), result[5]); // Non-default delimiters (plural) - result = isc::strutil::tokens("+*--alpha*beta+ -gamma**delta+epsilon-+**", + result = isc::util::str::tokens("+*--alpha*beta+ -gamma**delta+epsilon-+**", "*+-"); ASSERT_EQ(6, result.size()); EXPECT_EQ(string("alpha"), result[0]); @@ -162,11 +163,11 @@ TEST_F(StringUtilTest, ChangeCase) { string lower("abcdefghijklmno123[]{=+--+]}"); string test = mixed; - isc::strutil::lowercase(test); + isc::util::str::lowercase(test); EXPECT_EQ(lower, test); test = mixed; - isc::strutil::uppercase(test); + isc::util::str::uppercase(test); EXPECT_EQ(upper, test); } @@ -180,35 +181,35 @@ TEST_F(StringUtilTest, Formatting) { args.push_back("arg3"); string format1 = "This is a string with no tokens"; - EXPECT_EQ(format1, isc::strutil::format(format1, args)); + EXPECT_EQ(format1, isc::util::str::format(format1, args)); string format2 = ""; // Empty string - EXPECT_EQ(format2, isc::strutil::format(format2, args)); + EXPECT_EQ(format2, isc::util::str::format(format2, args)); string format3 = " "; // Empty string - EXPECT_EQ(format3, isc::strutil::format(format3, args)); + EXPECT_EQ(format3, isc::util::str::format(format3, args)); string format4 = "String with %d non-string tokens %lf"; - EXPECT_EQ(format4, isc::strutil::format(format4, args)); + EXPECT_EQ(format4, isc::util::str::format(format4, args)); string format5 = "String with %s correct %s number of tokens %s"; string result5 = "String with arg1 correct arg2 number of tokens arg3"; - EXPECT_EQ(result5, isc::strutil::format(format5, args)); + EXPECT_EQ(result5, isc::util::str::format(format5, args)); string format6 = "String with %s too %s few tokens"; string result6 = "String with arg1 too arg2 few tokens"; - EXPECT_EQ(result6, isc::strutil::format(format6, args)); + EXPECT_EQ(result6, isc::util::str::format(format6, args)); string format7 = "String with %s too %s many %s tokens %s !"; string result7 = "String with arg1 too arg2 many arg3 tokens %s !"; - EXPECT_EQ(result7, isc::strutil::format(format7, args)); + EXPECT_EQ(result7, isc::util::str::format(format7, args)); string format8 = "String with embedded%s%s%stokens"; string result8 = "String with embeddedarg1arg2arg3tokens"; - EXPECT_EQ(result8, isc::strutil::format(format8, args)); + EXPECT_EQ(result8, isc::util::str::format(format8, args)); // Handle an empty vector args.clear(); string format9 = "%s %s"; - EXPECT_EQ(format9, isc::strutil::format(format9, args)); + EXPECT_EQ(format9, isc::util::str::format(format9, args)); } diff --git a/src/lib/dns/tests/dnssectime_unittest.cc b/src/lib/util/tests/time_utilities_unittest.cc similarity index 92% rename from src/lib/dns/tests/dnssectime_unittest.cc rename to src/lib/util/tests/time_utilities_unittest.cc index b2708cc6e834f3c7e3e93be9b7880976eba4f87a..9261ea0bef2142fee7d3ba848535bc30b165bdc2 100644 --- a/src/lib/dns/tests/dnssectime_unittest.cc +++ b/src/lib/util/tests/time_utilities_unittest.cc @@ -16,30 +16,28 @@ #include -#include +#include #include using namespace std; -using namespace isc::dns; +using namespace isc::util; -// See dnssectime.cc +// See time_utilities.cc namespace isc { -namespace dns { -namespace dnssectime { +namespace util { namespace detail { extern int64_t (*gettimeFunction)(); } } } -} namespace { class DNSSECTimeTest : public ::testing::Test { protected: ~DNSSECTimeTest() { - dnssectime::detail::gettimeFunction = NULL; + detail::gettimeFunction = NULL; } }; @@ -115,7 +113,7 @@ TEST_F(DNSSECTimeTest, toText) { // Set the current time to: Feb 18 09:04:14 UTC 2012 (an arbitrary choice // in the range of the first half of uint32 since epoch). - dnssectime::detail::gettimeFunction = testGetTime<1329555854LL>; + detail::gettimeFunction = testGetTime<1329555854LL>; // Test the "year 2038" problem. // Check the result of toText() for "INT_MIN" in int32_t. It's in the @@ -135,7 +133,7 @@ TEST_F(DNSSECTimeTest, toText) { // After the singular point of year 2038, the first half of uint32 can // point to a future time. // Set the current time to: Apr 1 00:00:00 UTC 2038: - dnssectime::detail::gettimeFunction = testGetTime<2153692800LL>; + detail::gettimeFunction = testGetTime<2153692800LL>; // then time "10" is Feb 7 06:28:26 UTC 2106 EXPECT_EQ("21060207062826", timeToText32(10)); // in 64-bit, it's 2^32 + 10 @@ -143,20 +141,20 @@ TEST_F(DNSSECTimeTest, toText) { // After year 2106, the upper half of uint32 can point to past time // (as it should). - dnssectime::detail::gettimeFunction = testGetTime<0x10000000aLL>; + detail::gettimeFunction = testGetTime<0x10000000aLL>; EXPECT_EQ("21060207062815", timeToText32(0xffffffffL)); // Try very large time value. Actually it's the possible farthest time // that can be represented in the form of YYYYMMDDHHmmSS. EXPECT_EQ("99991231235959", timeToText64(YEAR10K_EVE)); - dnssectime::detail::gettimeFunction = testGetTime; + detail::gettimeFunction = testGetTime; EXPECT_EQ("99991231235959", timeToText32(4294197631LU)); } TEST_F(DNSSECTimeTest, overflow) { // Jan 1, Year 10,000. EXPECT_THROW(timeToText64(253402300800LL), InvalidTime); - dnssectime::detail::gettimeFunction = testGetTime; + detail::gettimeFunction = testGetTime; EXPECT_THROW(timeToText32(4294197632LU), InvalidTime); } diff --git a/src/lib/dns/dnssectime.cc b/src/lib/util/time_utilities.cc similarity index 98% rename from src/lib/dns/dnssectime.cc rename to src/lib/util/time_utilities.cc index c889178424f9ed3084c35393954c17784ae98649..229800db02ab585d860ef3dec9c0009e2c7cdd5a 100644 --- a/src/lib/dns/dnssectime.cc +++ b/src/lib/util/time_utilities.cc @@ -26,7 +26,7 @@ #include -#include +#include using namespace std; @@ -50,7 +50,7 @@ monthSecs(const int month, const int year) { } namespace isc { -namespace dns { +namespace util { string timeToText64(uint64_t value) { @@ -108,16 +108,14 @@ timeToText64(uint64_t value) { // Otherwise we use the standard gettimeofday(2). This hook is specifically // intended for testing purposes, so, even if it's visible outside of this // library, it's not even declared in a header file. -namespace dnssectime { namespace detail { int64_t (*gettimeFunction)() = NULL; } -} namespace { int64_t gettimeofdayWrapper() { - using namespace dnssectime::detail; + using namespace detail; if (gettimeFunction != NULL) { return (gettimeFunction()); } @@ -207,5 +205,6 @@ timeFromText32(const string& time_txt) { // because we only need to drop higher 32 bits. return (timeFromText64(time_txt)); } + } } diff --git a/src/lib/dns/dnssectime.h b/src/lib/util/time_utilities.h similarity index 98% rename from src/lib/dns/dnssectime.h rename to src/lib/util/time_utilities.h index baf866f3e0110acf5c20e9cf96bf5973a5fbb6c1..0558f165805568b6cf8645da75213fd08a1fa601 100644 --- a/src/lib/dns/dnssectime.h +++ b/src/lib/util/time_utilities.h @@ -12,8 +12,8 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#ifndef __DNSSECTIME_H -#define __DNSSECTIME_H 1 +#ifndef __TIME_UTILITIES_H +#define __TIME_UTILITIES_H 1 #include #include @@ -27,7 +27,7 @@ // namespace isc { -namespace dns { +namespace util { /// /// \brief A standard DNS (or ISC) module exception that is thrown if @@ -140,6 +140,6 @@ timeToText32(const uint32_t value); #endif // __DNSSECTIME_H -// Local Variables: +// Local Variables: // mode: c++ -// End: +// End: diff --git a/src/lib/util/unittests/Makefile.am b/src/lib/util/unittests/Makefile.am index 0ea86539ffa1ac1326602b2ad7e10e1955d0421d..b7026478ff73cb5b9e9aa44749fb0be5bf6bd4a9 100644 --- a/src/lib/util/unittests/Makefile.am +++ b/src/lib/util/unittests/Makefile.am @@ -3,7 +3,5 @@ AM_CXXFLAGS = $(B10_CXXFLAGS) lib_LTLIBRARIES = libutil_unittests.la libutil_unittests_la_SOURCES = fork.h fork.cc -libutil_unittests_la_LIBADD = \ - $(top_builddir)/src/lib/util/io/libutil_io.la CLEANFILES = *.gcno *.gcda diff --git a/tests/Makefile.am b/tests/Makefile.am index d4008c0dd037273e71e4c75eb04603c8f598072b..570c0e22cc2ee06222c63ec8cd3cbd95709b5506 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1 +1 @@ -SUBDIRS = system +SUBDIRS = system tools diff --git a/tests/tools/Makefile.am b/tests/tools/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..2f07494dce3841b2fc4e1133003efb7e6629d9f7 --- /dev/null +++ b/tests/tools/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = badpacket diff --git a/tests/tools/badpacket/Makefile.am b/tests/tools/badpacket/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..7df7077984292cb05a39bdbc645fe69a89d08b3a --- /dev/null +++ b/tests/tools/badpacket/Makefile.am @@ -0,0 +1,33 @@ +SUBDIRS = . tests + +AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log +AM_CPPFLAGS += $(BOOST_INCLUDES) + +AM_CXXFLAGS = $(B10_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +CLEANFILES = *.gcno *.gcda + +noinst_PROGRAMS = badpacket +badpacket_SOURCES = badpacket.cc +badpacket_SOURCES += command_options.cc command_options.h +badpacket_SOURCES += header_flags.h +badpacket_SOURCES += option_info.cc option_info.h +badpacket_SOURCES += scan.cc scan.h +badpacket_SOURCES += version.h + +badpacket_CXXFLAGS = $(AM_CXXFLAGS) +if USE_CLANGPP +badpacket_CXXFLAGS += -Wno-error +endif + +badpacket_LDADD = $(top_builddir)/src/lib/asiodns/libasiodns.la +badpacket_LDADD += $(top_builddir)/src/lib/dns/libdns++.la +badpacket_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la +badpacket_LDADD += $(top_builddir)/src/lib/log/liblog.la +badpacket_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la + diff --git a/tests/tools/badpacket/README b/tests/tools/badpacket/README new file mode 100644 index 0000000000000000000000000000000000000000..3f5e801720e13c6731b59aad114866ce1e0f4d0d --- /dev/null +++ b/tests/tools/badpacket/README @@ -0,0 +1,53 @@ +"badpacket" is a tool intended to test that a nameserver can cope with +incorrectly-formatted DNS messages. + +This particular incarnation of the tool allows various fields in the DNS +message to be set to any value (including to values that invalidate the query). +As well as setting individual values, it is possible to specify ranges; when +this is done, the tool will send a set of packets so that each combination +of values is checked. + +To illustrate this, consider the following command: + +badpacket --address 192.0.2.21 --port 5301 --aa 0-1 --cd 1 + --rc 0-2 ftp.example.com + +(The command has been split across two lines for clarity.) + +The address and port flags are self-evident. The other flags specify +settings for the AA bit (0 and 1), CD bit (always 1) and the RCODE field +(0, 1, 2). (The remaining fields in the flags word are not specified, so +will always be zero.) There are six combinations of these values, so six +packets will sent to the remote server with the following settings: + +AA RCODE CD Rest +0 0 1 0 +0 1 1 0 +0 2 1 0 +1 0 1 0 +1 1 1 0 +1 2 1 0 + +Each packet will cause a line to be output to stdout, which will have the +following form: + +SUCCESS: (QR:0 OP:0 AA:0 TC:0 RD:0 RA:0 ... + (qr:1 op:0 aa:0 tc:0 rd:0 ra:1 ... + +(Again the text has been split across two lines for clarity. Also, the full +list of fields has been truncated.) + +Each lines contains a status (SUCCESS indicates that a response was received, +regardless of the contents of the response), the state of the fields in the +flags word of the packet sent (in upper-case letters) and the state of the +fields in the flags word of the response (in lower-case letters). + +TODO: At the moment the tool is limited to: +* Setting values in the flags field. +* Setting section counts to arbitrary values. +* Extending or truncating the DNS message size. + +Additional options needed are: +* Add data to sections that should be empty. +* Deliberately mangle the names placed in the message sections (e.g. by altering + the label count fields). diff --git a/tests/tools/badpacket/badpacket.cc b/tests/tools/badpacket/badpacket.cc new file mode 100644 index 0000000000000000000000000000000000000000..86bbc47a2e9f5d0bcce537f7231fde8944de7294 --- /dev/null +++ b/tests/tools/badpacket/badpacket.cc @@ -0,0 +1,62 @@ +// Copyright (C) 2011 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. + +#include +#include + +#include + +#include +#include "command_options.h" +#include "scan.h" + +/// \brief Perform Bad Packet Scan +/// +/// Scans the server by sending a sequence of (potentially) bad packets and +/// printing the packet settings and the response received. The principle +/// raison d'etre for this is to check if a bad packet will cause a crash. +/// +/// This particular version of the code allows a set of ranges to be set for: +/// - The flags fields in the message. +/// - The section count fields, regardless of what is in the section. +/// - The message size: the message can be truncated or extended. +/// +/// The program then sends a set of packets corresponding to all combinations +/// of values in the ranges selected. + +// TODO: Extend to cover: +// - Mangling the QNAME +// - Adding names to the message sections +// - Adding EDNS0 RR and magling the fields there + +using namespace isc::badpacket; + +/// \brief Main Program +int main(int argc, char* argv[]) { + + try { + // Parse command + CommandOptions options; + options.parse(argc, argv); + + // Send the sequence of messages + Scan scanner; + scanner.scan(options); + } catch (isc::Exception& e) { + std::cout << "ERROR: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/tests/tools/badpacket/command_options.cc b/tests/tools/badpacket/command_options.cc new file mode 100644 index 0000000000000000000000000000000000000000..eea5ff0dae9ea80b1d7e245cf1aa94f92bf6b627 --- /dev/null +++ b/tests/tools/badpacket/command_options.cc @@ -0,0 +1,333 @@ +// Copyright (C) 2011 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. + +#include +#include +#include +#include + +#include +#include + +#include "exceptions/exceptions.h" +#include "util/strutil.h" + +#include "command_options.h" +#include "option_info.h" +#include "version.h" + +using namespace std; +using namespace isc; + +namespace isc { +namespace badpacket { + +// Reset stored values to the defaults. +void +CommandOptions::reset() { + address_ = "127.0.0.1"; + port_ = 53; + timeout_ = 500; + qname_ = "www.example.com"; + + for (int i = 0; i < OptionInfo::SIZE; ++i) { + options_[i].minimum = OptionInfo::defval(i); + options_[i].maximum = OptionInfo::defval(i); + options_[i].present = false; + } +} + +/// Parses the command-line options and records the results. +void +CommandOptions::parse(int argc, char* const argv[]) { + + // Set up options for processing. The declaration of the string constants + // as mutable arrays and putting the string variable into the "longopts" + // structure (as opposed to just putting a string literal there) is + // occasioned by a version of solaris which declares the first field as + // "char*" (instead of the correct "const char*"). + + // General options. + char HELP[] = {"help"}; + char VERSION[] = {"version"}; + char ADDRESS[] = {"address"}; + char PORT[] = {"port"}; + char TIMEOUT[] = {"timeout"}; + + // Settings for options in the flags field. + char QR[] = {"qr"}; + char OP[] = {"op"}; + char AA[] = {"aa"}; + char TC[] = {"tc"}; + char RD[] = {"rd"}; + char RA[] = {"ra"}; + char Z[] = {"z"}; + char AD[] = {"ad"}; + char CD[] = {"cd"}; + char RC[] = {"rc"}; + + // Settings for the count fields + char QC[] = {"qc"}; + char AC[] = {"ac"}; + char UC[] = {"uc"}; + char DC[] = {"dc"}; + + // Message size + char MS[] = {"ms"}; + + const struct option longopts[] = { + {HELP, 0, NULL, 'h'}, // Print usage message and exit + {VERSION, 0, NULL, 'v'}, // Print program version and exit + {ADDRESS, 1, NULL, 'a'}, // Specify target server address + {PORT, 1, NULL, 'p'}, // Specify target port + {TIMEOUT, 1, NULL, 't'}, // Time to wait before timing out (ms) + {QR, 1, NULL, 'Q'}, // Query/response flag + {OP, 1, NULL, 'O'}, // Opcode + {AA, 1, NULL, 'A'}, // Authoritative answer + {TC, 1, NULL, 'T'}, // Truncated + {RD, 1, NULL, 'D'}, // recursion Desired + {RA, 1, NULL, 'R'}, // Recursion available + {Z, 1, NULL, 'Z'}, // must be Zero (reserved bit) + {AD, 1, NULL, 'U'}, // aUthenticated data + {CD, 1, NULL, 'C'}, // Checking disabled + {RC, 1, NULL, 'E'}, // rEsult code + {QC, 1, NULL, 'Y'}, // querY section count + {AC, 1, NULL, 'W'}, // ansWer section count + {UC, 1, NULL, 'H'}, // autHority section count + {DC, 1, NULL, 'I'}, // addItional section count + {MS, 1, NULL, 'M'}, // Message size + {NULL, 0, NULL, 0 } + }; + const char* shortopts = "hva:p:t:Q:O:A:T:D:R:Z:U:C:E:Y:W:H:I:M:"; + + + // Set record of options to defaults before parsing + reset(); + + // Process command line + int c; // Option being processed + optind = 0; // Reset parsing + while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + switch (c) { + case 'h': // --help + usage(); + exit(0); + + case 'v': // --version + version(); + exit(0); + + case 'a': // --address + address_ = optarg; + break; + + case 'p': // --port + port_ = boost::lexical_cast(string(optarg)); + break; + + case 't': // --timeout + timeout_ = boost::lexical_cast(string(optarg)); + break; + + case 'Q': // --qr (query/response) + case 'O': // --op (operation code) + case 'A': // --aa (authoritative answer) + case 'T': // --tc (truncated) + case 'D': // --rd (recursion desired) + case 'R': // --ra (recursion available) + case 'Z': // --z (zero: reserved bit) + case 'U': // --ad (authenticated data) + case 'C': // --cd (checking disabled) + case 'E': // --rc (result code) + case 'Y': // --qc (query count) + case 'W': // --ac (answer count) + case 'H': // --uc (authority count) + case 'I': // --dc (additional count) + case 'M': // --ms (message size) + processOptionValue(c, optarg); + break; + + default: + isc_throw(isc::InvalidParameter, + "unknown option given on the command line"); + } + } + + // Pick up a parameter if there is one (and report excess). + if (optind < argc) { + qname_ = argv[optind++]; + } + + if (optind < argc) { + isc_throw(isc::InvalidParameter, + "only a single (optional) parameter may be specified on the command line"); + } +} + +// Print usage information. +void +CommandOptions::usage() { + cout << "Usage: badpacket [options] query\n" + "\n" + "Sends a sequence of DNS messages to the specified nameserver and prints the\n" + " results. The packets are valid query packets but certain aspects of the\n" + " packets (such as the flags fields, section count fields and message size) can\n" + "be set to arbitrary values using the command-line switches.\n" + "\n" + "In the following list of command-line switches, '' indicates a range of\n" + "values specified as either or - (e.g. both '42'\n" + "and '0-1' would be valid values for range). The program sends a sequence of\n" + "messages that contain all combinations of the flag values. For example,\n" + "specifying:\n" + "\n" + "--tc 0-1 --op 1-4 --aa 1 --rd 0-1\n" + "\n" + "... would send a total of 16 packets which would have all combinations of the\n" + "the tc bit set to 0 and 1, the rd bit set to 0 and 1, and the opcode set to all\n" + "values between 1 and 4. All other flags fields would be zero except for the aa\n" + "bit which would always be 1.\n" + "\n" + "The long form of the option is given. It can also be specified as a single-\n" + "character short-form, which is listed in sqare brackets in the description.\n" + "\n" + "General options are:\n" + "\n" + "--help [-h] Prints this message and exits.\n" + "--version [-v] Prints the program version number.\n" + "--address
[-a] Address of nameserver, which defaults to 127.0.0.1\n" + "--port [-p] Port to which to send query. Defaults to 53.\n" + "--timeout [-t] Timeout value for the query. Specified in ms, it\n" + " defaults to 500ms.\n" + "\n" + "The following options set fields in the outgoing DNS message flags word:\n" + "\n" + "--qr [-Q] Set query/response bit. Valid is 0-1.\n" + "--op [-O] Set opcode. Valid is 0-15.\n" + "--aa [-A] Set authoritative answer bit. Valid is 0-1.\n" + "--tc [-T] Set truncated bit. Valid is 0-1.\n" + "--rd [-D] Set recursion desired bit. Valid is 0-1.\n" + "--ra [-D] Set recursion available bit. Valid is 0-1.\n" + "--z [-Z] Set zero (reserved) bit. Valid is 0-1.\n" + "--ad [-U] Set authenticated data bit. Valid is 0-1.\n" + "--cd [-C] Set checking disabled bit. Valid is 0-1.\n" + "--rc [-E] Set rcode value. Valid is 0-15\n" + "\n" + "The following options set the various section counts (independent of what is\n" + "actually in the section):\n" + "\n" + "--qc [-Y] Set the query count. Valid range is 0-65535.\n" + "--ac [-W] Set the answer count. Valid range is 0-65535.\n" + "--uc [-H] Set the authority count. Valid range is 0-65535.\n" + "--dc [-I] Set the additional count. Valid range is 0-65535.\n" + "\n" + "Other options are:\n" + "\n" + "--ms [-M] Set the size of the message. If the specified size\n" + " smaller than the natural message size, it is truncated.\n" + " If longer, the packet is extended with random values.\n" + " Valid range is 2 to 65536\n" + "\n" + "query Name to query for. The query is for an 'IN' A record. If\n" + " not given, the name 'www.example.com' is used.\n" + "\n" + "The output is a single (very long) line containing the settings of the various\n" + "fields. The settings for the outgoing packet are reported in uppercase letters\n" + "and that of the returned packet in lowercase.\n" + ; +} + +// Print version information, +void +CommandOptions::version() { + cout << BADPACKET_VERSION << "\n"; +} + +// Process single flag that can be stored in the options_ member. +void +CommandOptions::processOptionValue(int c, const char* value) { + + // Get values for this option. + int index = OptionInfo::getIndex(c); + const char* name = OptionInfo::name(index); + uint32_t minval = OptionInfo::minval(index); + uint32_t maxval = OptionInfo::maxval(index); + + // Split the string up into one or two tokens. + vector tokens = isc::util::str::tokens(string(value), "-"); + if ((tokens.size() < 1) || (tokens.size() > 2)) { + isc_throw(isc::BadValue, "value given for " << name << " is '" << value << + "': it must be in the form 'int' or 'int1-int2'"); + } + + // Convert to uint32. + try { + options_[index].minimum = boost::lexical_cast(tokens[0]); + if (tokens.size() == 2) { + options_[index].maximum = boost::lexical_cast(tokens[1]); + } else { + options_[index].maximum = options_[index].minimum; + } + } catch (boost::bad_lexical_cast) { + isc_throw(isc::BadValue, "value given for " << name << " is '" << value << + "': it must be in the form 'int' or 'int1-int2'"); + } + + // Set the limits in the correct order. + if (options_[index].minimum > options_[index].maximum) { + swap(options_[index].minimum, options_[index].maximum); + } + + // Check that tokens lie inside the allowed ranges. + if ((tokens.size() == 1) && + ((options_[index].minimum < OptionInfo::minval(index)) || (options_[index].maximum > maxval))) { + isc_throw(isc::BadValue, "the value of " << options_[index].minimum << + " given for " << name << " is outside the range of " << + minval << " to " << maxval); + } else if (options_[index].minimum < minval) { + isc_throw(isc::BadValue, "the lower limit of " << options_[index].minimum << + " given for " << name << " is below the minimum permitted" + " value of " << minval); + } else if (options_[index].maximum > maxval) { + isc_throw(isc::BadValue, "the upper limit of " << options_[index].maximum << + " given for " << name << " is above the maximum permitted" + " value of " << maxval); + } + + // And finally note that the option was specified on the command line + options_[index].present = true; +} + +// Return information about the option - minimum and maximum values and whether +// it was actually specified. (Note that if it wasn't, the maximum and minimum +// values will have been set to the default recorded in the OptionInfo class.) +uint32_t +CommandOptions::minimum(int index) const { + OptionInfo::checkIndex(index); + return (options_[index].minimum); +} + +uint32_t +CommandOptions::maximum(int index) const { + OptionInfo::checkIndex(index); + return (options_[index].maximum); +} + +bool +CommandOptions::present(int index) const { + OptionInfo::checkIndex(index); + return (options_[index].present); +} + +} // namespace badpacket +} // namespace isc diff --git a/tests/tools/badpacket/command_options.h b/tests/tools/badpacket/command_options.h new file mode 100644 index 0000000000000000000000000000000000000000..fc819e931a93bf3aa7bfeaf4096d172cb3fba1af --- /dev/null +++ b/tests/tools/badpacket/command_options.h @@ -0,0 +1,162 @@ +// Copyright (C) 2011 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. + +#ifndef __COMMAND_OPTIONS_H +#define __COMMAND_OPTIONS_H + +#include +#include +#include + +#include "option_info.h" + +namespace isc { +namespace badpacket { + +/// \brief Command Options +/// +/// This class is responsible for parsing the command-line and storing the +/// specified options. +/// +/// Some of the options perform general control (like setting the address of the +/// nameserver under test, while the rest set values in the DNS message being +/// sent. Each of the latter options can be specified as either: +/// +/// - \c --option value +/// - \c --option value1-value2 +/// +/// Either way, two values are extracted the low value and the high value (in +/// the former case, both are the same). The values are stored and can be +/// returned on request. +/// +/// For simplicity, the class takes care of the --help and --version flags, +/// each of which will cause a message to be printed to stdout and the program +/// to terminate. + +class CommandOptions { +public: + + /// \brief Default Constructor + /// + /// Set values to defaults. + CommandOptions() { + reset(); + } + + /// \brief Return minimum value for option + /// + /// Applicable only to an option affecting a field in the message, this + /// method returns the minimum value that was given on the command line. + /// (If only a single value was given, it will be that value returned.) + /// If the option was not specified on the command line, the default value + /// set in the OptionsInfo class will be returned. + /// + /// \param index Index of the command-line option. + /// + /// \return uint32_t holding the minimum value given (or the default if + /// the option was not specified on the command line). + uint32_t minimum(int index) const; + + /// \brief Return maximum value for option + /// + /// Applicable only to an option affecting a field in the message, this + /// method returns the maximum value that was given on the command line. + /// (If only a single value was given, it will be that value returned.) + /// If the option was not specified on the command line, the default value + /// set in the OptionsInfo class will be returned. + /// + /// \param index Index of the command-line option. + /// + /// \return uint32_t holding the maximum value given (or the default if + /// the option was not specified on the command line). + uint32_t maximum(int index) const; + + /// \brief Reports if option was given on command line + /// + /// \param index Index of the command-line option. + /// + /// \return true if the option was present, false if not. + bool present(int index) const; + + + /// \brief Return target address + std::string getAddress() const { + return address_; + } + + /// \brief Return target port + uint16_t getPort() const { + return port_; + } + + /// \brief Return timeout + int getTimeout() const { + return timeout_; + } + + /// \brief Return qname + std::string getQname() const { + return qname_; + } + + /// \brief Reset to defaults + /// + /// Resets the CommandOptions object to default values. + void reset(); + + /// \brief Parse command line + /// + /// Parses the command line and stores the selected options. The parsing + /// also handles the --help and --version commands: both of these will cause + /// some text to be printed to stdout, after which exit() is called to + /// terminate the program. + /// + /// \param argc Argument count passed to main(). + /// \param argv Argument value array passed to main(). + void parse(int argc, char* const argv[]); + + /// \brief Print usage information and exit program + void usage(); + + /// \brief Print version information and exit program + void version(); + +private: + /// \brief Process Option Value + /// + /// Processes a specific command-line option, interpreting the value and + /// placing it in the appropriate location. On error a BadValue exception + /// is thrown. + /// + /// \param c Short form option character from the command line + /// \param value Value of the option read from the command line + void processOptionValue(int c, const char* value); + + // Member variables + + struct { + uint32_t minimum; ///< Minimum value specified + uint32_t maximum; ///< Maximum value specified + bool present; ///< true if specified on command line + } options_[OptionInfo::SIZE]; ///< Information about command options + std::string address_; ///< Address to where query is sent + uint16_t port_; ///< Target port + int timeout_; ///< Timeout for query + std::string qname_; ///< Query to make +}; + +} // namespace badpacket +} // namespace isc + +#endif // __COMMAND_OPTIONS_H diff --git a/tests/tools/badpacket/header_flags.h b/tests/tools/badpacket/header_flags.h new file mode 100644 index 0000000000000000000000000000000000000000..5d74e75b17d130da2d9b5ec8161c61ab8a33dad6 --- /dev/null +++ b/tests/tools/badpacket/header_flags.h @@ -0,0 +1,102 @@ +// Copyright (C) 2011 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. + +#ifndef __HEADER_FLAGS_H +#define __HEADER_FLAGS_H + +#include +#include "option_info.h" + +namespace isc { +namespace badpacket { + +/// \brief Header Flags +/// +/// Simple class providing easy conversion between the header flags in a DNS +/// message and a 16-bit value. + +class HeaderFlags { +public: + + /// \brief Constructor + HeaderFlags() { + reset(); + } + + /// \brief Reset values to zero + /// + /// Clears all flags. + void reset() { + setValue(0); + } + + /// \brief Get header flags as 16-bit value + uint16_t getValue() const { + return (flags_); + } + + /// \brief Set header flags as 16-bit value + /// + /// \param value 16-bit value to put into object as representing the + /// header flags. + void setValue(uint16_t value) { + flags_ = value; + } + + /// \brief Get field + /// + /// Return the value of a bit field in the flags word. + /// + /// \param int Index of the bit field in the OptionInfo data structure + /// + /// \return Value of the field. + uint16_t get(int index) const { + OptionInfo::checkIndex(index); + return ((flags_ & OptionInfo::mask(index)) >> OptionInfo::offset(index)); + } + + /// \brief Set field + /// + /// Sets the value of a bit field. + /// + /// \param int Index of the bit field in the OptionInfo data structure + /// \param value Value to set. If the value is more than the field can + /// hold, a BadValue exception is thrown. + void set(int index, uint16_t value) { + + // Declare an OptionInfo object for brevity and check the index is + // valid. + OptionInfo o; + o.checkIndex(index); + + // Ensure the value is within limits and throw an exception if not. (This + // should not really be needed, as the command line parsing should have + // checked the limits. But be safe.) + if ((value < o.minval(index)) || (value > o.maxval(index))) { + isc_throw(isc::BadValue, "value of index " << index << " is out of range"); + } + + // Clear the field then set it with the value. + flags_ &= ~o.mask(index); + flags_ |= (value << o.offset(index)); + } + +private: + uint16_t flags_; ///< Variable holding field values +}; + +} // namespace badpacket +} // namespace isc + +#endif // __HEADER_FLAGS_H diff --git a/tests/tools/badpacket/option_info.cc b/tests/tools/badpacket/option_info.cc new file mode 100644 index 0000000000000000000000000000000000000000..e1c1f78992fc70d24d369a870b46b111b5aac294 --- /dev/null +++ b/tests/tools/badpacket/option_info.cc @@ -0,0 +1,114 @@ +// Copyright (C) 2011 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. + +#include "option_info.h" + +namespace { + +// Define the various options for the command switches. This includes both the +// long form and short form of the switch. Unfortunately this means that the +// information is duplicated here and where the long options are specified for +// getopt_long, but this inconvenience is outweighed by the simplified command +// processing. +// +// Fields are: +// * Short option name +// * Long option name +// * Offset of 16-bit word holding datum in DNS message (if applicable) +// * Bit mask for the data (if applicable) +// * Offset of the bit field in the word (if applicable) +// * Default value (this can be ignored if applicable) +// * Minimum value specified on command line +// * Maximum value specified on command line + +isc::badpacket::OptionInfo::Parameter option_information[] = { + {'Q', "qr", 2, 0x8000, 15, 0, 0, 1}, + {'O', "op", 2, 0x7800, 11, 0, 0, 15}, + {'A', "aa", 2, 0x0400, 10, 0, 0, 1}, + {'T', "tc", 2, 0x0200, 9, 0, 0, 1}, + {'D', "rd", 2, 0x0100, 8, 0, 0, 1}, + {'R', "ra", 2, 0x0080, 7, 0, 0, 1}, + {'Z', "z", 2, 0x0040, 6, 0, 0, 1}, + {'U', "ad", 2, 0x0020, 5, 0, 0, 1}, + {'C', "cd", 2, 0x0010, 4, 0, 0, 1}, + {'E', "rc", 2, 0x000F, 0, 0, 0, 15}, + {'Y', "qc", 4, 0, 0, 1, 0, 0xFFFF}, + {'W', "ac", 6, 0, 0, 0, 0, 0xFFFF}, + {'H', "uc", 8, 0, 0, 0, 0, 0xFFFF}, + {'I', "dc", 10, 0, 0, 0, 0, 0xFFFF}, + {'M', "ms", 0, 0, 0, 0, 1, 65536} +}; + +} // Anonymous namespace + +namespace isc { +namespace badpacket { + +// Locate the index of the information in the array from the short switch. +int +OptionInfo::getIndex(int c) { + for (int i = 0; i < SIZE; ++i) { + if (option_information[i].short_form == c) { + return (i); + } + } + isc_throw(isc::BadValue, "unknown option: " << c); +} + +// Methods to return values from the array + +const char* +OptionInfo::name(int i) { + checkIndex(i); + return (option_information[i].long_form); +} + +uint16_t +OptionInfo::mask(int i) { + checkIndex(i); + return (option_information[i].mask); +} + +int +OptionInfo::word(int i) { + checkIndex(i); + return (option_information[i].word); +} + +int +OptionInfo::offset(int i) { + checkIndex(i); + return (option_information[i].offset); +} + +uint32_t +OptionInfo::minval(int i) { + checkIndex(i); + return (option_information[i].minval); +} + +uint32_t +OptionInfo::defval(int i) { + checkIndex(i); + return (option_information[i].defval); +} + +uint32_t +OptionInfo::maxval(int i) { + checkIndex(i); + return (option_information[i].maxval); +} + +} // namespace badpacket +} // namespace isc diff --git a/tests/tools/badpacket/option_info.h b/tests/tools/badpacket/option_info.h new file mode 100644 index 0000000000000000000000000000000000000000..a340c1d3f84b07b1402f745cae90be7eb26fef21 --- /dev/null +++ b/tests/tools/badpacket/option_info.h @@ -0,0 +1,174 @@ +// Copyright (C) 2011 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. + +#ifndef __OPTION_INFO_H +#define __OPTION_INFO_H + +#include +#include "exceptions/exceptions.h" + +namespace isc { +namespace badpacket { + +/// \brief Option Information +/// +/// Holds details about the options that can be specified on the command line +/// that require values and which control data put in the DNS message sent to +/// the remote system. +/// +/// Some of the fields are no applicable to all options. For example, some of +/// the options correspond to fields in the flags word of the DNS message +/// header, so the information includes details about the position of the fields +/// and an appropriate bit mask. +/// +/// Note that the class does not hold values specified on the command line - it +/// only holds information about the available options. + +class OptionInfo { +public: + + /// \brief Array Indexes + /// + /// The data for the flags options are held in an array. Although declared + /// as an enum, only the numeric values are used as they are the indexes + /// into the array. + enum Index { + FLAGS_START = 0, // Start of flags field codes + QR = 0, // Query/response + OP = 1, // Opcode + AA = 2, // Authoritative answer + TC = 3, // Truncated + RD = 4, // Recursion desired + RA = 5, // Recursion available + Z = 6, // Zero (reserved) + AD = 7, // Authenticated data + CD = 8, // Checking disabled + RC = 9, // Response code + FLAGS_END = 9, // End of flags field codes + COUNT_START = 10, // Start of count fields + QC = 10, // Query count + AC = 11, // Answer count + UC = 12, // Authority count + DC = 13, // Additional count + COUNT_END = 13, // End of count fields + OTHER_START = 14, // Start of other fields + MS = 14, // Message size + OTHER_END = 14, // End of other fields + SIZE = 15 // Number of index values + }; + + /// \brief Option parameters + /// + /// Defines a structure that holds information associated with each of the + /// flags field command options. Not all members of the structure are + /// relevant to all options. + struct Parameter { + const char short_form; // Short form of the command switch + const char* long_form; // Long form of the command switch + int word; // Byte offset of word in message header + uint16_t mask; // Bit mask of field in the flags word + int offset; // Offset of field in flags word + uint32_t defval; // Default value + uint32_t minval; // Minimum valid value for this field + uint32_t maxval; // Maximum valid value for this field + }; + + /// \brief Return index for command option + /// + /// Given the short form of a command-line option, return the index in the + /// options array corresponding to that option. + /// + /// \param c The character that is the short form of the command line option. + /// An 'int' is used as the value passed will be the return value + /// from 'getopt()' (or equivalent) which is an int. If the + /// character is not found, an exception will be thrown. + /// + /// \return A valid index value. + static int getIndex(int c); + + /// \brief Return long form of command switch for this field + /// + /// \param index A valid index (one of the values in the 'Index' enum). + /// + /// \return The long option name (e.q. "qr" for the Query/Response field). + static const char* name(int index); + + /// \brief Return header word offset + /// + /// Returns the byte offset in the DNS message header of the two-byte word + /// holding the data in question. + /// + /// \param index A valid index (one of the values in the 'Index' enum). + /// + /// \return The offset in the header for this datum. + static int word(int index); + + /// \brief Return mask associated with switch field + /// + /// \param index A valid index (one of the values in the 'Index' enum). + /// + /// \return The mask for this particular option in the DNS message flags + /// word. The returned value is only valid for options that + /// correspond to fields in the flags word. + static uint16_t mask(int index); + + /// \brief Return offset associated with option field + /// + /// \param index A valid index (one of the values in the 'Index' enum). + /// + /// \return The offset of the field corresponding to this option in the DNS + /// message flags field. The returned value is only valid for + /// options that correpond to fields in the flags word. + static int offset(int index); + + /// \brief Return minimum allowed value of an option + /// + /// \param index A valid index (one of the values in the 'Index' enum). + /// + /// \return Minimum allowed value for this option. + static uint32_t minval(int index); + + /// \brief Return default value of an option + /// + /// \param index A valid index (one of the values in the 'Index' enum). + /// + /// \return Default value for this option + static uint32_t defval(int index); + + /// \brief Return maximum allowed value of an option + /// + /// \param index A valid index (one of the values in the 'Index' enum). + /// + /// \return Maximum allowed value for this option. If the option is a bit + /// in the flags field of the DNS message hearder, this will be 1. + static uint32_t maxval(int index); + + /// \brief Check Array Index + /// + /// Checks the passed field index and throws an exception if it does not + /// correspond to one of the valid indexes in the 'Index' enum. + /// + /// \param index An index value. + static void checkIndex(int i) { + if ((i < 0) || (i >= SIZE)) { + isc_throw(isc::OutOfRange, "option index must be in the range " + "0 to " << SIZE); + } + } +}; + +} // namespace badpacket +} // namespace isc + +#endif // __OPTION_INFO_H diff --git a/tests/tools/badpacket/scan.cc b/tests/tools/badpacket/scan.cc new file mode 100644 index 0000000000000000000000000000000000000000..b0c605cc12e4d44efc27a624010fe6927a60df43 --- /dev/null +++ b/tests/tools/badpacket/scan.cc @@ -0,0 +1,316 @@ +// Copyright (C) 2011 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. + +#include +#include +#include +#include + +#include + +#include + +// on sunstudio, asio.hpp needs unistd.h for pipe() to be defined +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "command_options.h" +#include "header_flags.h" +#include "scan.h" + +using namespace std; +using namespace isc::asiolink; +using namespace isc::asiodns; +using namespace isc::dns; +using namespace isc::util; +using namespace isc::util::str; + +namespace isc { +namespace badpacket { + +// Perform the scan from start to end on a single question. +void +Scan::scan(const CommandOptions& options) { + + // Create the message buffer to use + Message message(Message::RENDER); + message.setOpcode(Opcode::QUERY()); + message.setRcode(Rcode::NOERROR()); + message.addQuestion(Question(Name(options.getQname()), RRClass::IN(), + RRType::A())); + + OutputBufferPtr msgbuf(new OutputBuffer(512)); + MessageRenderer renderer(*msgbuf); + message.toWire(renderer); + + iterateFlagsStart(msgbuf, options); +} + +// Iterate through the various settings in the flags fields. +void +Scan::iterateFlagsStart(OutputBufferPtr& msgbuf, const CommandOptions& options) { + HeaderFlags flags; + iterateFlags(msgbuf, options, flags, OptionInfo::FLAGS_START, + OptionInfo::FLAGS_END); +} +void +Scan::iterateFlags(OutputBufferPtr& msgbuf, const CommandOptions& options, + HeaderFlags& flags, int index, int maxindex) +{ + // Is the index valid? + if (index <= maxindex) { + + // Index is valid, did the command line specify a range of values for + // this field? + if (options.present(index)) { + + // It did, so loop between minimum and maximum values given. + for (uint32_t i = options.minimum(index); + i <= options.maximum(index); ++i) { + flags.set(index, i); + + // Recurse to set the next option. + iterateFlags(msgbuf, options, flags, (index + 1), maxindex); + } + } else { + + // Not specified on command line, so set the default value in the + // flags and process the next index. + flags.set(index, OptionInfo::defval(index)); + iterateFlags(msgbuf, options, flags, (index + 1), maxindex); + } + } else { + + // Index is not valid, so we have recursed enough to process all the + // flags fields. Set the value in the message header and call the next + // stage in the processing. + // + // (In the next statement, the "word" offset of in the header is the + // same for all flags options, so the value for an arbitrary field + // (QR) has been used.) + msgbuf->writeUint16At(flags.getValue(), + OptionInfo::word(OptionInfo::QR)); + iterateCountStart(msgbuf, options); + } +} + +// Iterate through the various count fields +void +Scan::iterateCountStart(OutputBufferPtr& msgbuf, const CommandOptions& options) +{ + iterateCount(msgbuf, options, OptionInfo::COUNT_START, + OptionInfo::COUNT_END); +} + +void +Scan::iterateCount(OutputBufferPtr& msgbuf, const CommandOptions& options, + int index, int maxindex) +{ + // If the index is valid, process the iteration over the range for this + // flags field. + if (index <= maxindex) { + + // Index is valid, did the command line specify a range of values for + // this field? + if (options.present(index)) { + + // It did, so loop between minimum and maximum values given. + for (uint32_t i = options.minimum(index); + i <= options.maximum(index); ++i) { + + // Set the value in the message buffer header and recurse to + // the next option. + msgbuf->writeUint16At(i, OptionInfo::word(index)); + iterateCount(msgbuf, options, (index + 1), maxindex); + } + } else { + + // Not specified on command line, so do change anything and process + // the next index. + iterateCount(msgbuf, options, (index + 1), maxindex); + } + } else { + + // Index is not valid, so we have recursed enough to process all the + // flags fields. Do the next stage of the processing. + sizeMessage(msgbuf, options); + } +} + +// Alter the message size. +void +Scan::sizeMessage(OutputBufferPtr& msgbuf, const CommandOptions& options) { + + if (options.present(OptionInfo::MS)) { + + // Iterate over the range of message sizes + for (size_t i = options.minimum(OptionInfo::MS); + i <= options.maximum(OptionInfo::MS); ++i) { + + // Copy the data into a new buffer. + OutputBufferPtr newbuf(new OutputBuffer(i)); + newbuf->writeData(msgbuf->getData(), min(msgbuf->getLength(), i)); + + // Pad with junk (actually pseudo-random data) if the new buffer is + // longer than the old. + for (size_t j = newbuf->getLength(); j < i; ++j) { + newbuf->writeUint8(static_cast(rand() & 0xFFU)); + } + + // ... and process. + scanOne(newbuf, options); + } + } else { + + // No packet size given, just process the message as it. + scanOne(msgbuf, options); + } +} + +// Perform the message exchange for a single combination command options. +void +Scan::scanOne(isc::util::OutputBufferPtr& msgbuf, const CommandOptions& options) { + // Store the interpretation of outgoing message. + string fields = string("(") + getFields(msgbuf) + string(")"); + + // Do the I/O, waiting for a reply + OutputBufferPtr replybuf(new OutputBuffer(512)); + performIO(msgbuf, replybuf, options); + + string status = ""; + string returned = ""; + switch (result_) { + case IOFetch::SUCCESS: + { + status = "SUCCESS"; + + // Parse the reply and get the fields + returned = string("(") + getFields(replybuf) + string(")"); + lowercase(returned); + } + break; + + case IOFetch::TIME_OUT: + status = "TIMEOUT"; + break; + + case IOFetch::STOPPED: + status = "STOPPED"; + break; + + default: + status = "UNKNOWN"; + } + + // ... and output the result + cout << status << ": " << fields << " " << returned << "\n"; +} + +// Get interpretation of the message fields. +std::string +Scan::getFields(isc::util::OutputBufferPtr& msgbuf) { + + // Header flags. (Note that all come from the same word in the message, so + // using the word offset for the QR flag as the position in the buffer from + // which to extract the values is valid.) + HeaderFlags flags; + InputBuffer inbuf(msgbuf->getData(), msgbuf->getLength()); + inbuf.setPosition(OptionInfo::word(OptionInfo::QR)); + flags.setValue(inbuf.readUint16()); + + std::ostringstream os; + os << std::hex << std::uppercase << + "QR:" << flags.get(OptionInfo::QR) << + " OP:" << flags.get(OptionInfo::OP) << + " AA:" << flags.get(OptionInfo::AA) << + " TC:" << flags.get(OptionInfo::TC) << + " RD:" << flags.get(OptionInfo::RD) << + " RA:" << flags.get(OptionInfo::RA) << + " Z:" << flags.get(OptionInfo::Z) << + " AD:" << flags.get(OptionInfo::AD) << + " CD:" << flags.get(OptionInfo::CD) << + " RC:" << flags.get(OptionInfo::RC); + + // Section count fields. + inbuf.setPosition(OptionInfo::word(OptionInfo::QC)); + os << std::dec << std::uppercase << + " QC:" << inbuf.readUint16(); + + inbuf.setPosition(OptionInfo::word(OptionInfo::AC)); + os << std::dec << std::uppercase << + " AC:" << inbuf.readUint16(); + + inbuf.setPosition(OptionInfo::word(OptionInfo::UC)); + os << std::dec << std::uppercase << + " UC:" << inbuf.readUint16(); + + inbuf.setPosition(OptionInfo::word(OptionInfo::DC)); + os << std::dec << std::uppercase << + " DC:" << inbuf.readUint16(); + + // ... and message size. + os << std::dec << std::uppercase << + " MS:" << msgbuf->getLength(); + + return (os.str()); +} + +// Perform the I/O to the nameserver. +void +Scan::performIO(OutputBufferPtr& sendbuf, OutputBufferPtr& recvbuf, + const CommandOptions& options) +{ + // Set up an I/O service for the I/O. This needs to be initialized before + // every call as the callback called when the I/O completes stops it. + service_.reset(new IOService()); + + // The object that will do the I/O + IOFetch fetch(IOFetch::UDP, *service_, sendbuf, + IOAddress(options.getAddress()), options.getPort(), recvbuf, + this, options.getTimeout()); + + // Execute the message exchange. The call to run() will return when a + // response is received or when the I/O times out. + (service_->get_io_service()).post(fetch); + service_->run(); +} + +// I/O Callback. Called when the message exchange completes or times out. +void +Scan::operator()(IOFetch::Result result) { + + // Record the result. This is accessed when deciding what was returned + // (if a timeout, nothing was returned). + result_ = result; + + // Stop the I/O service. This will cause the call to run() to return. + service_->stop(); +} + +} // namespace test +} // namespace isc diff --git a/tests/tools/badpacket/scan.h b/tests/tools/badpacket/scan.h new file mode 100644 index 0000000000000000000000000000000000000000..ca566462d9e9cdb0370787c93660fca5a39443ca --- /dev/null +++ b/tests/tools/badpacket/scan.h @@ -0,0 +1,198 @@ +// Copyright (C) 2011 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. + +#ifndef __SCAN_H +#define __SCAN_H + +#include + +#include + +#include + +#include +#include +#include + +#include "command_options.h" +#include "header_flags.h" + +namespace isc { +namespace badpacket { + +/// \brief Field Scan +/// +/// This class implements a field scan. Given a CommandOptions object, it will +/// cycle through combinations of the given options, sending and receiving +/// messages. For each packet exchange, a summary is written to stdout. + +class Scan : public isc::asiodns::IOFetch::Callback { +public: + + /// \brief Constructor + Scan() : service_(), result_() + {} + + /// \brief Run Scan + /// + /// Actually performs the scan for the combination of options. + /// + /// \param options Command-line options + void scan(const CommandOptions& options); + + /// \brief Callback + /// + /// This class is derived from the IOFetch::Callback class as it acts as the + /// callback object. When an asynchronous I/I has completed, this method + /// will be called. + /// + /// \param result Result of the asynchronous I/O. Zero implies success. + virtual void operator()(isc::asiodns::IOFetch::Result result); + +private: + /// \brief Iterate over flags fields options + /// + /// This method relies on the fact that data concerning the settings for + /// the fields in the flags word of the DNS message are held at adjacent + /// elements in the various data arrays and so can be accessed by a set + /// of contiguous index values. + /// + /// The method is passed an index value and the maximum valid index value. + /// If a set of values for the field at the given index was specified on + /// the command line, it loops through those values and sets the appropriate + /// value in the a copy of the DNS message header flags. It then calls + /// itself with an incremented index. If the value was not given, it just + /// sets a default value calls itself (with the incremented index). When + /// called with an index above the maximum valid index, the header flags + /// in the message buffer are set and the next stage of processing called. + /// + /// In this way, all fields can be cycled through without the need for a + /// single function to nest loops very deeply. + /// + /// \param msgbuf Message that will be sent to the remote nameserver. The + /// QID given will be ignored - the value used will be determined by + /// the sending code + /// \param options Command-line options (the important ones being address, + /// port and timeout). + /// \param flags Header flags + /// \param index Index of the current field to be processed. + /// \param maxindex Maximum valid index value + void iterateFlags(isc::util::OutputBufferPtr& msgbuf, + const CommandOptions& options, HeaderFlags& flags, + int index, int maxindex); + + /// \brief Start iterating over flags field options + /// + /// Kicks off the call to \c iterateFlags by calling it with the initial + /// index value. + /// + /// \param msgbuf Message that will be sent to the remote nameserver. The + /// QID given will be ignored - the value used will be determined by + /// the sending code + /// \param options Command-line options (the important ones being address, + /// port and timeout). + void iterateFlagsStart(isc::util::OutputBufferPtr& msgbuf, + const CommandOptions& options); + + /// \brief Iterate over count fields + /// + /// In a manner similar to iterateFlags, this iterates over all specified + /// values for each count field, recursively calling itself to process the + /// next field. When all fields have been processed, it chains to the + /// next stage of packet processing. + /// + /// \param msgbuf Message that will be sent to the remote nameserver. The + /// QID given will be ignored - the value used will be determined by + /// the sending code + /// \param options Command-line options (the important ones being address, + /// port and timeout). + /// \param index Index of the current field to be processed. + /// \param maxindex Maximum valid index value + void iterateCount(isc::util::OutputBufferPtr& msgbuf, + const CommandOptions& options, int index, int maxindex); + + /// \brief Start iterating over count fields + /// + /// Kicks off the call to \c iterateCount by calling it with the initial + /// index value. + /// + /// \param msgbuf Message that will be sent to the remote nameserver. The + /// QID given will be ignored - the value used will be determined by + /// the sending code + /// \param options Command-line options (the important ones being address, + /// port and timeout). + void iterateCountStart(isc::util::OutputBufferPtr& msgbuf, + const CommandOptions& options); + + /// \brief Iterate over message sizes + /// + /// If the message size option is given on the command line, the message + /// sent to the remote system is either truncated or extended (with zeroes) + /// before being set. + /// + /// \param msgbuf Message that will be sent to the remote nameserver. The + /// QID given will be ignored - the value used will be determined by + /// the sending code + /// \param options Command-line options (the important ones being address, + /// port and timeout). + void sizeMessage(isc::util::OutputBufferPtr& msgbuf, + const CommandOptions& options); + + /// \brief Scan One Value + /// + /// Performs one exchange of messages with the remote nameserver, sending + /// the specified message. + /// + /// \param msgbuf Message that will be sent to the remote nameserver. The + /// QID given will be ignored - the value used will be determined by + /// the sending code + /// \param options Command-line options (the important ones being address, + /// port and timeout). + void scanOne(isc::util::OutputBufferPtr& msgbuf, + const CommandOptions& options); + + /// \brief Perform I/O + /// + /// Performs a single query to the nameserver and reads the response. It + /// outputs a summary of the result. + /// + /// \param sendbuf Buffer sent to the nameserver + /// \param recvbuf Buffer to hold reply from the nameserver + /// \param options Command-line options + void performIO(isc::util::OutputBufferPtr& sendbuf, + isc::util::OutputBufferPtr& recvbuf, + const CommandOptions& options); + + /// \brief Get Fields + /// + /// Interprets the fields in a DNS message and converts them to a brief + /// textual format. + /// + /// \param msg Message for which the header is value + /// + /// \return A string that holds a textual interpretation of all the fields + /// in the header. + std::string getFields(isc::util::OutputBufferPtr& msgbuf); + + // Member variables + + boost::scoped_ptr service_; + ///< Service to run the scan + isc::asiodns::IOFetch::Result result_; ///< Result of the I/O +}; + +} // namespace test +} // namespace isc + +#endif // __SCAN_H diff --git a/tests/tools/badpacket/tests/Makefile.am b/tests/tools/badpacket/tests/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..7cde4aa1179109f652c6d8786b368bc938dc5f4d --- /dev/null +++ b/tests/tools/badpacket/tests/Makefile.am @@ -0,0 +1,31 @@ +SUBDIRS = . + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CXXFLAGS = $(B10_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +CLEANFILES = *.gcno *.gcda + +TESTS = +if HAVE_GTEST +TESTS += run_unittests +run_unittests_SOURCES = run_unittests.cc +run_unittests_SOURCES += command_options_unittest.cc +run_unittests_SOURCES += option_info_unittest.cc +run_unittests_SOURCES += header_flags_unittest.cc +run_unittests_SOURCES += $(top_builddir)/tests/tools/badpacket/command_options.cc +run_unittests_SOURCES += $(top_builddir)/tests/tools/badpacket/option_info.cc + +run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) +run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) +run_unittests_LDFLAGS += $(top_builddir)/src/lib/log/liblog.la +run_unittests_LDFLAGS += $(top_builddir)/src/lib/exceptions/libexceptions.la + +run_unittests_LDADD = $(GTEST_LDADD) +endif + +noinst_PROGRAMS = $(TESTS) diff --git a/tests/tools/badpacket/tests/command_options_unittest.cc b/tests/tools/badpacket/tests/command_options_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..014618e900744432a8ecad460b92ac0542aeebfa --- /dev/null +++ b/tests/tools/badpacket/tests/command_options_unittest.cc @@ -0,0 +1,300 @@ +// Copyright (C) 2011 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. + +#include +#include +#include + +#include "../command_options.h" + +#include "exceptions/exceptions.h" + +using namespace std; +using namespace isc; +using namespace isc::badpacket; + + +/// \brief Test Fixture Class + +class CommandOptionsTest : public virtual ::testing::Test, + public virtual CommandOptions +{ +public: + + /// \brief Default Constructor + CommandOptionsTest() + {} + + /// \brief Check Non-Limit Options + /// + /// Checks that the options that are NOT related to the message are set to + /// their default values. + void checkDefaultOtherValues() { + EXPECT_EQ("127.0.0.1", getAddress()); + EXPECT_EQ(53, getPort()); + EXPECT_EQ(500, getTimeout()); + EXPECT_EQ("www.example.com", getQname()); + } + + /// \brief Checks the minimum and maximum value specified for an option + /// + /// Checks the values for one of the options whose values are stored in the + /// class's options_ array. + /// + /// \param index Index of the option in the limits_ array + /// \param minval Expected minimum value + /// \param maxval Expected maximum value + void checkValuePair(int index, uint32_t minval = 0, uint32_t maxval = 0) { + EXPECT_EQ(minimum(index), minval); + EXPECT_EQ(maximum(index), maxval); + } + + /// \brief Checks that all options are at default values + /// + /// Checks that all options have both their maximum and minimum set to the + /// default values. + /// + /// \param except Index not to check. (This allows options not being tested + /// to be checked to see that they are at the default value.) As all + /// index values are positive, a negative value means check + /// everything. + void checkDefaultLimitsValues(int except = -1) { + for (int i = 0; i < OptionInfo::SIZE; ++i) { + if (i != except) { + checkValuePair(i, OptionInfo::defval(i), + OptionInfo::defval(i)); + } + } + } + + /// \brief Check valid command option + /// + /// Checks that the command line specification of one of the options taking + /// a value correctly processes the option. + /// + /// \param index Option index + /// \param optflag Option flag (in the form '--option') + /// \param optval Value to be passed to the option. + /// \param minval Expected minimum value + /// \param maxval Expected maximum value + void checkCommandValid(int index, const char* optflag, const char* optval, + uint32_t minval, uint32_t maxval) { + + // Set up the command line and parse it. + const char* argv[] = {"badpacket", NULL, NULL}; + argv[1] = optflag; + argv[2] = optval; + int argc = 3; + parse(argc, const_cast(argv)); + + // Check the results. Everything should be at the defaults except for + // the specified option, where the minimum and maximum should be as + // specified. + checkDefaultOtherValues(); + checkDefaultLimitsValues(index); + checkValuePair(index, minval, maxval); + } + + /// \brief Check invalid command option + /// + /// Passed a command with an invalid value, checks that the parsing throws + /// a BadValue exception. + /// + /// \param optflag Option flag (in the form '--option') + /// \param optval Value to be passed to the option. + void checkCommandInvalid(const char* optflag, const char* optval) { + + // Set up the command line and parse it. + const char* argv[] = {"badpacket", NULL, NULL}; + argv[1] = optflag; + argv[2] = optval; + int argc = 3; + EXPECT_THROW(parse(argc, const_cast(argv)), isc::BadValue); + } + + /// \brief Check one-bit field + /// + /// Explicitly for those fields in the flags word that are one bit wide, + /// perform a series of tests to check that they accept valid values and + /// reject invalid ones. + /// + /// \param index Option index + /// \param optflag Option flag (in the form '--option') + void checkOneBitField(int index, const char* optflag) { + checkCommandValid(index, optflag, "0", 0, 0); + checkCommandValid(index, optflag, "1", 1, 1); + checkCommandValid(index, optflag, "0-1", 0, 1); + checkCommandValid(index, optflag, "1-0", 0, 1); + checkCommandInvalid(optflag, "0-3"); + checkCommandInvalid(optflag, "4"); + checkCommandInvalid(optflag, "xyz"); + } + + /// \brief Check four-bit field + /// + /// Explicitly for those fields in the flags word that are four bits wide, + /// perform a series of tests to check that they accept valid values and + /// reject invalid ones. + /// + /// \param index Option index + /// \param optflag Option flag (in the form '--option') + void checkFourBitField(int index, const char* optflag) { + checkCommandValid(index, optflag, "0", 0, 0); + checkCommandValid(index, optflag, "15", 15, 15); + checkCommandValid(index, optflag, "0-15", 0, 15); + checkCommandValid(index, optflag, "15-0", 0, 15); + checkCommandInvalid(optflag, "0-17"); + checkCommandInvalid(optflag, "24"); + checkCommandInvalid(optflag, "xyz"); + } + + /// \brief Check sixteen-bit field + /// + /// Explicitly test the parsing of the fields that can take a 16-bit + /// value ranging from 0 to 65535. + /// + /// \param index Option index + /// \param optflag Option flag (in the form '--option') + void checkSixteenBitField(int index, const char* optflag) { + checkCommandValid(index, optflag, "0", 0, 0); + checkCommandValid(index, optflag, "65535", 65535, 65535); + checkCommandValid(index, optflag, "0-65535", 0, 65535); + checkCommandValid(index, optflag, "65535-0", 0, 65535); + checkCommandInvalid(optflag, "0-65536"); + checkCommandInvalid(optflag, "65537"); + checkCommandInvalid(optflag, "xyz"); + } +}; + +// Check that each of the non-message options will be recognised + +TEST_F(CommandOptionsTest, address) { + const char* argv[] = {"badpacket", "--address", "192.0.2.1"}; + int argc = sizeof(argv) / sizeof(const char*); + + // The conversion is ugly but it simplifies the process of entering the + // string constant. The cast throws away the "const"ness of the pointed-to + // strings in order to conform to the function signature; however, the + // called functions all treat the strings as const. + parse(argc, const_cast(argv)); + EXPECT_EQ("192.0.2.1", getAddress()); + EXPECT_EQ(53, getPort()); + EXPECT_EQ(500, getTimeout()); + EXPECT_EQ("www.example.com", getQname()); + checkDefaultLimitsValues(); +} + +TEST_F(CommandOptionsTest, port) { + const char* argv[] = {"badpacket", "--port", "153"}; + int argc = sizeof(argv) / sizeof(const char*); + + parse(argc, const_cast(argv)); + EXPECT_EQ("127.0.0.1", getAddress()); + EXPECT_EQ(153, getPort()); + EXPECT_EQ(500, getTimeout()); + EXPECT_EQ("www.example.com", getQname()); + checkDefaultLimitsValues(); +} + +TEST_F(CommandOptionsTest, timeout) { + const char* argv[] = {"badpacket", "--timeout", "250"}; + int argc = sizeof(argv) / sizeof(const char*); + + parse(argc, const_cast(argv)); + EXPECT_EQ("127.0.0.1", getAddress()); + EXPECT_EQ(53, getPort()); + EXPECT_EQ(250, getTimeout()); + EXPECT_EQ("www.example.com", getQname()); + checkDefaultLimitsValues(); +} + +TEST_F(CommandOptionsTest, parameter) { + const char* argv[] = {"badpacket", "ftp.example.net"}; + int argc = sizeof(argv) / sizeof(const char*); + + parse(argc, const_cast(argv)); + EXPECT_EQ("127.0.0.1", getAddress()); + EXPECT_EQ(53, getPort()); + EXPECT_EQ(500, getTimeout()); + EXPECT_EQ("ftp.example.net", getQname()); + checkDefaultLimitsValues(); +} + +// Test options representing the flags fields. + +TEST_F(CommandOptionsTest, qr) { + checkOneBitField(OptionInfo::QR, "--qr"); +} + +TEST_F(CommandOptionsTest, op) { + checkFourBitField(OptionInfo::OP, "--op"); +} + +TEST_F(CommandOptionsTest, aa) { + checkOneBitField(OptionInfo::AA, "--aa"); +} + +TEST_F(CommandOptionsTest, tc) { + checkOneBitField(OptionInfo::TC, "--tc"); +} + +TEST_F(CommandOptionsTest, z) { + checkOneBitField(OptionInfo::Z, "--z"); +} + +TEST_F(CommandOptionsTest, ad) { + checkOneBitField(OptionInfo::AD, "--ad"); +} + +TEST_F(CommandOptionsTest, cd) { + checkOneBitField(OptionInfo::CD, "--cd"); +} + +TEST_F(CommandOptionsTest, rc) { + checkFourBitField(OptionInfo::RC, "--rc"); +} + +// Section count options + +TEST_F(CommandOptionsTest, qc) { + checkSixteenBitField(OptionInfo::QC, "--qc"); +} + +TEST_F(CommandOptionsTest, ac) { + checkSixteenBitField(OptionInfo::AC, "--ac"); +} + +TEST_F(CommandOptionsTest, uc) { + checkSixteenBitField(OptionInfo::UC, "--uc"); +} + +TEST_F(CommandOptionsTest, dc) { + checkSixteenBitField(OptionInfo::DC, "--dc"); +} + +// ... and the message size option + +TEST_F(CommandOptionsTest, ms) { + int index = OptionInfo::MS; + const char* optflag = "--ms"; + + checkCommandValid(index, optflag, "1", 1, 1); + checkCommandValid(index, optflag, "65536", 65536, 65536); + checkCommandValid(index, optflag, "1-65536", 1, 65536); + checkCommandValid(index, optflag, "65536-1", 1, 65536); + checkCommandInvalid(optflag, "0"); + checkCommandInvalid(optflag, "1-65537"); + checkCommandInvalid(optflag, "65538"); + checkCommandInvalid(optflag, "xyz"); +} diff --git a/tests/tools/badpacket/tests/header_flags_unittest.cc b/tests/tools/badpacket/tests/header_flags_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..5a7a722eaf4a61e8848b0eab06fe9127fb47535e --- /dev/null +++ b/tests/tools/badpacket/tests/header_flags_unittest.cc @@ -0,0 +1,141 @@ +// Copyright (C) 2011 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. + +#include +#include +#include + +#include "../option_info.h" +#include "../header_flags.h" + +using namespace isc::badpacket; + +// Test fixture class + +class HeaderFlagsTest : public ::testing::Test { +public: + HeaderFlagsTest() {} + + + /// \brief Checks that all options are zero + /// + /// Checks that all flags options are set to zero. + /// + /// \param flags Flags structure to check. + /// \param except Index not to check. (This allows options not being tested + /// to be checked to see that they are at the default value.) As all + /// index values are positive, a negative value means check + /// everything. + void checkZero(const HeaderFlags& flags, int except = -1) { + + // Check individual fields + for (int i = OptionInfo::FLAGS_START; i < OptionInfo::FLAGS_END; ++i) { + if (i != except) { + EXPECT_EQ(0, flags.get(i)); + } + } + + // ... and check the composite + if (except == -1) { + EXPECT_EQ(0, flags.getValue()); + } else { + EXPECT_NE(0, flags.getValue()); + } + } + + /// \brief Check Option + /// + /// Checks that an option will only set the appropriate bits in the flags + /// field. + /// + /// \param index Index of the flags field to check. + /// \param maxval Maximum value of the header field. + void checkOption(int index, uint32_t maxval) { + + // Create header flags and check initialized properly. + HeaderFlags flags; + checkZero(flags); + + // Check we can set field to maximum. + flags.set(index, maxval); + EXPECT_EQ(maxval, flags.get(index)); + checkZero(flags, index); + + // Check we can reset it to zero. + flags.set(index, 0); + checkZero(flags); + } +}; + +// Set of tests to check that setting a bit only sets that bit and nothing +// else. + +TEST_F(HeaderFlagsTest, fields) { + checkOption(OptionInfo::QR, 1); + checkOption(OptionInfo::OP, 15); + checkOption(OptionInfo::AA, 1); + checkOption(OptionInfo::TC, 1); + checkOption(OptionInfo::RD, 1); + checkOption(OptionInfo::RA, 1); + checkOption(OptionInfo::Z, 1); + checkOption(OptionInfo::AD, 1); + checkOption(OptionInfo::CD, 1); + checkOption(OptionInfo::RC, 15); +} + +// Check that the correct bits are set + +TEST_F(HeaderFlagsTest, bitValues) { + HeaderFlags flags; + checkZero(flags); + + flags.set(OptionInfo::QR, 1); + EXPECT_EQ(0x8000, flags.getValue()); + + flags.set(OptionInfo::QR, 0); + flags.set(OptionInfo::OP, 15); + EXPECT_EQ(0x7800, flags.getValue()); + + flags.set(OptionInfo::OP, 0); + flags.set(OptionInfo::AA, 1); + EXPECT_EQ(0x0400, flags.getValue()); + + flags.set(OptionInfo::AA, 0); + flags.set(OptionInfo::TC, 1); + EXPECT_EQ(0x0200, flags.getValue()); + + flags.set(OptionInfo::TC, 0); + flags.set(OptionInfo::RD, 1); + EXPECT_EQ(0x0100, flags.getValue()); + + flags.set(OptionInfo::RD, 0); + flags.set(OptionInfo::RA, 1); + EXPECT_EQ(0x0080, flags.getValue()); + + flags.set(OptionInfo::RA, 0); + flags.set(OptionInfo::Z, 1); + EXPECT_EQ(0x0040, flags.getValue()); + + flags.set(OptionInfo::Z, 0); + flags.set(OptionInfo::AD, 1); + EXPECT_EQ(0x0020, flags.getValue()); + + flags.set(OptionInfo::AD, 0); + flags.set(OptionInfo::CD, 1); + EXPECT_EQ(0x0010, flags.getValue()); + + flags.set(OptionInfo::CD, 0); + flags.set(OptionInfo::RC, 15); + EXPECT_EQ(0x000F, flags.getValue()); +} diff --git a/tests/tools/badpacket/tests/option_info_unittest.cc b/tests/tools/badpacket/tests/option_info_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..8c061dec9b6c43803819ba95001f83d14976e22b --- /dev/null +++ b/tests/tools/badpacket/tests/option_info_unittest.cc @@ -0,0 +1,161 @@ +// Copyright (C) 2011 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. + +#include +#include +#include + +#include "../option_info.h" + +using namespace isc::badpacket; + + +// Test fixture class + +class OptionInfoTest : public ::testing::Test { +public: + OptionInfoTest() {} +}; + + +// Check the values are as expected + +TEST_F(OptionInfoTest, FlagValues) { + EXPECT_STREQ("qr", OptionInfo::name(OptionInfo::QR)); + EXPECT_STREQ("qr", OptionInfo::name(OptionInfo::getIndex('Q'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::QR)); + EXPECT_EQ(0x8000, OptionInfo::mask(OptionInfo::QR)); + EXPECT_EQ(15, OptionInfo::offset(OptionInfo::QR)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::QR)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::QR)); + EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::QR)); + + EXPECT_STREQ("op", OptionInfo::name(OptionInfo::OP)); + EXPECT_STREQ("op", OptionInfo::name(OptionInfo::getIndex('O'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::OP)); + EXPECT_EQ(0x7800, OptionInfo::mask(OptionInfo::OP)); + EXPECT_EQ(11, OptionInfo::offset(OptionInfo::OP)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::OP)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::OP)); + EXPECT_EQ(15, OptionInfo::maxval(OptionInfo::OP)); + + EXPECT_STREQ("aa", OptionInfo::name(OptionInfo::AA)); + EXPECT_STREQ("aa", OptionInfo::name(OptionInfo::getIndex('A'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::AA)); + EXPECT_EQ(0x0400, OptionInfo::mask(OptionInfo::AA)); + EXPECT_EQ(10, OptionInfo::offset(OptionInfo::AA)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::AA)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::AA)); + EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::AA)); + + EXPECT_STREQ("tc", OptionInfo::name(OptionInfo::TC)); + EXPECT_STREQ("tc", OptionInfo::name(OptionInfo::getIndex('T'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::TC)); + EXPECT_EQ(0x0200, OptionInfo::mask(OptionInfo::TC)); + EXPECT_EQ(9, OptionInfo::offset(OptionInfo::TC)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::TC)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::TC)); + EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::TC)); + + EXPECT_STREQ("rd", OptionInfo::name(OptionInfo::RD)); + EXPECT_STREQ("rd", OptionInfo::name(OptionInfo::getIndex('D'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::RD)); + EXPECT_EQ(0x0100, OptionInfo::mask(OptionInfo::RD)); + EXPECT_EQ(8, OptionInfo::offset(OptionInfo::RD)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::RD)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::RD)); + EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::RD)); + + EXPECT_STREQ("ra", OptionInfo::name(OptionInfo::RA)); + EXPECT_STREQ("ra", OptionInfo::name(OptionInfo::getIndex('R'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::RA)); + EXPECT_EQ(0x0080, OptionInfo::mask(OptionInfo::RA)); + EXPECT_EQ(7, OptionInfo::offset(OptionInfo::RA)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::RA)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::RA)); + EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::RA)); + + EXPECT_STREQ("z", OptionInfo::name(OptionInfo::Z)); + EXPECT_STREQ("z", OptionInfo::name(OptionInfo::getIndex('Z'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::Z)); + EXPECT_EQ(0x0040, OptionInfo::mask(OptionInfo::Z)); + EXPECT_EQ(6, OptionInfo::offset(OptionInfo::Z)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::Z)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::Z)); + EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::Z)); + + EXPECT_STREQ("ad", OptionInfo::name(OptionInfo::AD)); + EXPECT_STREQ("ad", OptionInfo::name(OptionInfo::getIndex('U'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::AD)); + EXPECT_EQ(0x0020, OptionInfo::mask(OptionInfo::AD)); + EXPECT_EQ(5, OptionInfo::offset(OptionInfo::AD)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::AD)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::AD)); + EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::AD)); + + EXPECT_STREQ("cd", OptionInfo::name(OptionInfo::CD)); + EXPECT_STREQ("cd", OptionInfo::name(OptionInfo::getIndex('C'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::CD)); + EXPECT_EQ(0x0010, OptionInfo::mask(OptionInfo::CD)); + EXPECT_EQ(4, OptionInfo::offset(OptionInfo::CD)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::CD)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::CD)); + EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::CD)); + + EXPECT_STREQ("rc", OptionInfo::name(OptionInfo::RC)); + EXPECT_STREQ("rc", OptionInfo::name(OptionInfo::getIndex('E'))); + EXPECT_EQ(2, OptionInfo::word(OptionInfo::RC)); + EXPECT_EQ(0x000F, OptionInfo::mask(OptionInfo::RC)); + EXPECT_EQ(0, OptionInfo::offset(OptionInfo::RC)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::RC)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::RC)); + EXPECT_EQ(15, OptionInfo::maxval(OptionInfo::RC)); +} + +TEST_F(OptionInfoTest, CountValues) { + EXPECT_STREQ("qc", OptionInfo::name(OptionInfo::QC)); + EXPECT_STREQ("qc", OptionInfo::name(OptionInfo::getIndex('Y'))); + EXPECT_EQ(4, OptionInfo::word(OptionInfo::QC)); + EXPECT_EQ(1, OptionInfo::defval(OptionInfo::QC)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::QC)); + EXPECT_EQ(0xFFFF, OptionInfo::maxval(OptionInfo::QC)); + + EXPECT_STREQ("ac", OptionInfo::name(OptionInfo::AC)); + EXPECT_STREQ("ac", OptionInfo::name(OptionInfo::getIndex('W'))); + EXPECT_EQ(6, OptionInfo::word(OptionInfo::AC)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::AC)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::AC)); + EXPECT_EQ(0xFFFF, OptionInfo::maxval(OptionInfo::AC)); + + EXPECT_STREQ("uc", OptionInfo::name(OptionInfo::UC)); + EXPECT_STREQ("uc", OptionInfo::name(OptionInfo::getIndex('H'))); + EXPECT_EQ(8, OptionInfo::word(OptionInfo::UC)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::UC)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::UC)); + EXPECT_EQ(0xFFFF, OptionInfo::maxval(OptionInfo::UC)); + + EXPECT_STREQ("dc", OptionInfo::name(OptionInfo::DC)); + EXPECT_STREQ("dc", OptionInfo::name(OptionInfo::getIndex('I'))); + EXPECT_EQ(10, OptionInfo::word(OptionInfo::DC)); + EXPECT_EQ(0, OptionInfo::defval(OptionInfo::DC)); + EXPECT_EQ(0, OptionInfo::minval(OptionInfo::DC)); + EXPECT_EQ(0xFFFF, OptionInfo::maxval(OptionInfo::DC)); +} + +TEST_F(OptionInfoTest, OtherValues) { + EXPECT_STREQ("ms", OptionInfo::name(OptionInfo::MS)); + EXPECT_STREQ("ms", OptionInfo::name(OptionInfo::getIndex('M'))); + EXPECT_EQ(1, OptionInfo::minval(OptionInfo::MS)); + EXPECT_EQ(65536, OptionInfo::maxval(OptionInfo::MS)); +} diff --git a/tests/tools/badpacket/tests/run_unittests.cc b/tests/tools/badpacket/tests/run_unittests.cc new file mode 100644 index 0000000000000000000000000000000000000000..624cf6fb6e45b22e071b7d5477ca69a66871fef9 --- /dev/null +++ b/tests/tools/badpacket/tests/run_unittests.cc @@ -0,0 +1,24 @@ +// Copyright (C) 2009 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. + +#include + +#include + +int +main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + return (RUN_ALL_TESTS()); +} diff --git a/tests/tools/badpacket/version.h b/tests/tools/badpacket/version.h new file mode 100644 index 0000000000000000000000000000000000000000..dc59b11f7e623df757b579334daf14bfcc352411 --- /dev/null +++ b/tests/tools/badpacket/version.h @@ -0,0 +1,26 @@ +// Copyright (C) 2011 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. + +#ifndef __VERSION_H +#define __VERSION_H + +namespace isc { +namespace badpacket { + +static const char* BADPACKET_VERSION = "1.0-1"; + +} // namespace badpacket +} // namespace isc + +#endif // __VERSION_H diff --git a/tools/query_cmp/README b/tools/query_cmp/README new file mode 100644 index 0000000000000000000000000000000000000000..bd3efccc2a320c79e310d086356a60991148325a --- /dev/null +++ b/tools/query_cmp/README @@ -0,0 +1,27 @@ +This is a tool to compare two DNS server's response to query. + +DIRECTORY STRUCTURE + +zonefile + The file under this directory is for the testee servers + to load before running the test, containing various types + of RRs in the test cases. It is in bind9's format. One + file is signed while the other is not, which you can choose. + +queries + The files under this directory are the input of the test, + involving various types of query cases. + +src + The scripts of this test. + It uses the dns python binding interface of bind10 from the + source tree, so src/lib/dns/python/.libs must be added to + PYTHONPATH environment variable ahead of running the tests. + +RUNNING + +e.g. +cd src +./query_two_server.py -u -f ../queries/dquery01 -s 10.10.1.1 -p 30000 -t 10.10.10.2 -q 30002 > bind10test_normal + +./query_two_server.py --help' for more details diff --git a/tools/query_cmp/queries/dquery01 b/tools/query_cmp/queries/dquery01 new file mode 100644 index 0000000000000000000000000000000000000000..923ba7dff223f73e245afee18fc65659e570b7c6 --- /dev/null +++ b/tools/query_cmp/queries/dquery01 @@ -0,0 +1,394 @@ +# Fields Description +# +#query:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT QNAME QTYPE QCLASS +#response:ID QR OPCODE AA TC RD RA Z AD CD RCODE QDCOUNT ANCOUNT NSCOUNT ARCOUNT QNAME QTYPE QCLASS +# := .. +# := NAME TYPE CLASS TTL RDLENGTH +# := ADDRESS | +# NSDNAME | +# MNAME RNAME SERIAL REFRESH RETRY EXPIRE MINIMUM | +# ... +# := .. +# := .. +# +# +# +# Description in BNF (http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form) +# ::=
+#
::= +# +# ::= +# +# ::=
+# ::= +# ::= +# ::= +# ::= { } +# ::= +# ::= | "" +# ::=