BIND 10 trac1067, updated. 3702df52de21023d90052afdc54732d9ad285b39 [trac1061] Logging descriptions
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Aug 4 08:55:42 UTC 2011
The branch, trac1067 has been updated
discards 747d2952c78ee32acc485946d3922cfe899a4b48 (commit)
discards f26298e3ae274ccea3d4bcef37f5ac85da383461 (commit)
discards 7489fa475c3f5963323a6b660e4544e48f45d37c (commit)
discards dae8a2aabc0cc9c9f3794276676872014c5a58fa (commit)
discards 3cebb4e77088feb357b485aeeda26429f98dce9b (commit)
discards c5124556a1a8907a84bb2c2bd1912da0c0aaafcc (commit)
discards 19912ea4537e669f9c9ad1108b6f5453025738ef (commit)
discards da32354d05eb22cecdf9543f542636d44e503a20 (commit)
discards 5fd94aa027828c50e63ae1073d9d6708e0a9c223 (commit)
discards 7b04ab1afedaf73b4492f9e0a9210dc4392ea068 (commit)
discards 4625b640b9b5892da7f35f165407ed3e850353d9 (commit)
discards d2f96b7e1e3e4a5917ea73a56429fa645d8ede7c (commit)
discards a01cd4ac5a68a1749593600c0f338620511cae2d (commit)
discards e62e50f3143aa67bd60c2351ad61d7544f28d4ca (commit)
discards d299036c6ac281d1d6c119c5fdbe603bed404851 (commit)
discards e5d9f259dce621201a2c52b56b260f8de776ecc0 (commit)
discards f773f9ac21221663bd093806374cab83abd2288d (commit)
discards 25b02eeaa9acda461629d19c4c6c2b20b5850795 (commit)
discards d9d0d1f6cb6c6210f293dcf5c181024d2df787f6 (commit)
discards c8710633f9cad97adc038852319f1a7a22cebc44 (commit)
discards d42d232acb16847ea8ec775854469e3226cdfe17 (commit)
discards 34634d2ba1efba222403e8a210379d1573759939 (commit)
discards 0373b72ac00aaecb7745cf7fd129424994e2fab8 (commit)
discards 07e015d587c487ce1934144abe59010b8f588c81 (commit)
discards 253a3fad875abba510e13a3112b6176b9e272e84 (commit)
discards eff38a97dea5a54b7a9f3e1213cd5e8b2b15be37 (commit)
discards 21b4324449c7091d36fc3e153d3e0f4ea3515278 (commit)
via 3702df52de21023d90052afdc54732d9ad285b39 (commit)
via e47f04584b00f6d7b5c8bf9e8ae6af9aaa6831fd (commit)
via 823e0fcf308c7f3fc88ba48070e12bd995e75392 (commit)
via 608d45610e9f499fb43d2e52eba461d489a7d45f (commit)
via e76dc86b0a01a54dab56cbf8552bd0c5fbb5b461 (commit)
via be9d5fe994e6a086a951e432d56e7de2af3cfd09 (commit)
via 11b8b873e7fd6722053aa224d20f29350bf2b298 (commit)
via b63b9aac20259f3612e23c7a3e977dcb48693ef1 (commit)
via 14a0766224d50d1c4c409e883cf29515dafc25f0 (commit)
via b5fbd9c942b1080aa60a48ee23da60574d1fc22f (commit)
via 63f4617b5ab99d75e98e40760ff68bb1615a84e6 (commit)
via 579fd2bf848e994ed6dcd8d1c3633f2fa62cbd28 (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (747d2952c78ee32acc485946d3922cfe899a4b48)
\
N -- N -- N (3702df52de21023d90052afdc54732d9ad285b39)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 3702df52de21023d90052afdc54732d9ad285b39
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Aug 3 11:36:47 2011 +0200
[trac1061] Logging descriptions
commit e47f04584b00f6d7b5c8bf9e8ae6af9aaa6831fd
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Aug 3 11:29:52 2011 +0200
[trac1061] Doxygen comments for SQLite3Connection
commit 823e0fcf308c7f3fc88ba48070e12bd995e75392
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Aug 3 11:14:41 2011 +0200
[trac1061] Implement SQLite3Connection::getZone
commit 608d45610e9f499fb43d2e52eba461d489a7d45f
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Aug 3 10:58:47 2011 +0200
[trac1061] Tests for SQLite3Connection::getZone
These are not copied, as this method was not public in the original
implementation. The constructor got a new parameter, the RR class, so it
knows what to query from the DB.
commit e76dc86b0a01a54dab56cbf8552bd0c5fbb5b461
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Aug 2 22:28:14 2011 +0200
[trac1061] (Co|De)structor of SQLite3Connection
Most of the code is slightly modified copy-paste from the
Sqlite3DataSource. No documentation or log messages and the getZone
method is dummy. But it compiles and provides some kind of frame for the
rest.
commit be9d5fe994e6a086a951e432d56e7de2af3cfd09
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Aug 1 13:29:36 2011 +0200
[trac1061] First attempt at SQLite3Connection interface
It will probably change during the implementation though.
commit 11b8b873e7fd6722053aa224d20f29350bf2b298
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Aug 1 13:06:13 2011 +0200
[trac1061] Implement finding a zone in DB
And provide some basics of the ZoneFinder, which does not work, but
compiles at last.
commit b63b9aac20259f3612e23c7a3e977dcb48693ef1
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Aug 1 13:04:40 2011 +0200
[trac1061] Don't return reference
While it works for in-memory zone and similar, it can't be done with
databases, as the database returns some primitive data and it must be
created on the spot.
commit 14a0766224d50d1c4c409e883cf29515dafc25f0
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Aug 1 12:03:35 2011 +0200
[trac1061] Test for constructor exception
commit b5fbd9c942b1080aa60a48ee23da60574d1fc22f
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Aug 1 11:47:37 2011 +0200
[trac1061] Tests for finding of the zone.
commit 63f4617b5ab99d75e98e40760ff68bb1615a84e6
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Jul 28 15:42:45 2011 +0200
[trac1061] Doxygen comments for database classes
commit 579fd2bf848e994ed6dcd8d1c3633f2fa62cbd28
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Jul 28 13:47:17 2011 +0200
[trac1061] Interface of the database connection and client
It will look something like this, hopefully. Let's see if it works.
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 10 -
configure.ac | 3 +-
src/bin/auth/Makefile.am | 1 -
src/bin/auth/benchmarks/Makefile.am | 1 -
src/bin/auth/tests/Makefile.am | 1 -
src/bin/auth/tests/query_unittest.cc | 4 +-
src/bin/bind10/Makefile.am | 6 +-
src/{lib/python/isc => bin}/bind10/__init__.py | 0
src/bin/bind10/bind10_src.py.in | 6 +-
src/bin/bind10/run_bind10.sh.in | 2 +-
src/{lib/python/isc => bin}/bind10/sockcreator.py | 0
src/bin/bind10/tests/Makefile.am | 2 +-
.../bind10/tests/sockcreator_test.py.in} | 2 +-
src/bin/dhcp6/Makefile.am | 1 -
src/bin/host/Makefile.am | 1 -
src/bin/zonemgr/zonemgr.py.in | 4 -
src/lib/bench/tests/Makefile.am | 1 -
src/lib/cache/tests/Makefile.am | 1 -
src/lib/config/ccsession.cc | 129 ++-------
src/lib/config/ccsession.h | 4 +-
src/lib/config/config_log.h | 8 -
src/lib/config/config_messages.mes | 25 --
src/lib/config/tests/ccsession_unittests.cc | 58 ++--
src/lib/datasrc/Makefile.am | 2 +
src/lib/datasrc/client.h | 2 +
src/lib/datasrc/database.cc | 85 +++++
src/lib/datasrc/database.h | 192 ++++++++++++
src/lib/datasrc/datasrc_messages.mes | 14 +-
src/lib/datasrc/memory_datasrc.cc | 4 +-
src/lib/datasrc/memory_datasrc.h | 4 +-
src/lib/datasrc/sqlite3_connection.cc | 322 ++++++++++++++++++++
src/lib/datasrc/sqlite3_connection.h | 111 +++++++
src/lib/datasrc/tests/Makefile.am | 3 +-
src/lib/datasrc/tests/database_unittest.cc | 99 ++++++
.../datasrc/tests/sqlite3_connection_unittest.cc | 116 +++++++
src/lib/datasrc/zone.h | 4 +-
src/lib/dns/Makefile.am | 2 -
src/lib/dns/benchmarks/Makefile.am | 1 -
src/lib/dns/rdata/any_255/tsig_250.cc | 126 +++++---
src/lib/dns/rdata/in_1/srv_33.cc | 245 ---------------
src/lib/dns/rdata/in_1/srv_33.h | 93 ------
src/lib/dns/tests/Makefile.am | 1 -
src/lib/dns/tests/rdata_srv_unittest.cc | 173 -----------
src/lib/dns/tests/testdata/Makefile.am | 1 -
src/lib/dns/tests/testdata/rdata_srv_fromWire | 36 ---
src/lib/python/isc/Makefile.am | 2 +-
src/lib/python/isc/bind10/Makefile.am | 4 -
src/lib/python/isc/bind10/tests/Makefile.am | 29 --
src/lib/resolve/tests/Makefile.am | 1 -
src/lib/util/strutil.cc | 11 -
src/lib/util/strutil.h | 62 ----
src/lib/util/tests/strutil_unittest.cc | 80 +----
52 files changed, 1110 insertions(+), 985 deletions(-)
rename src/{lib/python/isc => bin}/bind10/__init__.py (100%)
rename src/{lib/python/isc => bin}/bind10/sockcreator.py (100%)
rename src/{lib/python/isc/bind10/tests/sockcreator_test.py => bin/bind10/tests/sockcreator_test.py.in} (99%)
create mode 100644 src/lib/datasrc/database.cc
create mode 100644 src/lib/datasrc/database.h
create mode 100644 src/lib/datasrc/sqlite3_connection.cc
create mode 100644 src/lib/datasrc/sqlite3_connection.h
create mode 100644 src/lib/datasrc/tests/database_unittest.cc
create mode 100644 src/lib/datasrc/tests/sqlite3_connection_unittest.cc
delete mode 100644 src/lib/dns/rdata/in_1/srv_33.cc
delete mode 100644 src/lib/dns/rdata/in_1/srv_33.h
delete mode 100644 src/lib/dns/tests/rdata_srv_unittest.cc
delete mode 100644 src/lib/dns/tests/testdata/rdata_srv_fromWire
delete mode 100644 src/lib/python/isc/bind10/Makefile.am
delete mode 100644 src/lib/python/isc/bind10/tests/Makefile.am
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 5a14558..41c9faa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,13 +1,3 @@
-277. [func] jerry
- Implement the SRV rrtype according to RFC2782.
- (Trac #1128, git 5fd94aa027828c50e63ae1073d9d6708e0a9c223)
-
-276. [func] stephen
- Although the top-level loggers are named after the program (e.g.
- b10-auth, b10-resolver), allow the logger configuration to omit the
- "b10-" prefix and use just the module name.
- (Trac #1003, git a01cd4ac5a68a1749593600c0f338620511cae2d)
-
275. [func] jinmei
Added support for TSIG key matching in ACLs. The xfrout ACL can
now refer to TSIG key names using the "key" attribute. For
diff --git a/configure.ac b/configure.ac
index 4ff0d07..0ede949 100644
--- a/configure.ac
+++ b/configure.ac
@@ -839,8 +839,6 @@ AC_CONFIG_FILES([Makefile
src/lib/python/isc/notify/Makefile
src/lib/python/isc/notify/tests/Makefile
src/lib/python/isc/testutils/Makefile
- src/lib/python/isc/bind10/Makefile
- src/lib/python/isc/bind10/tests/Makefile
src/lib/config/Makefile
src/lib/config/tests/Makefile
src/lib/config/tests/testdata/Makefile
@@ -909,6 +907,7 @@ AC_OUTPUT([doc/version.ent
src/bin/bind10/bind10_src.py
src/bin/bind10/run_bind10.sh
src/bin/bind10/tests/bind10_test.py
+ src/bin/bind10/tests/sockcreator_test.py
src/bin/bindctl/run_bindctl.sh
src/bin/bindctl/bindctl_main.py
src/bin/bindctl/tests/bindctl_test
diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am
index e3128b5..64136c1 100644
--- a/src/bin/auth/Makefile.am
+++ b/src/bin/auth/Makefile.am
@@ -56,7 +56,6 @@ EXTRA_DIST += auth_messages.mes
b10_auth_LDADD = $(top_builddir)/src/lib/datasrc/libdatasrc.la
b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-b10_auth_LDADD += $(top_builddir)/src/lib/util/libutil.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
diff --git a/src/bin/auth/benchmarks/Makefile.am b/src/bin/auth/benchmarks/Makefile.am
index d51495b..cf3fe4a 100644
--- a/src/bin/auth/benchmarks/Makefile.am
+++ b/src/bin/auth/benchmarks/Makefile.am
@@ -17,7 +17,6 @@ query_bench_SOURCES += ../auth_log.h ../auth_log.cc
nodist_query_bench_SOURCES = ../auth_messages.h ../auth_messages.cc
query_bench_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
-query_bench_LDADD += $(top_builddir)/src/lib/util/libutil.la
query_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
query_bench_LDADD += $(top_builddir)/src/lib/bench/libbench.la
query_bench_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index 5cd2f5a..71520c2 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -47,7 +47,6 @@ 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/util/libutil.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
diff --git a/src/bin/auth/tests/query_unittest.cc b/src/bin/auth/tests/query_unittest.cc
index 6a75856..9ef8c13 100644
--- a/src/bin/auth/tests/query_unittest.cc
+++ b/src/bin/auth/tests/query_unittest.cc
@@ -122,8 +122,8 @@ public:
masterLoad(zone_stream, origin_, rrclass_,
boost::bind(&MockZoneFinder::loadRRset, this, _1));
}
- virtual const isc::dns::Name& getOrigin() const { return (origin_); }
- virtual const isc::dns::RRClass& getClass() const { return (rrclass_); }
+ virtual isc::dns::Name getOrigin() const { return (origin_); }
+ virtual isc::dns::RRClass getClass() const { return (rrclass_); }
virtual FindResult find(const isc::dns::Name& name,
const isc::dns::RRType& type,
RRsetList* target = NULL,
diff --git a/src/bin/bind10/Makefile.am b/src/bin/bind10/Makefile.am
index 6ab88d8..1a5ce64 100644
--- a/src/bin/bind10/Makefile.am
+++ b/src/bin/bind10/Makefile.am
@@ -1,7 +1,11 @@
SUBDIRS = . tests
sbin_SCRIPTS = bind10
-CLEANFILES = bind10 bind10_src.pyc bind10_messages.py bind10_messages.pyc
+CLEANFILES = bind10 bind10_src.pyc bind10_messages.py bind10_messages.pyc \
+ sockcreator.pyc
+
+python_PYTHON = __init__.py sockcreator.py
+pythondir = $(pyexecdir)/bind10
pkglibexecdir = $(libexecdir)/@PACKAGE@
pyexec_DATA = bind10_messages.py
diff --git a/src/bin/bind10/__init__.py b/src/bin/bind10/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/bin/bind10/bind10_src.py.in b/src/bin/bind10/bind10_src.py.in
index b497f7c..bbb17a2 100755
--- a/src/bin/bind10/bind10_src.py.in
+++ b/src/bin/bind10/bind10_src.py.in
@@ -67,7 +67,7 @@ import isc.util.process
import isc.net.parse
import isc.log
from bind10_messages import *
-import isc.bind10.sockcreator
+import bind10.sockcreator
isc.log.init("b10-boss")
logger = isc.log.Logger("boss")
@@ -337,8 +337,8 @@ class BoB:
def start_creator(self):
self.curproc = 'b10-sockcreator'
- self.sockcreator = isc.bind10.sockcreator.Creator("@@LIBEXECDIR@@:" +
- os.environ['PATH'])
+ self.sockcreator = bind10.sockcreator.Creator("@@LIBEXECDIR@@:" +
+ os.environ['PATH'])
def stop_creator(self, kill=False):
if self.sockcreator is None:
diff --git a/src/bin/bind10/run_bind10.sh.in b/src/bin/bind10/run_bind10.sh.in
index b5b9721..bb44ca0 100755
--- a/src/bin/bind10/run_bind10.sh.in
+++ b/src/bin/bind10/run_bind10.sh.in
@@ -20,7 +20,7 @@ export PYTHON_EXEC
BIND10_PATH=@abs_top_builddir@/src/bin/bind10
-PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/resolver:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/stats:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:@abs_top_builddir@/src/bin/dhcp6:@abs_top_builddir@/src/bin/sockcreator:$PATH
+PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/resolver:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/stats:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:@abs_top_builddir@/src/bin/dhcp6:$PATH
export PATH
PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs:@abs_top_builddir@/src/lib/util/io/.libs:@abs_top_builddir@/src/lib/python/isc/config:@abs_top_builddir@/src/lib/python/isc/acl/.libs:
diff --git a/src/bin/bind10/sockcreator.py b/src/bin/bind10/sockcreator.py
new file mode 100644
index 0000000..9fcc74e
--- /dev/null
+++ b/src/bin/bind10/sockcreator.py
@@ -0,0 +1,226 @@
+# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+#
+# 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.
+
+import socket
+import struct
+import os
+import subprocess
+from bind10_messages import *
+from libutil_io_python import recv_fd
+
+logger = isc.log.Logger("boss")
+
+"""
+Module that comunicates with the privileged socket creator (b10-sockcreator).
+"""
+
+class CreatorError(Exception):
+ """
+ Exception for socket creator related errors.
+
+ It has two members: fatal and errno and they are just holding the values
+ passed to the __init__ function.
+ """
+
+ def __init__(self, message, fatal, errno=None):
+ """
+ Creates the exception. The message argument is the usual string.
+ The fatal one tells if the error is fatal (eg. the creator crashed)
+ and errno is the errno value returned from socket creator, if
+ applicable.
+ """
+ Exception.__init__(self, message)
+ self.fatal = fatal
+ self.errno = errno
+
+class Parser:
+ """
+ This class knows the sockcreator language. It creates commands, sends them
+ and receives the answers and parses them.
+
+ It does not start it, the communication channel must be provided.
+
+ In theory, anything here can throw a fatal CreatorError exception, but it
+ happens only in case something like the creator process crashes. Any other
+ occasions are mentioned explicitly.
+ """
+
+ def __init__(self, creator_socket):
+ """
+ Creates the parser. The creator_socket is socket to the socket creator
+ process that will be used for communication. However, the object must
+ have a read_fd() method to read the file descriptor. This slightly
+ unusual trick with modifying an object is used to easy up testing.
+
+ You can use WrappedSocket in production code to add the method to any
+ ordinary socket.
+ """
+ self.__socket = creator_socket
+ logger.info(BIND10_SOCKCREATOR_INIT)
+
+ def terminate(self):
+ """
+ Asks the creator process to terminate and waits for it to close the
+ socket. Does not return anything. Raises a CreatorError if there is
+ still data on the socket, if there is an error closing the socket,
+ or if the socket had already been closed.
+ """
+ if self.__socket is None:
+ raise CreatorError('Terminated already', True)
+ logger.info(BIND10_SOCKCREATOR_TERMINATE)
+ try:
+ self.__socket.sendall(b'T')
+ # Wait for an EOF - it will return empty data
+ eof = self.__socket.recv(1)
+ if len(eof) != 0:
+ raise CreatorError('Protocol error - data after terminated',
+ True)
+ self.__socket = None
+ except socket.error as se:
+ self.__socket = None
+ raise CreatorError(str(se), True)
+
+ def get_socket(self, address, port, socktype):
+ """
+ Asks the socket creator process to create a socket. Pass an address
+ (the isc.net.IPaddr object), port number and socket type (either
+ string "UDP", "TCP" or constant socket.SOCK_DGRAM or
+ socket.SOCK_STREAM.
+
+ Blocks until it is provided by the socket creator process (which
+ should be fast, as it is on localhost) and returns the file descriptor
+ number. It raises a CreatorError exception if the creation fails.
+ """
+ if self.__socket is None:
+ raise CreatorError('Socket requested on terminated creator', True)
+ # First, assemble the request from parts
+ logger.info(BIND10_SOCKET_GET, address, port, socktype)
+ data = b'S'
+ if socktype == 'UDP' or socktype == socket.SOCK_DGRAM:
+ data += b'U'
+ elif socktype == 'TCP' or socktype == socket.SOCK_STREAM:
+ data += b'T'
+ else:
+ raise ValueError('Unknown socket type: ' + str(socktype))
+ if address.family == socket.AF_INET:
+ data += b'4'
+ elif address.family == socket.AF_INET6:
+ data += b'6'
+ else:
+ raise ValueError('Unknown address family in address')
+ data += struct.pack('!H', port)
+ data += address.addr
+ try:
+ # Send the request
+ self.__socket.sendall(data)
+ answer = self.__socket.recv(1)
+ if answer == b'S':
+ # Success!
+ result = self.__socket.read_fd()
+ logger.info(BIND10_SOCKET_CREATED, result)
+ return result
+ elif answer == b'E':
+ # There was an error, read the error as well
+ error = self.__socket.recv(1)
+ errno = struct.unpack('i',
+ self.__read_all(len(struct.pack('i',
+ 0))))
+ if error == b'S':
+ cause = 'socket'
+ elif error == b'B':
+ cause = 'bind'
+ else:
+ self.__socket = None
+ logger.fatal(BIND10_SOCKCREATOR_BAD_CAUSE, error)
+ raise CreatorError('Unknown error cause' + str(answer), True)
+ logger.error(BIND10_SOCKET_ERROR, cause, errno[0],
+ os.strerror(errno[0]))
+ raise CreatorError('Error creating socket on ' + cause, False,
+ errno[0])
+ else:
+ self.__socket = None
+ logger.fatal(BIND10_SOCKCREATOR_BAD_RESPONSE, answer)
+ raise CreatorError('Unknown response ' + str(answer), True)
+ except socket.error as se:
+ self.__socket = None
+ logger.fatal(BIND10_SOCKCREATOR_TRANSPORT_ERROR, str(se))
+ raise CreatorError(str(se), True)
+
+ def __read_all(self, length):
+ """
+ Keeps reading until length data is read or EOF or error happens.
+
+ EOF is considered error as well and throws a CreatorError.
+ """
+ result = b''
+ while len(result) < length:
+ data = self.__socket.recv(length - len(result))
+ if len(data) == 0:
+ self.__socket = None
+ logger.fatal(BIND10_SOCKCREATOR_EOF)
+ raise CreatorError('Unexpected EOF', True)
+ result += data
+ return result
+
+class WrappedSocket:
+ """
+ This class wraps a socket and adds a read_fd method, so it can be used
+ for the Parser class conveniently. It simply copies all its guts into
+ itself and implements the method.
+ """
+ def __init__(self, socket):
+ # Copy whatever can be copied from the socket
+ for name in dir(socket):
+ if name not in ['__class__', '__weakref__']:
+ setattr(self, name, getattr(socket, name))
+ # Keep the socket, so we can prevent it from being garbage-collected
+ # and closed before we are removed ourself
+ self.__orig_socket = socket
+
+ def read_fd(self):
+ """
+ Read the file descriptor from the socket.
+ """
+ return recv_fd(self.fileno())
+
+# FIXME: Any idea how to test this? Starting an external process doesn't sound
+# OK
+class Creator(Parser):
+ """
+ This starts the socket creator and allows asking for the sockets.
+ """
+ def __init__(self, path):
+ (local, remote) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+ # Popen does not like, for some reason, having the same socket for
+ # stdin as well as stdout, so we dup it before passing it there.
+ remote2 = socket.fromfd(remote.fileno(), socket.AF_UNIX,
+ socket.SOCK_STREAM)
+ env = os.environ
+ env['PATH'] = path
+ self.__process = subprocess.Popen(['b10-sockcreator'], env=env,
+ stdin=remote.fileno(),
+ stdout=remote2.fileno())
+ remote.close()
+ remote2.close()
+ Parser.__init__(self, WrappedSocket(local))
+
+ def pid(self):
+ return self.__process.pid
+
+ def kill(self):
+ logger.warn(BIND10_SOCKCREATOR_KILL)
+ if self.__process is not None:
+ self.__process.kill()
+ self.__process = None
diff --git a/src/bin/bind10/tests/Makefile.am b/src/bin/bind10/tests/Makefile.am
index d9e012f..6d758b3 100644
--- a/src/bin/bind10/tests/Makefile.am
+++ b/src/bin/bind10/tests/Makefile.am
@@ -1,7 +1,7 @@
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
#PYTESTS = args_test.py bind10_test.py
# NOTE: this has a generated test found in the builddir
-PYTESTS = bind10_test.py
+PYTESTS = bind10_test.py sockcreator_test.py
# If necessary (rare cases), explicitly specify paths to dynamic libraries
# required by loadable python modules.
diff --git a/src/bin/bind10/tests/sockcreator_test.py.in b/src/bin/bind10/tests/sockcreator_test.py.in
new file mode 100644
index 0000000..53e7035
--- /dev/null
+++ b/src/bin/bind10/tests/sockcreator_test.py.in
@@ -0,0 +1,327 @@
+# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+#
+# 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.
+
+# This test file is generated .py.in -> .py just to be in the build dir,
+# same as the rest of the tests. Saves a lot of stuff in makefile.
+
+"""
+Tests for the bind10.sockcreator module.
+"""
+
+import unittest
+import struct
+import socket
+from isc.net.addr import IPAddr
+import isc.log
+from libutil_io_python import send_fd
+from bind10.sockcreator import Parser, CreatorError, WrappedSocket
+
+class FakeCreator:
+ """
+ Class emulating the socket to the socket creator. It can be given expected
+ data to receive (and check) and responses to give to the Parser class
+ during testing.
+ """
+
+ class InvalidPlan(Exception):
+ """
+ Raised when someone wants to recv when sending is planned or vice
+ versa.
+ """
+ pass
+
+ class InvalidData(Exception):
+ """
+ Raises when the data passed to sendall are not the same as expected.
+ """
+ pass
+
+ def __init__(self, plan):
+ """
+ Create the object. The plan variable contains list of expected actions,
+ in form:
+
+ [('r', 'Data to return from recv'), ('s', 'Data expected on sendall'),
+ , ('d', 'File descriptor number to return from read_sock'), ('e',
+ None), ...]
+
+ It modifies the array as it goes.
+ """
+ self.__plan = plan
+
+ def __get_plan(self, expected):
+ if len(self.__plan) == 0:
+ raise InvalidPlan('Nothing more planned')
+ (kind, data) = self.__plan[0]
+ if kind == 'e':
+ self.__plan.pop(0)
+ raise socket.error('False socket error')
+ if kind != expected:
+ raise InvalidPlan('Planned ' + kind + ', but ' + expected +
+ 'requested')
+ return data
+
+ def recv(self, maxsize):
+ """
+ Emulate recv. Returs maxsize bytes from the current recv plan. If
+ there are data left from previous recv call, it is used first.
+
+ If no recv is planned, raises InvalidPlan.
+ """
+ data = self.__get_plan('r')
+ result, rest = data[:maxsize], data[maxsize:]
+ if len(rest) > 0:
+ self.__plan[0] = ('r', rest)
+ else:
+ self.__plan.pop(0)
+ return result
+
+ def read_fd(self):
+ """
+ Emulate the reading of file descriptor. Returns one from a plan.
+
+ It raises InvalidPlan if no socket is planned now.
+ """
+ fd = self.__get_plan('f')
+ self.__plan.pop(0)
+ return fd
+
+ def sendall(self, data):
+ """
+ Checks that the data passed are correct according to plan. It raises
+ InvalidData if the data differs or InvalidPlan when sendall is not
+ expected.
+ """
+ planned = self.__get_plan('s')
+ dlen = len(data)
+ prefix, rest = planned[:dlen], planned[dlen:]
+ if prefix != data:
+ raise InvalidData('Expected "' + str(prefix)+ '", got "' +
+ str(data) + '"')
+ if len(rest) > 0:
+ self.__plan[0] = ('s', rest)
+ else:
+ self.__plan.pop(0)
+
+ def all_used(self):
+ """
+ Returns if the whole plan was consumed.
+ """
+ return len(self.__plan) == 0
+
+class ParserTests(unittest.TestCase):
+ """
+ Testcases for the Parser class.
+
+ A lot of these test could be done by
+ `with self.assertRaises(CreatorError) as cm`. But some versions of python
+ take the scope wrong and don't work, so we use the primitive way of
+ try-except.
+ """
+ def __terminate(self):
+ creator = FakeCreator([('s', b'T'), ('r', b'')])
+ parser = Parser(creator)
+ self.assertEqual(None, parser.terminate())
+ self.assertTrue(creator.all_used())
+ return parser
+
+ def test_terminate(self):
+ """
+ Test if the command to terminate is correct and it waits for reading the
+ EOF.
+ """
+ self.__terminate()
+
+ def __terminate_raises(self, parser):
+ """
+ Check that terminate() raises a fatal exception.
+ """
+ try:
+ parser.terminate()
+ self.fail("Not raised")
+ except CreatorError as ce:
+ self.assertTrue(ce.fatal)
+ self.assertEqual(None, ce.errno)
+
+ def test_terminate_error1(self):
+ """
+ Test it reports an exception when there's error terminating the creator.
+ This one raises an error when receiving the EOF.
+ """
+ creator = FakeCreator([('s', b'T'), ('e', None)])
+ parser = Parser(creator)
+ self.__terminate_raises(parser)
+
+ def test_terminate_error2(self):
+ """
+ Test it reports an exception when there's error terminating the creator.
+ This one raises an error when sending data.
+ """
+ creator = FakeCreator([('e', None)])
+ parser = Parser(creator)
+ self.__terminate_raises(parser)
+
+ def test_terminate_error3(self):
+ """
+ Test it reports an exception when there's error terminating the creator.
+ This one sends data when it should have terminated.
+ """
+ creator = FakeCreator([('s', b'T'), ('r', b'Extra data')])
+ parser = Parser(creator)
+ self.__terminate_raises(parser)
+
+ def test_terminate_twice(self):
+ """
+ Test we can't terminate twice.
+ """
+ parser = self.__terminate()
+ self.__terminate_raises(parser)
+
+ def test_crash(self):
+ """
+ Tests that the parser correctly raises exception when it crashes
+ unexpectedly.
+ """
+ creator = FakeCreator([('s', b'SU4\0\0\0\0\0\0'), ('r', b'')])
+ parser = Parser(creator)
+ try:
+ parser.get_socket(IPAddr('0.0.0.0'), 0, 'UDP')
+ self.fail("Not raised")
+ except CreatorError as ce:
+ self.assertTrue(creator.all_used())
+ # Is the exception correct?
+ self.assertTrue(ce.fatal)
+ self.assertEqual(None, ce.errno)
+
+ def test_error(self):
+ """
+ Tests that the parser correctly raises non-fatal exception when
+ the socket can not be created.
+ """
+ # We split the int to see if it can cope with data coming in
+ # different packets
+ intpart = struct.pack('@i', 42)
+ creator = FakeCreator([('s', b'SU4\0\0\0\0\0\0'), ('r', b'ES' +
+ intpart[:1]), ('r', intpart[1:])])
+ parser = Parser(creator)
+ try:
+ parser.get_socket(IPAddr('0.0.0.0'), 0, 'UDP')
+ self.fail("Not raised")
+ except CreatorError as ce:
+ self.assertTrue(creator.all_used())
+ # Is the exception correct?
+ self.assertFalse(ce.fatal)
+ self.assertEqual(42, ce.errno)
+
+ def __error(self, plan):
+ creator = FakeCreator(plan)
+ parser = Parser(creator)
+ try:
+ parser.get_socket(IPAddr('0.0.0.0'), 0, socket.SOCK_DGRAM)
+ self.fail("Not raised")
+ except CreatorError as ce:
+ self.assertTrue(creator.all_used())
+ self.assertTrue(ce.fatal)
+
+ def test_error_send(self):
+ self.__error([('e', None)])
+
+ def test_error_recv(self):
+ self.__error([('s', b'SU4\0\0\0\0\0\0'), ('e', None)])
+
+ def test_error_read_fd(self):
+ self.__error([('s', b'SU4\0\0\0\0\0\0'), ('r', b'S'), ('e', None)])
+
+ def __create(self, addr, socktype, encoded):
+ creator = FakeCreator([('s', b'S' + encoded), ('r', b'S'), ('f', 42)])
+ parser = Parser(creator)
+ self.assertEqual(42, parser.get_socket(IPAddr(addr), 42, socktype))
+
+ def test_create1(self):
+ self.__create('192.0.2.0', 'UDP', b'U4\0\x2A\xC0\0\x02\0')
+
+ def test_create2(self):
+ self.__create('2001:db8::', socket.SOCK_STREAM,
+ b'T6\0\x2A\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\0\0')
+
+ def test_create_terminated(self):
+ """
+ Test we can't request sockets after it was terminated.
+ """
+ parser = self.__terminate()
+ try:
+ parser.get_socket(IPAddr('0.0.0.0'), 0, 'UDP')
+ self.fail("Not raised")
+ except CreatorError as ce:
+ self.assertTrue(ce.fatal)
+ self.assertEqual(None, ce.errno)
+
+ def test_invalid_socktype(self):
+ """
+ Test invalid socket type is rejected
+ """
+ self.assertRaises(ValueError, Parser(FakeCreator([])).get_socket,
+ IPAddr('0.0.0.0'), 42, 'RAW')
+
+ def test_invalid_family(self):
+ """
+ Test it rejects invalid address family.
+ """
+ # Note: this produces a bad logger output, since this address
+ # can not be converted to string, so the original message with
+ # placeholders is output. This should not happen in practice, so
+ # it is harmless.
+ addr = IPAddr('0.0.0.0')
+ addr.family = 42
+ self.assertRaises(ValueError, Parser(FakeCreator([])).get_socket,
+ addr, 42, socket.SOCK_DGRAM)
+
+class WrapTests(unittest.TestCase):
+ """
+ Tests for the wrap_socket function.
+ """
+ def test_wrap(self):
+ # We construct two pairs of socket. The receiving side of one pair will
+ # be wrapped. Then we send one of the other pair through this pair and
+ # check the received one can be used as a socket
+
+ # The transport socket
+ (t1, t2) = socket.socketpair()
+ # The payload socket
+ (p1, p2) = socket.socketpair()
+
+ t2 = WrappedSocket(t2)
+
+ # Transfer the descriptor
+ send_fd(t1.fileno(), p1.fileno())
+ p1 = socket.fromfd(t2.read_fd(), socket.AF_UNIX, socket.SOCK_STREAM)
+
+ # Now, pass some data trough the socket
+ p1.send(b'A')
+ data = p2.recv(1)
+ self.assertEqual(b'A', data)
+
+ # Test the wrapping didn't hurt the socket's usual methods
+ t1.send(b'B')
+ data = t2.recv(1)
+ self.assertEqual(b'B', data)
+ t2.send(b'C')
+ data = t1.recv(1)
+ self.assertEqual(b'C', data)
+
+if __name__ == '__main__':
+ isc.log.init("bind10") # FIXME Should this be needed?
+ isc.log.resetUnitTestRootLogger()
+ unittest.main()
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index 824e8a8..8d341cb 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -35,7 +35,6 @@ b10_dhcp6_SOURCES = main.cc
b10_dhcp6_SOURCES += dhcp6.h
b10_dhcp6_LDADD = $(top_builddir)/src/lib/datasrc/libdatasrc.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/util/libutil.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/cc/libcc.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/bin/host/Makefile.am b/src/bin/host/Makefile.am
index a8f96c2..ec34ce7 100644
--- a/src/bin/host/Makefile.am
+++ b/src/bin/host/Makefile.am
@@ -13,7 +13,6 @@ CLEANFILES = *.gcno *.gcda
bin_PROGRAMS = b10-host
b10_host_SOURCES = host.cc
b10_host_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
-b10_host_LDADD += $(top_builddir)/src/lib/util/libutil.la
b10_host_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
man_MANS = b10-host.1
diff --git a/src/bin/zonemgr/zonemgr.py.in b/src/bin/zonemgr/zonemgr.py.in
index 845190b..c6e3163 100755
--- a/src/bin/zonemgr/zonemgr.py.in
+++ b/src/bin/zonemgr/zonemgr.py.in
@@ -38,10 +38,6 @@ from optparse import OptionParser, OptionValueError
from isc.config.ccsession import *
import isc.util.process
-# Initialize logging for called modules.
-# TODO: Log messages properly
-isc.log.init("b10-zonemgr")
-
isc.util.process.rename()
# If B10_FROM_BUILD is set in the environment, we use data files
diff --git a/src/lib/bench/tests/Makefile.am b/src/lib/bench/tests/Makefile.am
index 3f8a678..3ebdf29 100644
--- a/src/lib/bench/tests/Makefile.am
+++ b/src/lib/bench/tests/Makefile.am
@@ -16,7 +16,6 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(top_builddir)/src/lib/bench/libbench.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/util/unittests/libutil_unittests.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
run_unittests_LDADD += $(GTEST_LDADD)
diff --git a/src/lib/cache/tests/Makefile.am b/src/lib/cache/tests/Makefile.am
index a215c56..f9237af 100644
--- a/src/lib/cache/tests/Makefile.am
+++ b/src/lib/cache/tests/Makefile.am
@@ -56,7 +56,6 @@ run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.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/util/unittests/libutil_unittests.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc
index ac85077..6b094ec 100644
--- a/src/lib/config/ccsession.cc
+++ b/src/lib/config/ccsession.cc
@@ -18,15 +18,12 @@
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
-#include <ctype.h>
-#include <algorithm>
-#include <cerrno>
-#include <fstream>
#include <iostream>
-#include <set>
+#include <fstream>
#include <sstream>
-#include <string>
+#include <cerrno>
+#include <set>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
@@ -178,36 +175,6 @@ ConstElementPtr getValueOrDefault(ConstElementPtr config_part,
}
}
-// Prefix name with "b10-".
-//
-// In BIND 10, modules have names taken from the .spec file, which are typically
-// names starting with a capital letter (e.g. "Resolver", "Auth" etc.). The
-// names of the associated binaries are derived from the module names, being
-// prefixed "b10-" and having the first letter of the module name lower-cased
-// (e.g. "b10-resolver", "b10-auth"). (It is a required convention that there
-// be this relationship between the names.)
-//
-// Within the binaries the root loggers are named after the binaries themselves.
-// (The reason for this is that the name of the logger is included in the
-// message logged, so making it clear which message comes from which BIND 10
-// process.) As logging is configured using module names, the configuration code
-// has to match these with the corresponding logger names. This function
-// converts a module name to a root logger name by lowercasing the first letter
-// of the module name and prepending "b10-".
-//
-// \param instring String to convert. (This may be empty, in which case
-// "b10-" will be returned.)
-//
-// \return Converted string.
-std::string
-b10Prefix(const std::string& instring) {
- std::string result = instring;
- if (!result.empty()) {
- result[0] = tolower(result[0]);
- }
- return (std::string("b10-") + result);
-}
-
// Reads a output_option subelement of a logger configuration,
// and sets the values thereing to the given OutputOption struct,
// or defaults values if they are not provided (from config_data).
@@ -248,7 +215,6 @@ readLoggersConf(std::vector<isc::log::LoggerSpecification>& specs,
ConstElementPtr logger,
const ConfigData& config_data)
{
- // Read name, adding prefix as required.
std::string lname = logger->get("name")->stringValue();
ConstElementPtr severity_el = getValueOrDefault(logger,
@@ -281,27 +247,6 @@ readLoggersConf(std::vector<isc::log::LoggerSpecification>& specs,
specs.push_back(logger_spec);
}
-// Copies the map for a logger, changing the name of the logger in the process.
-// This is used because the map being copied is "const", so in order to
-// change the name we need to create a new one.
-//
-// \param cur_logger Logger being copied.
-// \param new_name New value of the "name" element at the top level.
-//
-// \return Pointer to the map with the updated element.
-ConstElementPtr
-copyLogger(ConstElementPtr& cur_logger, const std::string& new_name) {
-
- // Since we'll only be updating one first-level element and subsequent
- // use won't change the contents of the map, a shallow map copy is enough.
- ElementPtr new_logger(Element::createMap());
- new_logger->setValue(cur_logger->mapValue());
- new_logger->set("name", Element::create(new_name));
-
- return (new_logger);
-}
-
-
} // end anonymous namespace
@@ -314,60 +259,38 @@ getRelatedLoggers(ConstElementPtr loggers) {
ElementPtr result = isc::data::Element::createList();
BOOST_FOREACH(ConstElementPtr cur_logger, loggers->listValue()) {
- // Need to add the b10- prefix to names ready from the spec file.
const std::string cur_name = cur_logger->get("name")->stringValue();
- const std::string mod_name = b10Prefix(cur_name);
- if (mod_name == root_name || mod_name.find(root_name + ".") == 0) {
-
- // Note this name so that we don't add a wildcard that matches it.
- our_names.insert(mod_name);
-
- // We want to store the logger with the modified name (i.e. with
- // the b10- prefix). As we are dealing with const loggers, we
- // store a modified copy of the data.
- result->add(copyLogger(cur_logger, mod_name));
- LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS, CONFIG_LOG_EXPLICIT)
- .arg(cur_name);
-
- } else if (!cur_name.empty() && (cur_name[0] != '*')) {
- // Not a wildcard logger and we are ignoring it.
- LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS,
- CONFIG_LOG_IGNORE_EXPLICIT).arg(cur_name);
+ if (cur_name == root_name || cur_name.find(root_name + ".") == 0) {
+ our_names.insert(cur_name);
+ result->add(cur_logger);
}
}
- // Now find the wildcard names (the one that start with "*").
+ // now find the * names
BOOST_FOREACH(ConstElementPtr cur_logger, loggers->listValue()) {
std::string cur_name = cur_logger->get("name")->stringValue();
- // If name is '*', or starts with '*.', replace * with root
- // logger name.
+ // if name is '*', or starts with '*.', replace * with root
+ // logger name
if (cur_name == "*" || cur_name.length() > 1 &&
cur_name[0] == '*' && cur_name[1] == '.') {
- // Substitute the "*" with the root name
- std::string mod_name = cur_name;
- mod_name.replace(0, 1, root_name);
-
- // Now add it to the result list, but only if a logger with
- // that name was not configured explicitly.
- if (our_names.find(mod_name) == our_names.end()) {
-
- // We substitute the name here, but as we are dealing with
- // consts, we need to copy the data.
- result->add(copyLogger(cur_logger, mod_name));
- LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS,
- CONFIG_LOG_WILD_MATCH).arg(cur_name);
-
- } else if (!cur_name.empty() && (cur_name[0] == '*')) {
- // Is a wildcard and we are ignoring it (because the wildcard
- // expands to a specification that we already encountered when
- // processing explicit names).
- LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS,
- CONFIG_LOG_IGNORE_WILD).arg(cur_name);
+ cur_name = root_name + cur_name.substr(1);
+ // now add it to the result list, but only if a logger with
+ // that name was not configured explicitely
+ if (our_names.find(cur_name) == our_names.end()) {
+ // we substitute the name here already, but as
+ // we are dealing with consts, we copy the data
+ ElementPtr new_logger(Element::createMap());
+ // since we'll only be updating one first-level element,
+ // and we return as const again, a shallow map copy is
+ // enough
+ new_logger->setValue(cur_logger->mapValue());
+ new_logger->set("name", Element::create(cur_name));
+ result->add(new_logger);
}
}
}
- return (result);
+ return result;
}
void
@@ -395,7 +318,7 @@ ModuleSpec
ModuleCCSession::readModuleSpecification(const std::string& filename) {
std::ifstream file;
ModuleSpec module_spec;
-
+
// this file should be declared in a @something@ directive
file.open(filename.c_str());
if (!file) {
@@ -462,7 +385,7 @@ ModuleCCSession::ModuleCCSession(
LOG_ERROR(config_logger, CONFIG_MOD_SPEC_REJECT).arg(answer->str());
isc_throw(CCSessionInitError, answer->str());
}
-
+
setLocalConfig(Element::fromJSON("{}"));
// get any stored configuration from the manager
if (config_handler_) {
@@ -588,7 +511,7 @@ int
ModuleCCSession::checkCommand() {
ConstElementPtr cmd, routing, data;
if (session_.group_recvmsg(routing, data, true)) {
-
+
/* ignore result messages (in case we're out of sync, to prevent
* pingpongs */
if (data->getType() != Element::map || data->contains("result")) {
diff --git a/src/lib/config/ccsession.h b/src/lib/config/ccsession.h
index 50bb65c..a39d996 100644
--- a/src/lib/config/ccsession.h
+++ b/src/lib/config/ccsession.h
@@ -377,10 +377,10 @@ default_logconfig_handler(const std::string& module_name,
/// \brief Returns the loggers related to this module
///
/// This function does two things;
-/// - it drops the configuration parts for loggers for other modules.
+/// - it drops the configuration parts for loggers for other modules
/// - it replaces the '*' in the name of the loggers by the name of
/// this module, but *only* if the expanded name is not configured
-/// explicitly.
+/// explicitely
///
/// Examples: if this is the module b10-resolver,
/// For the config names ['*', 'b10-auth']
diff --git a/src/lib/config/config_log.h b/src/lib/config/config_log.h
index 74e6a84..0063855 100644
--- a/src/lib/config/config_log.h
+++ b/src/lib/config/config_log.h
@@ -32,14 +32,6 @@ namespace config {
/// space.
extern isc::log::Logger config_logger; // isc::config::config_logger is the CONFIG logger
-/// \brief Debug Levels
-///
-/// Debug levels used in the configuration library
-enum {
- DBG_CONFIG_PROCESS = 40 // Enumerate configuration elements as they
- // ... are processed.
-};
-
} // namespace config
} // namespace isc
diff --git a/src/lib/config/config_messages.mes b/src/lib/config/config_messages.mes
index c439edd..660ab9a 100644
--- a/src/lib/config/config_messages.mes
+++ b/src/lib/config/config_messages.mes
@@ -37,31 +37,6 @@ manager is appended to the log error. The most likely cause is that
the module is of a different (command specification) version than the
running configuration manager.
-% CONFIG_LOG_EXPLICIT will use logging configuration for explicitly-named logger %1
-This is a debug message. When processing the "loggers" part of the
-configuration file, the configuration library found an entry for the named
-logger that matches the logger specification for the program. The logging
-configuration for the program will be updated with the information.
-
-% CONFIG_LOG_IGNORE_EXPLICIT ignoring logging configuration for explicitly-named logger %1
-This is a debug message. When processing the "loggers" part of the
-configuration file, the configuration library found an entry for the
-named logger. As this does not match the logger specification for the
-program, it has been ignored.
-
-% CONFIG_LOG_IGNORE_WILD ignoring logging configuration for wildcard logger %1
-This is a debug message. When processing the "loggers" part of the
-configuration file, the configuration library found the named wildcard
-entry (one containing the "*" character) that matched a logger already
-matched by an explicitly named entry. The configuration is ignored.
-
-% CONFIG_LOG_WILD_MATCH will use logging configuration for wildcard logger %1
-This is a debug message. When processing the "loggers" part of
-the configuration file, the configuration library found the named
-wildcard entry (one containing the "*" character) that matches a logger
-specification in the program. The logging configuration for the program
-will be updated with the information.
-
% CONFIG_JSON_PARSE JSON parse error in %1: %2
There was an error parsing the JSON file. The given file does not appear
to be in valid JSON format. Please verify that the filename is correct
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index 5ea4f32..283fcc4 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -44,9 +44,7 @@ el(const std::string& str) {
class CCSessionTest : public ::testing::Test {
protected:
- CCSessionTest() : session(el("[]"), el("[]"), el("[]")),
- root_name(isc::log::getRootLoggerName())
- {
+ CCSessionTest() : session(el("[]"), el("[]"), el("[]")) {
// upon creation of a ModuleCCSession, the class
// sends its specification to the config manager.
// it expects an ok answer back, so everytime we
@@ -54,11 +52,8 @@ protected:
// ok answer.
session.getMessages()->add(createAnswer());
}
- ~CCSessionTest() {
- isc::log::setRootLoggerName(root_name);
- }
+ ~CCSessionTest() {}
FakeSession session;
- const std::string root_name;
};
TEST_F(CCSessionTest, createAnswer) {
@@ -657,44 +652,41 @@ void doRelatedLoggersTest(const char* input, const char* expected) {
TEST(LogConfigTest, relatedLoggersTest) {
// make sure logger configs for 'other' programs are ignored,
// and that * is substituted correctly
- // We'll use a root logger name of "b10-test".
- isc::log::setRootLoggerName("b10-test");
-
+ // The default root logger name is "bind10"
doRelatedLoggersTest("[{ \"name\": \"other_module\" }]",
"[]");
doRelatedLoggersTest("[{ \"name\": \"other_module.somelib\" }]",
"[]");
- doRelatedLoggersTest("[{ \"name\": \"test_other\" }]",
+ doRelatedLoggersTest("[{ \"name\": \"bind10_other\" }]",
"[]");
- doRelatedLoggersTest("[{ \"name\": \"test_other.somelib\" }]",
+ doRelatedLoggersTest("[{ \"name\": \"bind10_other.somelib\" }]",
"[]");
doRelatedLoggersTest("[ { \"name\": \"other_module\" },"
- " { \"name\": \"test\" }]",
- "[ { \"name\": \"b10-test\" } ]");
- doRelatedLoggersTest("[ { \"name\": \"test\" }]",
- "[ { \"name\": \"b10-test\" } ]");
- doRelatedLoggersTest("[ { \"name\": \"test.somelib\" }]",
- "[ { \"name\": \"b10-test.somelib\" } ]");
+ " { \"name\": \"bind10\" }]",
+ "[ { \"name\": \"bind10\" } ]");
+ doRelatedLoggersTest("[ { \"name\": \"bind10\" }]",
+ "[ { \"name\": \"bind10\" } ]");
+ doRelatedLoggersTest("[ { \"name\": \"bind10.somelib\" }]",
+ "[ { \"name\": \"bind10.somelib\" } ]");
doRelatedLoggersTest("[ { \"name\": \"other_module.somelib\" },"
- " { \"name\": \"test.somelib\" }]",
- "[ { \"name\": \"b10-test.somelib\" } ]");
+ " { \"name\": \"bind10.somelib\" }]",
+ "[ { \"name\": \"bind10.somelib\" } ]");
doRelatedLoggersTest("[ { \"name\": \"other_module.somelib\" },"
- " { \"name\": \"test\" },"
- " { \"name\": \"test.somelib\" }]",
- "[ { \"name\": \"b10-test\" },"
- " { \"name\": \"b10-test.somelib\" } ]");
+ " { \"name\": \"bind10\" },"
+ " { \"name\": \"bind10.somelib\" }]",
+ "[ { \"name\": \"bind10\" },"
+ " { \"name\": \"bind10.somelib\" } ]");
doRelatedLoggersTest("[ { \"name\": \"*\" }]",
- "[ { \"name\": \"b10-test\" } ]");
+ "[ { \"name\": \"bind10\" } ]");
doRelatedLoggersTest("[ { \"name\": \"*.somelib\" }]",
- "[ { \"name\": \"b10-test.somelib\" } ]");
+ "[ { \"name\": \"bind10.somelib\" } ]");
doRelatedLoggersTest("[ { \"name\": \"*\", \"severity\": \"DEBUG\" },"
- " { \"name\": \"test\", \"severity\": \"WARN\"}]",
- "[ { \"name\": \"b10-test\", \"severity\": \"WARN\"} ]");
+ " { \"name\": \"bind10\", \"severity\": \"WARN\"}]",
+ "[ { \"name\": \"bind10\", \"severity\": \"WARN\"} ]");
doRelatedLoggersTest("[ { \"name\": \"*\", \"severity\": \"DEBUG\" },"
" { \"name\": \"some_module\", \"severity\": \"WARN\"}]",
- "[ { \"name\": \"b10-test\", \"severity\": \"DEBUG\"} ]");
- doRelatedLoggersTest("[ { \"name\": \"b10-test\" }]",
- "[]");
+ "[ { \"name\": \"bind10\", \"severity\": \"DEBUG\"} ]");
+
// make sure 'bad' things like '*foo.x' or '*lib' are ignored
// (cfgmgr should have already caught it in the logconfig plugin
// check, and is responsible for reporting the error)
@@ -704,8 +696,8 @@ TEST(LogConfigTest, relatedLoggersTest) {
"[ ]");
doRelatedLoggersTest("[ { \"name\": \"*foo\" },"
" { \"name\": \"*foo.lib\" },"
- " { \"name\": \"test\" } ]",
- "[ { \"name\": \"b10-test\" } ]");
+ " { \"name\": \"bind10\" } ]",
+ "[ { \"name\": \"bind10\" } ]");
}
}
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index 261baae..e6bff58 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -22,6 +22,8 @@ libdatasrc_la_SOURCES += zone.h
libdatasrc_la_SOURCES += result.h
libdatasrc_la_SOURCES += logger.h logger.cc
libdatasrc_la_SOURCES += client.h
+libdatasrc_la_SOURCES += database.h database.cc
+libdatasrc_la_SOURCES += sqlite3_connection.h sqlite3_connection.cc
nodist_libdatasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
libdatasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/lib/datasrc/client.h b/src/lib/datasrc/client.h
index a830f00..9fe6519 100644
--- a/src/lib/datasrc/client.h
+++ b/src/lib/datasrc/client.h
@@ -15,6 +15,8 @@
#ifndef __DATA_SOURCE_CLIENT_H
#define __DATA_SOURCE_CLIENT_H 1
+#include <boost/noncopyable.hpp>
+
#include <datasrc/zone.h>
namespace isc {
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
new file mode 100644
index 0000000..5fe9f7b
--- /dev/null
+++ b/src/lib/datasrc/database.cc
@@ -0,0 +1,85 @@
+// 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 <datasrc/database.h>
+
+#include <exceptions/exceptions.h>
+#include <dns/name.h>
+
+using isc::dns::Name;
+
+namespace isc {
+namespace datasrc {
+
+DatabaseClient::DatabaseClient(std::auto_ptr<DatabaseConnection> connection) :
+ connection_(connection)
+{
+ if (connection_.get() == NULL) {
+ isc_throw(isc::InvalidParameter,
+ "No connection provided to DatabaseClient");
+ }
+}
+
+DataSourceClient::FindResult
+DatabaseClient::findZone(const Name& name) const {
+ std::pair<bool, int> zone(connection_->getZone(name));
+ // Try exact first
+ if (zone.first) {
+ return (FindResult(result::SUCCESS,
+ ZoneFinderPtr(new Finder(*connection_,
+ zone.second))));
+ }
+ // Than super domains
+ // Start from 1, as 0 is covered above
+ for (size_t i(1); i < name.getLabelCount(); ++i) {
+ zone = connection_->getZone(name.split(i));
+ if (zone.first) {
+ return (FindResult(result::PARTIALMATCH,
+ ZoneFinderPtr(new Finder(*connection_,
+ zone.second))));
+ }
+ }
+ // No, really nothing
+ return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+}
+
+DatabaseClient::Finder::Finder(DatabaseConnection& connection, int zone_id) :
+ connection_(connection),
+ zone_id_(zone_id)
+{ }
+
+ZoneFinder::FindResult
+DatabaseClient::Finder::find(const isc::dns::Name&,
+ const isc::dns::RRType&,
+ isc::dns::RRsetList*,
+ const FindOptions) const
+{
+ // TODO Implement
+ return (FindResult(SUCCESS, isc::dns::ConstRRsetPtr()));
+}
+
+Name
+DatabaseClient::Finder::getOrigin() const {
+ // TODO Implement
+ return (Name("."));
+}
+
+isc::dns::RRClass
+DatabaseClient::Finder::getClass() const {
+ // TODO Implement
+ return isc::dns::RRClass::IN();
+}
+
+}
+}
diff --git a/src/lib/datasrc/database.h b/src/lib/datasrc/database.h
new file mode 100644
index 0000000..5693479
--- /dev/null
+++ b/src/lib/datasrc/database.h
@@ -0,0 +1,192 @@
+// 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 __DATABASE_DATASRC_H
+#define __DATABASE_DATASRC_H
+
+#include <datasrc/client.h>
+
+namespace isc {
+namespace datasrc {
+
+/**
+ * \brief Abstract connection to database with DNS data
+ *
+ * This class is defines interface to databases. Each supported database
+ * will provide methods for accessing the data stored there in a generic
+ * manner. The methods are meant to be low-level, without much or any knowledge
+ * about DNS and should be possible to translate directly to queries.
+ *
+ * On the other hand, how the communication with database is done and in what
+ * schema (in case of relational/SQL database) is up to the concrete classes.
+ *
+ * This class is non-copyable, as copying connections to database makes little
+ * sense and will not be needed.
+ *
+ * \todo Is it true this does not need to be copied? For example the zone
+ * iterator might need it's own copy. But a virtual clone() method might
+ * be better for that than copy constructor.
+ *
+ * \note The same application may create multiple connections to the same
+ * database. If the database allows having multiple open queries at one
+ * connection, the connection class may share it.
+ */
+class DatabaseConnection : boost::noncopyable {
+public:
+ /**
+ * \brief Destructor
+ *
+ * It is empty, but needs a virtual one, since we will use the derived
+ * classes in polymorphic way.
+ */
+ virtual ~ DatabaseConnection() { }
+ /**
+ * \brief Retrieve a zone identifier
+ *
+ * This method looks up a zone for the given name in the database. It
+ * should match only exact zone name (eg. name is equal to the zone's
+ * apex), as the DatabaseClient will loop trough the labels itself and
+ * find the most suitable zone.
+ *
+ * It is not specified if and what implementation of this method may throw,
+ * so code should expect anything.
+ *
+ * \param name The name of the zone's apex to be looked up.
+ * \return The first part of the result indicates if a matching zone
+ * was found. In case it was, the second part is internal zone ID.
+ * This one will be passed to methods finding data in the zone.
+ * It is not required to keep them, in which case whatever might
+ * be returned - the ID is only passed back to the connection as
+ * an opaque handle.
+ */
+ virtual std::pair<bool, int> getZone(const isc::dns::Name& name) const = 0;
+};
+
+/**
+ * \brief Concrete data source client oriented at database backends.
+ *
+ * This class (together with corresponding versions of ZoneFinder,
+ * ZoneIterator, etc.) translates high-level data source queries to
+ * low-level calls on DatabaseConnection. It calls multiple queries
+ * if necessary and validates data from the database, allowing the
+ * DatabaseConnection to be just simple translation to SQL/other
+ * queries to database.
+ *
+ * While it is possible to subclass it for specific database in case
+ * of special needs, it is not expected to be needed. This should just
+ * work as it is with whatever DatabaseConnection.
+ */
+class DatabaseClient : public DataSourceClient {
+public:
+ /**
+ * \brief Constructor
+ *
+ * It initializes the client with a connection.
+ *
+ * It throws isc::InvalidParameter if connection is NULL. It might throw
+ * standard allocation exception as well, but doesn't throw anything else.
+ *
+ * \note Some objects returned from methods of this class (like ZoneFinder)
+ * hold references to the connection. As the lifetime of the connection
+ * is bound to this object, the returned objects must not be used after
+ * descruction of the DatabaseClient.
+ *
+ * \todo Should we use shared_ptr instead? On one side, we would get rid of
+ * the restriction and maybe could easy up some shutdown scenarios with
+ * multi-threaded applications, on the other hand it is more expensive
+ * and looks generally unneeded.
+ *
+ * \param connection The connection to use to get data. As the parameter
+ * suggests, the client takes ownership of the connection and will
+ * delete it when itself deleted.
+ */
+ DatabaseClient(std::auto_ptr<DatabaseConnection> connection);
+ /**
+ * \brief Corresponding ZoneFinder implementation
+ *
+ * The zone finder implementation for database data sources. Similarly
+ * to the DatabaseClient, it translates the queries to methods of the
+ * connection.
+ *
+ * Application should not come directly in contact with this class
+ * (it should handle it trough generic ZoneFinder pointer), therefore
+ * it could be completely hidden in the .cc file. But it is provided
+ * to allow testing and for rare cases when a database needs slightly
+ * different handling, so it can be subclassed.
+ *
+ * Methods directly corresponds to the ones in ZoneFinder.
+ */
+ class Finder : public ZoneFinder {
+ public:
+ /**
+ * \brief Constructor
+ *
+ * \param connection The connection (shared with DatabaseClient) to
+ * be used for queries (the one asked for ID before).
+ * \param zone_id The zone ID which was returned from
+ * DatabaseConnection::getZone and which will be passed to further
+ * calls to the connection.
+ */
+ Finder(DatabaseConnection& connection, int zone_id);
+ virtual isc::dns::Name getOrigin() const;
+ virtual isc::dns::RRClass getClass() const;
+ virtual FindResult find(const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ isc::dns::RRsetList* target = NULL,
+ const FindOptions options = FIND_DEFAULT)
+ const;
+ /**
+ * \brief The zone ID
+ *
+ * This function provides the stored zone ID as passed to the
+ * constructor. This is meant for testing purposes and normal
+ * applications shouldn't need it.
+ */
+ int zone_id() const { return (zone_id_); }
+ /**
+ * \brief The database connection.
+ *
+ * This function provides the database connection stored inside as
+ * passed to the constructor. This is meant for testing purposes and
+ * normal applications shouldn't need it.
+ */
+ const DatabaseConnection& connection() const {
+ return (connection_);
+ }
+ private:
+ DatabaseConnection& connection_;
+ const int zone_id_;
+ };
+ /**
+ * \brief Find a zone in the database
+ *
+ * This queries connection's getZone to find the best matching zone.
+ * It will propagate whatever exceptions are thrown from that method
+ * (which is not restricted in any way).
+ *
+ * \param name Name of the zone or data contained there.
+ * \return Result containing the code and instance of Finder, if anything
+ * is found. Applications should not rely on the specific class being
+ * returned, though.
+ */
+ virtual FindResult findZone(const isc::dns::Name& name) const;
+private:
+ /// \brief Our connection.
+ const std::auto_ptr<DatabaseConnection> connection_;
+};
+
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index 3dc69e0..3fbb24d 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -400,12 +400,22 @@ enough information for it. The code is 1 for error, 2 for not implemented.
% DATASRC_SQLITE_CLOSE closing SQLite database
Debug information. The SQLite data source is closing the database file.
+
+% DATASRC_SQLITE_CONNOPEN Opening sqlite database file '%1'
+The database file is being opened so it can start providing data.
+
+% DATASRC_SQLITE_CONNCLOSE Closing sqlite database
+The database file is no longer needed and is being closed.
+
% DATASRC_SQLITE_CREATE SQLite data source created
Debug information. An instance of SQLite data source is being created.
% DATASRC_SQLITE_DESTROY SQLite data source destroyed
Debug information. An instance of SQLite data source is being destroyed.
+% DATASRC_SQLITE_DROPCONN SQLite3Connection is being deinitialized
+The object around a database connection is being destroyed.
+
% DATASRC_SQLITE_ENCLOSURE looking for zone containing '%1'
Debug information. The SQLite data source is trying to identify which zone
should hold this domain.
@@ -458,6 +468,9 @@ source.
The SQLite data source was asked to provide a NSEC3 record for given zone.
But it doesn't contain that zone.
+% DATASRC_SQLITE_NEWCONN SQLite3Connection is being initialized
+A wrapper object to hold database connection is being initialized.
+
% DATASRC_SQLITE_OPEN opening SQLite database '%1'
Debug information. The SQLite data source is loading an SQLite database in
the provided file.
@@ -496,4 +509,3 @@ data source.
% DATASRC_UNEXPECTED_QUERY_STATE unexpected query state
This indicates a programming error. An internal task of unknown type was
generated.
-
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 3d24ce0..26223da 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -606,12 +606,12 @@ InMemoryZoneFinder::~InMemoryZoneFinder() {
delete impl_;
}
-const Name&
+Name
InMemoryZoneFinder::getOrigin() const {
return (impl_->origin_);
}
-const RRClass&
+RRClass
InMemoryZoneFinder::getClass() const {
return (impl_->zone_class_);
}
diff --git a/src/lib/datasrc/memory_datasrc.h b/src/lib/datasrc/memory_datasrc.h
index 9bed960..9707797 100644
--- a/src/lib/datasrc/memory_datasrc.h
+++ b/src/lib/datasrc/memory_datasrc.h
@@ -58,10 +58,10 @@ public:
//@}
/// \brief Returns the origin of the zone.
- virtual const isc::dns::Name& getOrigin() const;
+ virtual isc::dns::Name getOrigin() const;
/// \brief Returns the class of the zone.
- virtual const isc::dns::RRClass& getClass() const;
+ virtual isc::dns::RRClass getClass() const;
/// \brief Looks up an RRset in the zone.
///
diff --git a/src/lib/datasrc/sqlite3_connection.cc b/src/lib/datasrc/sqlite3_connection.cc
new file mode 100644
index 0000000..e850db4
--- /dev/null
+++ b/src/lib/datasrc/sqlite3_connection.cc
@@ -0,0 +1,322 @@
+// 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 <sqlite3.h>
+
+#include <datasrc/sqlite3_connection.h>
+#include <datasrc/logger.h>
+#include <datasrc/data_source.h>
+
+namespace isc {
+namespace datasrc {
+
+struct SQLite3Parameters {
+ SQLite3Parameters() :
+ db_(NULL), version_(-1),
+ q_zone_(NULL) /*, q_record_(NULL), q_addrs_(NULL), q_referral_(NULL),
+ q_any_(NULL), q_count_(NULL), q_previous_(NULL), q_nsec3_(NULL),
+ q_prevnsec3_(NULL) */
+ {}
+ sqlite3* db_;
+ int version_;
+ sqlite3_stmt* q_zone_;
+ /*
+ TODO: Yet unneeded statements
+ sqlite3_stmt* q_record_;
+ sqlite3_stmt* q_addrs_;
+ sqlite3_stmt* q_referral_;
+ sqlite3_stmt* q_any_;
+ sqlite3_stmt* q_count_;
+ sqlite3_stmt* q_previous_;
+ sqlite3_stmt* q_nsec3_;
+ sqlite3_stmt* q_prevnsec3_;
+ */
+};
+
+SQLite3Connection::SQLite3Connection(const isc::data::ConstElementPtr&
+ config,
+ const isc::dns::RRClass& rrclass) :
+ dbparameters_(new SQLite3Parameters),
+ class_(rrclass.toText())
+{
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_NEWCONN);
+
+ if (config && config->contains("database_file")) {
+ open(config->get("database_file")->stringValue());
+ } else {
+ isc_throw(DataSourceError, "No SQLite database file specified");
+ }
+}
+
+namespace {
+
+// This is a helper class to initialize a Sqlite3 DB safely. An object of
+// this class encapsulates all temporary resources that are necessary for
+// the initialization, and release them in the destructor. Once everything
+// is properly initialized, the move() method moves the allocated resources
+// to the main object in an exception free manner. This way, the main code
+// for the initialization can be exception safe, and can provide the strong
+// exception guarantee.
+class Initializer {
+public:
+ ~Initializer() {
+ if (params_.q_zone_ != NULL) {
+ sqlite3_finalize(params_.q_zone_);
+ }
+ /*
+ if (params_.q_record_ != NULL) {
+ sqlite3_finalize(params_.q_record_);
+ }
+ if (params_.q_addrs_ != NULL) {
+ sqlite3_finalize(params_.q_addrs_);
+ }
+ if (params_.q_referral_ != NULL) {
+ sqlite3_finalize(params_.q_referral_);
+ }
+ if (params_.q_any_ != NULL) {
+ sqlite3_finalize(params_.q_any_);
+ }
+ if (params_.q_count_ != NULL) {
+ sqlite3_finalize(params_.q_count_);
+ }
+ if (params_.q_previous_ != NULL) {
+ sqlite3_finalize(params_.q_previous_);
+ }
+ if (params_.q_nsec3_ != NULL) {
+ sqlite3_finalize(params_.q_nsec3_);
+ }
+ if (params_.q_prevnsec3_ != NULL) {
+ sqlite3_finalize(params_.q_prevnsec3_);
+ }
+ */
+ if (params_.db_ != NULL) {
+ sqlite3_close(params_.db_);
+ }
+ }
+ void move(SQLite3Parameters* dst) {
+ *dst = params_;
+ params_ = SQLite3Parameters(); // clear everything
+ }
+ SQLite3Parameters params_;
+};
+
+const char* const SCHEMA_LIST[] = {
+ "CREATE TABLE schema_version (version INTEGER NOT NULL)",
+ "INSERT INTO schema_version VALUES (1)",
+ "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
+ "name STRING NOT NULL COLLATE NOCASE, "
+ "rdclass STRING NOT NULL COLLATE NOCASE DEFAULT 'IN', "
+ "dnssec BOOLEAN NOT NULL DEFAULT 0)",
+ "CREATE INDEX zones_byname ON zones (name)",
+ "CREATE TABLE records (id INTEGER PRIMARY KEY, "
+ "zone_id INTEGER NOT NULL, name STRING NOT NULL COLLATE NOCASE, "
+ "rname STRING NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
+ "rdtype STRING NOT NULL COLLATE NOCASE, sigtype STRING COLLATE NOCASE, "
+ "rdata STRING NOT NULL)",
+ "CREATE INDEX records_byname ON records (name)",
+ "CREATE INDEX records_byrname ON records (rname)",
+ "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
+ "hash STRING NOT NULL COLLATE NOCASE, "
+ "owner STRING NOT NULL COLLATE NOCASE, "
+ "ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
+ "rdata STRING NOT NULL)",
+ "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
+ NULL
+};
+
+const char* const q_zone_str = "SELECT id FROM zones WHERE name=?1 AND rdclass = ?2";
+
+/* TODO: Prune the statements, not everything will be needed maybe?
+const char* const q_record_str = "SELECT rdtype, ttl, sigtype, rdata "
+ "FROM records WHERE zone_id=?1 AND name=?2 AND "
+ "((rdtype=?3 OR sigtype=?3) OR "
+ "(rdtype='CNAME' OR sigtype='CNAME') OR "
+ "(rdtype='NS' OR sigtype='NS'))";
+
+const char* const q_addrs_str = "SELECT rdtype, ttl, sigtype, rdata "
+ "FROM records WHERE zone_id=?1 AND name=?2 AND "
+ "(rdtype='A' OR sigtype='A' OR rdtype='AAAA' OR sigtype='AAAA')";
+
+const char* const q_referral_str = "SELECT rdtype, ttl, sigtype, rdata FROM "
+ "records WHERE zone_id=?1 AND name=?2 AND"
+ "(rdtype='NS' OR sigtype='NS' OR rdtype='DS' OR sigtype='DS' OR "
+ "rdtype='DNAME' OR sigtype='DNAME')";
+
+const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
+ "FROM records WHERE zone_id=?1 AND name=?2";
+
+const char* const q_count_str = "SELECT COUNT(*) FROM records "
+ "WHERE zone_id=?1 AND rname LIKE (?2 || '%');";
+
+const char* const q_previous_str = "SELECT name FROM records "
+ "WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
+ "rname < $2 ORDER BY rname DESC LIMIT 1";
+
+const char* const q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
+ "WHERE zone_id = ?1 AND hash = $2";
+
+const char* const q_prevnsec3_str = "SELECT hash FROM nsec3 "
+ "WHERE zone_id = ?1 AND hash <= $2 ORDER BY hash DESC LIMIT 1";
+ */
+
+sqlite3_stmt*
+prepare(sqlite3* const db, const char* const statement) {
+ sqlite3_stmt* prepared = NULL;
+ if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
+ isc_throw(SQLite3Error, "Could not prepare SQLite statement: " <<
+ statement);
+ }
+ return (prepared);
+}
+
+void
+checkAndSetupSchema(Initializer* initializer) {
+ sqlite3* const db = initializer->params_.db_;
+
+ sqlite3_stmt* prepared = NULL;
+ if (sqlite3_prepare_v2(db, "SELECT version FROM schema_version", -1,
+ &prepared, NULL) == SQLITE_OK &&
+ sqlite3_step(prepared) == SQLITE_ROW) {
+ initializer->params_.version_ = sqlite3_column_int(prepared, 0);
+ sqlite3_finalize(prepared);
+ } else {
+ logger.info(DATASRC_SQLITE_SETUP);
+ if (prepared != NULL) {
+ sqlite3_finalize(prepared);
+ }
+ for (int i = 0; SCHEMA_LIST[i] != NULL; ++i) {
+ if (sqlite3_exec(db, SCHEMA_LIST[i], NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ isc_throw(SQLite3Error,
+ "Failed to set up schema " << SCHEMA_LIST[i]);
+ }
+ }
+ }
+
+ initializer->params_.q_zone_ = prepare(db, q_zone_str);
+ /* TODO: Yet unneeded statements
+ initializer->params_.q_record_ = prepare(db, q_record_str);
+ initializer->params_.q_addrs_ = prepare(db, q_addrs_str);
+ initializer->params_.q_referral_ = prepare(db, q_referral_str);
+ initializer->params_.q_any_ = prepare(db, q_any_str);
+ initializer->params_.q_count_ = prepare(db, q_count_str);
+ initializer->params_.q_previous_ = prepare(db, q_previous_str);
+ initializer->params_.q_nsec3_ = prepare(db, q_nsec3_str);
+ initializer->params_.q_prevnsec3_ = prepare(db, q_prevnsec3_str);
+ */
+}
+
+}
+
+void
+SQLite3Connection::open(const std::string& name) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNOPEN).arg(name);
+ if (dbparameters_->db_ != NULL) {
+ // There shouldn't be a way to trigger this anyway
+ isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
+ }
+
+ Initializer initializer;
+
+ if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) {
+ isc_throw(SQLite3Error, "Cannot open SQLite database file: " << name);
+ }
+
+ checkAndSetupSchema(&initializer);
+ initializer.move(dbparameters_);
+}
+
+SQLite3Connection::~ SQLite3Connection() {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DROPCONN);
+ if (dbparameters_->db_ != NULL) {
+ close();
+ }
+ delete dbparameters_;
+}
+
+void
+SQLite3Connection::close(void) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNCLOSE);
+ if (dbparameters_->db_ == NULL) {
+ isc_throw(DataSourceError,
+ "SQLite data source is being closed before open");
+ }
+
+ // XXX: sqlite3_finalize() could fail. What should we do in that case?
+ sqlite3_finalize(dbparameters_->q_zone_);
+ dbparameters_->q_zone_ = NULL;
+
+ /* TODO: Once they are needed or not, uncomment or drop
+ sqlite3_finalize(dbparameters->q_record_);
+ dbparameters->q_record_ = NULL;
+
+ sqlite3_finalize(dbparameters->q_addrs_);
+ dbparameters->q_addrs_ = NULL;
+
+ sqlite3_finalize(dbparameters->q_referral_);
+ dbparameters->q_referral_ = NULL;
+
+ sqlite3_finalize(dbparameters->q_any_);
+ dbparameters->q_any_ = NULL;
+
+ sqlite3_finalize(dbparameters->q_count_);
+ dbparameters->q_count_ = NULL;
+
+ sqlite3_finalize(dbparameters->q_previous_);
+ dbparameters->q_previous_ = NULL;
+
+ sqlite3_finalize(dbparameters->q_prevnsec3_);
+ dbparameters->q_prevnsec3_ = NULL;
+
+ sqlite3_finalize(dbparameters->q_nsec3_);
+ dbparameters->q_nsec3_ = NULL;
+ */
+
+ sqlite3_close(dbparameters_->db_);
+ dbparameters_->db_ = NULL;
+}
+
+std::pair<bool, int>
+SQLite3Connection::getZone(const isc::dns::Name& name) const {
+ int rc;
+
+ sqlite3_reset(dbparameters_->q_zone_);
+ rc = sqlite3_bind_text(dbparameters_->q_zone_, 1, name.toText().c_str(),
+ -1, SQLITE_STATIC);
+ if (rc != SQLITE_OK) {
+ isc_throw(SQLite3Error, "Could not bind " << name <<
+ " to SQL statement (zone)");
+ }
+ rc = sqlite3_bind_text(dbparameters_->q_zone_, 2, class_.c_str(), -1,
+ SQLITE_STATIC);
+ if (rc != SQLITE_OK) {
+ isc_throw(SQLite3Error, "Could not bind " << class_ <<
+ " to SQL statement (zone)");
+ }
+
+ rc = sqlite3_step(dbparameters_->q_zone_);
+ std::pair<bool, int> result;
+ if (rc == SQLITE_ROW) {
+ result = std::pair<bool, int>(true,
+ sqlite3_column_int(dbparameters_->
+ q_zone_, 0));
+ } else {
+ result = std::pair<bool, int>(false, 0);
+ }
+ sqlite3_reset(dbparameters_->q_zone_);
+ return (result);
+}
+
+}
+}
diff --git a/src/lib/datasrc/sqlite3_connection.h b/src/lib/datasrc/sqlite3_connection.h
new file mode 100644
index 0000000..266dd05
--- /dev/null
+++ b/src/lib/datasrc/sqlite3_connection.h
@@ -0,0 +1,111 @@
+// 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 __DATASRC_SQLITE3_CONNECTION_H
+#define __DATASRC_SQLITE3_CONNECTION_H
+
+#include <datasrc/database.h>
+
+#include <exceptions/exceptions.h>
+#include <cc/data.h>
+
+#include <string>
+
+namespace isc {
+namespace dns {
+class RRClass;
+}
+
+namespace datasrc {
+
+/**
+ * \brief Low-level database error
+ *
+ * This exception is thrown when the SQLite library complains about something.
+ * It might mean corrupt database file, invalid request or that something is
+ * rotten in the library.
+ */
+class SQLite3Error : public Exception {
+public:
+ SQLite3Error(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+struct SQLite3Parameters;
+
+/**
+ * \brief Concrete implementation of DatabaseConnection for SQLite3 databases
+ *
+ * This opens one database file with our schema and serves data from there.
+ * According to the design, it doesn't interpret the data in any way, it just
+ * provides unified access to the DB.
+ */
+class SQLite3Connection : public DatabaseConnection {
+public:
+ /**
+ * \brief Constructor
+ *
+ * This opens the database and becomes ready to serve data from there.
+ *
+ * This might throw SQLite3Error if the given database file doesn't work
+ * (it is broken, doesn't exist and can't be created, etc). It might throw
+ * DataSourceError if the provided config is invalid (it is missing the
+ * database_file element).
+ *
+ * \param config The part of config describing which database file should
+ * be used.
+ * \param rrclass Which class of data it should serve (while the database
+ * can contain multiple classes of data, single connection can provide
+ * only one class).
+ * \todo Should we pass the database filename instead of the config? It
+ * might be cleaner if this class doesn't know anything about configs.
+ */
+ SQLite3Connection(const isc::data::ConstElementPtr& config,
+ const isc::dns::RRClass& rrclass);
+ /**
+ * \brief Destructor
+ *
+ * Closes the database.
+ */
+ ~ SQLite3Connection();
+ /**
+ * \brief Look up a zone
+ *
+ * This implements the getZone from DatabaseConnection and looks up a zone
+ * in the data. It looks for a zone with the exact given origin and class
+ * passed to the constructor.
+ *
+ * It may throw SQLite3Error if something about the database is broken.
+ *
+ * \param name The name of zone to look up
+ * \return The pair contains if the lookup was successful in the first
+ * element and the zone id in the second if it was.
+ */
+ virtual std::pair<bool, int> getZone(const isc::dns::Name& name) const;
+private:
+ /// \brief Private database data
+ SQLite3Parameters* dbparameters_;
+ /// \brief The class for which the queries are done
+ const std::string class_;
+ /// \brief Opens the database
+ void open(const std::string& filename);
+ /// \brief Closes the database
+ void close();
+};
+
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index ffedb75..c2e2b5c 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -28,6 +28,8 @@ run_unittests_SOURCES += rbtree_unittest.cc
run_unittests_SOURCES += zonetable_unittest.cc
run_unittests_SOURCES += memory_datasrc_unittest.cc
run_unittests_SOURCES += logger_unittest.cc
+run_unittests_SOURCES += database_unittest.cc
+run_unittests_SOURCES += sqlite3_connection_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
@@ -36,7 +38,6 @@ run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(SQLITE_LIBS)
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/util/libutil.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/cc/libcc.la
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
new file mode 100644
index 0000000..b60d5c0
--- /dev/null
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -0,0 +1,99 @@
+// 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 <gtest/gtest.h>
+
+#include <dns/name.h>
+#include <exceptions/exceptions.h>
+
+#include <datasrc/database.h>
+
+using namespace isc::datasrc;
+using namespace std;
+using namespace boost;
+using isc::dns::Name;
+
+namespace {
+
+/*
+ * A virtual database connection that pretends it contains single zone --
+ * example.org.
+ */
+class MockConnection : public DatabaseConnection {
+public:
+ virtual std::pair<bool, int> getZone(const Name& name) const {
+ if (name == Name("example.org")) {
+ return (std::pair<bool, int>(true, 42));
+ } else {
+ return (std::pair<bool, int>(false, 0));
+ }
+ }
+};
+
+class DatabaseClientTest : public ::testing::Test {
+public:
+ DatabaseClientTest() {
+ createClient();
+ }
+ /*
+ * We initialize the client from a function, so we can call it multiple
+ * times per test.
+ */
+ void createClient() {
+ current_connection_ = new MockConnection();
+ client_.reset(new DatabaseClient(auto_ptr<DatabaseConnection>(
+ current_connection_)));
+ }
+ // Will be deleted by client_, just keep the current value for comparison.
+ MockConnection* current_connection_;
+ auto_ptr<DatabaseClient> client_;
+ /**
+ * Check the zone finder is a valid one and references the zone ID and
+ * connection available here.
+ */
+ void checkZoneFinder(const DataSourceClient::FindResult& zone) {
+ ASSERT_NE(ZoneFinderPtr(), zone.zone_finder) << "No zone finder";
+ shared_ptr<DatabaseClient::Finder> finder(
+ dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
+ ASSERT_NE(shared_ptr<DatabaseClient::Finder>(), finder) <<
+ "Wrong type of finder";
+ EXPECT_EQ(42, finder->zone_id());
+ EXPECT_EQ(current_connection_, &finder->connection());
+ }
+};
+
+TEST_F(DatabaseClientTest, zoneNotFound) {
+ DataSourceClient::FindResult zone(client_->findZone(Name("example.com")));
+ EXPECT_EQ(result::NOTFOUND, zone.code);
+}
+
+TEST_F(DatabaseClientTest, exactZone) {
+ DataSourceClient::FindResult zone(client_->findZone(Name("example.org")));
+ EXPECT_EQ(result::SUCCESS, zone.code);
+ checkZoneFinder(zone);
+}
+
+TEST_F(DatabaseClientTest, superZone) {
+ DataSourceClient::FindResult zone(client_->findZone(Name(
+ "sub.example.org")));
+ EXPECT_EQ(result::PARTIALMATCH, zone.code);
+ checkZoneFinder(zone);
+}
+
+TEST_F(DatabaseClientTest, noConnException) {
+ EXPECT_THROW(DatabaseClient(auto_ptr<DatabaseConnection>()),
+ isc::InvalidParameter);
+}
+
+}
diff --git a/src/lib/datasrc/tests/sqlite3_connection_unittest.cc b/src/lib/datasrc/tests/sqlite3_connection_unittest.cc
new file mode 100644
index 0000000..3065dfe
--- /dev/null
+++ b/src/lib/datasrc/tests/sqlite3_connection_unittest.cc
@@ -0,0 +1,116 @@
+// 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 <datasrc/sqlite3_connection.h>
+#include <datasrc/data_source.h>
+
+#include <dns/rrclass.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::datasrc;
+using isc::data::ConstElementPtr;
+using isc::data::Element;
+using isc::dns::RRClass;
+using isc::dns::Name;
+
+namespace {
+// Some test data
+ConstElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
+ "{ \"database_file\": \"" TEST_DATA_DIR "/test.sqlite3\"}");
+ConstElementPtr SQLITE_DBFILE_EXAMPLE2 = Element::fromJSON(
+ "{ \"database_file\": \"" TEST_DATA_DIR "/example2.com.sqlite3\"}");
+ConstElementPtr SQLITE_DBFILE_EXAMPLE_ROOT = Element::fromJSON(
+ "{ \"database_file\": \"" TEST_DATA_DIR "/test-root.sqlite3\"}");
+ConstElementPtr SQLITE_DBFILE_BROKENDB = Element::fromJSON(
+ "{ \"database_file\": \"" TEST_DATA_DIR "/brokendb.sqlite3\"}");
+ConstElementPtr SQLITE_DBFILE_MEMORY = Element::fromJSON(
+ "{ \"database_file\": \":memory:\"}");
+
+// The following file must be non existent and must be non"creatable";
+// the sqlite3 library will try to create a new DB file if it doesn't exist,
+// so to test a failure case the create operation should also fail.
+// The "nodir", a non existent directory, is inserted for this purpose.
+ConstElementPtr SQLITE_DBFILE_NOTEXIST = Element::fromJSON(
+ "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}");
+
+// Opening works (the content is tested in different tests)
+TEST(SQLite3Open, common) {
+ EXPECT_NO_THROW(SQLite3Connection conn(SQLITE_DBFILE_EXAMPLE,
+ RRClass::IN()));
+}
+
+// Missing config
+TEST(SQLite3Open, noConfig) {
+ EXPECT_THROW(SQLite3Connection conn(Element::fromJSON("{}"),
+ RRClass::IN()),
+ DataSourceError);
+}
+
+// The file can't be opened
+TEST(SQLite3Open, notExist) {
+ EXPECT_THROW(SQLite3Connection conn(SQLITE_DBFILE_NOTEXIST,
+ RRClass::IN()), SQLite3Error);
+}
+
+// It rejects broken DB
+TEST(SQLite3Open, brokenDB) {
+ EXPECT_THROW(SQLite3Connection conn(SQLITE_DBFILE_BROKENDB,
+ RRClass::IN()), SQLite3Error);
+}
+
+// Test we can create the schema on the fly
+TEST(SQLite3Open, memoryDB) {
+ EXPECT_NO_THROW(SQLite3Connection conn(SQLITE_DBFILE_MEMORY,
+ RRClass::IN()));
+}
+
+// Test fixture for querying the connection
+class SQLite3Conn : public ::testing::Test {
+public:
+ SQLite3Conn() {
+ initConn(SQLITE_DBFILE_EXAMPLE, RRClass::IN());
+ }
+ // So it can be re-created with different data
+ void initConn(const ConstElementPtr& config, const RRClass& rrclass) {
+ conn.reset(new SQLite3Connection(config, rrclass));
+ }
+ // The tested connection
+ std::auto_ptr<SQLite3Connection> conn;
+};
+
+// This zone exists in the data, so it should be found
+TEST_F(SQLite3Conn, getZone) {
+ std::pair<bool, int> result(conn->getZone(Name("example.com")));
+ EXPECT_TRUE(result.first);
+ EXPECT_EQ(1, result.second);
+}
+
+// But it should find only the zone, nothing below it
+TEST_F(SQLite3Conn, subZone) {
+ EXPECT_FALSE(conn->getZone(Name("sub.example.com")).first);
+}
+
+// This zone is not there at all
+TEST_F(SQLite3Conn, noZone) {
+ EXPECT_FALSE(conn->getZone(Name("example.org")).first);
+}
+
+// This zone is there, but in different class
+TEST_F(SQLite3Conn, noClass) {
+ initConn(SQLITE_DBFILE_EXAMPLE, RRClass::CH());
+ EXPECT_FALSE(conn->getZone(Name("example.com")).first);
+}
+
+}
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index 69785f0..f67ed4b 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -131,10 +131,10 @@ public:
/// These methods should never throw an exception.
//@{
/// Return the origin name of the zone.
- virtual const isc::dns::Name& getOrigin() const = 0;
+ virtual isc::dns::Name getOrigin() const = 0;
/// Return the RR class of the zone.
- virtual const isc::dns::RRClass& getClass() const = 0;
+ virtual isc::dns::RRClass getClass() const = 0;
//@}
///
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 4a0173c..887ac09 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -57,8 +57,6 @@ EXTRA_DIST += rdata/in_1/a_1.cc
EXTRA_DIST += rdata/in_1/a_1.h
EXTRA_DIST += rdata/in_1/aaaa_28.cc
EXTRA_DIST += rdata/in_1/aaaa_28.h
-EXTRA_DIST += rdata/in_1/srv_33.cc
-EXTRA_DIST += rdata/in_1/srv_33.h
#EXTRA_DIST += rdata/template.cc
#EXTRA_DIST += rdata/template.h
diff --git a/src/lib/dns/benchmarks/Makefile.am b/src/lib/dns/benchmarks/Makefile.am
index 0d7856f..8645385 100644
--- a/src/lib/dns/benchmarks/Makefile.am
+++ b/src/lib/dns/benchmarks/Makefile.am
@@ -13,6 +13,5 @@ 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/util/libutil.la
rdatarender_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
rdatarender_bench_LDADD += $(SQLITE_LIBS)
diff --git a/src/lib/dns/rdata/any_255/tsig_250.cc b/src/lib/dns/rdata/any_255/tsig_250.cc
index aeb1b3b..2557965 100644
--- a/src/lib/dns/rdata/any_255/tsig_250.cc
+++ b/src/lib/dns/rdata/any_255/tsig_250.cc
@@ -19,7 +19,6 @@
#include <boost/lexical_cast.hpp>
#include <util/buffer.h>
-#include <util/strutil.h>
#include <util/encode/base64.h>
#include <dns/messagerenderer.h>
@@ -31,7 +30,6 @@ using namespace std;
using namespace boost;
using namespace isc::util;
using namespace isc::util::encode;
-using namespace isc::util::str;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
@@ -67,6 +65,45 @@ struct TSIG::TSIGImpl {
const vector<uint8_t> other_data_;
};
+namespace {
+string
+getToken(istringstream& iss, const string& full_input) {
+ string token;
+ iss >> token;
+ if (iss.bad() || iss.fail()) {
+ isc_throw(InvalidRdataText, "Invalid TSIG text: parse error " <<
+ full_input);
+ }
+ return (token);
+}
+
+// This helper function converts a string token to an *unsigned* integer.
+// NumType is a *signed* integral type (e.g. int32_t) that is sufficiently
+// wide to store resulting integers.
+// BitSize is the maximum number of bits that the resulting integer can take.
+// This function first checks whether the given token can be converted to
+// an integer of NumType type. It then confirms the conversion result is
+// within the valid range, i.e., [0, 2^NumType - 1]. The second check is
+// necessary because lexical_cast<T> where T is an unsigned integer type
+// doesn't correctly reject negative numbers when compiled with SunStudio.
+template <typename NumType, int BitSize>
+NumType
+tokenToNum(const string& num_token) {
+ NumType num;
+ try {
+ num = lexical_cast<NumType>(num_token);
+ } catch (const boost::bad_lexical_cast& ex) {
+ isc_throw(InvalidRdataText, "Invalid TSIG numeric parameter: " <<
+ num_token);
+ }
+ if (num < 0 || num >= (static_cast<NumType>(1) << BitSize)) {
+ isc_throw(InvalidRdataText, "Numeric TSIG parameter out of range: " <<
+ num);
+ }
+ return (num);
+}
+}
+
/// \brief Constructor from string.
///
/// \c tsig_str must be formatted as follows:
@@ -111,52 +148,47 @@ struct TSIG::TSIGImpl {
TSIG::TSIG(const std::string& tsig_str) : impl_(NULL) {
istringstream iss(tsig_str);
- try {
- const Name algorithm(getToken(iss));
- const int64_t time_signed = tokenToNum<int64_t, 48>(getToken(iss));
- const int32_t fudge = tokenToNum<int32_t, 16>(getToken(iss));
- const int32_t macsize = tokenToNum<int32_t, 16>(getToken(iss));
-
- const string mac_txt = (macsize > 0) ? getToken(iss) : "";
- vector<uint8_t> mac;
- decodeBase64(mac_txt, mac);
- if (mac.size() != macsize) {
- isc_throw(InvalidRdataText, "TSIG MAC size and data are inconsistent");
- }
-
- const int32_t orig_id = tokenToNum<int32_t, 16>(getToken(iss));
-
- const string error_txt = getToken(iss);
- int32_t error = 0;
- // XXX: In the initial implementation we hardcode the mnemonics.
- // We'll soon generalize this.
- if (error_txt == "BADSIG") {
- error = 16;
- } else if (error_txt == "BADKEY") {
- error = 17;
- } else if (error_txt == "BADTIME") {
- error = 18;
- } else {
- error = tokenToNum<int32_t, 16>(error_txt);
- }
-
- const int32_t otherlen = tokenToNum<int32_t, 16>(getToken(iss));
- const string otherdata_txt = (otherlen > 0) ? getToken(iss) : "";
- vector<uint8_t> other_data;
- decodeBase64(otherdata_txt, other_data);
-
- if (!iss.eof()) {
- isc_throw(InvalidRdataText, "Unexpected input for TSIG RDATA: " <<
- tsig_str);
- }
-
- impl_ = new TSIGImpl(algorithm, time_signed, fudge, mac, orig_id,
- error, other_data);
-
- } catch (StringTokenError ste) {
- isc_throw(InvalidRdataText, "Invalid TSIG text: " << ste.what() <<
- ": " << tsig_str);
+ const Name algorithm(getToken(iss, tsig_str));
+ const int64_t time_signed = tokenToNum<int64_t, 48>(getToken(iss,
+ tsig_str));
+ const int32_t fudge = tokenToNum<int32_t, 16>(getToken(iss, tsig_str));
+ const int32_t macsize = tokenToNum<int32_t, 16>(getToken(iss, tsig_str));
+
+ const string mac_txt = (macsize > 0) ? getToken(iss, tsig_str) : "";
+ vector<uint8_t> mac;
+ decodeBase64(mac_txt, mac);
+ if (mac.size() != macsize) {
+ isc_throw(InvalidRdataText, "TSIG MAC size and data are inconsistent");
}
+
+ const int32_t orig_id = tokenToNum<int32_t, 16>(getToken(iss, tsig_str));
+
+ const string error_txt = getToken(iss, tsig_str);
+ int32_t error = 0;
+ // XXX: In the initial implementation we hardcode the mnemonics.
+ // We'll soon generalize this.
+ if (error_txt == "BADSIG") {
+ error = 16;
+ } else if (error_txt == "BADKEY") {
+ error = 17;
+ } else if (error_txt == "BADTIME") {
+ error = 18;
+ } else {
+ error = tokenToNum<int32_t, 16>(error_txt);
+ }
+
+ const int32_t otherlen = tokenToNum<int32_t, 16>(getToken(iss, tsig_str));
+ const string otherdata_txt = (otherlen > 0) ? getToken(iss, tsig_str) : "";
+ vector<uint8_t> other_data;
+ decodeBase64(otherdata_txt, other_data);
+
+ if (!iss.eof()) {
+ isc_throw(InvalidRdataText, "Unexpected input for TSIG RDATA: " <<
+ tsig_str);
+ }
+
+ impl_ = new TSIGImpl(algorithm, time_signed, fudge, mac, orig_id,
+ error, other_data);
}
/// \brief Constructor from wire-format data.
diff --git a/src/lib/dns/rdata/in_1/srv_33.cc b/src/lib/dns/rdata/in_1/srv_33.cc
deleted file mode 100644
index 50ae665..0000000
--- a/src/lib/dns/rdata/in_1/srv_33.cc
+++ /dev/null
@@ -1,245 +0,0 @@
-// 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 <iostream>
-#include <sstream>
-
-#include <boost/lexical_cast.hpp>
-
-#include <util/buffer.h>
-#include <util/strutil.h>
-
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-using namespace std;
-using namespace isc::util;
-using namespace isc::util::str;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-struct SRVImpl {
- // straightforward representation of SRV RDATA fields
- SRVImpl(uint16_t priority, uint16_t weight, uint16_t port,
- const Name& target) :
- priority_(priority), weight_(weight), port_(port),
- target_(target)
- {}
-
- uint16_t priority_;
- uint16_t weight_;
- uint16_t port_;
- Name target_;
-};
-
-/// \brief Constructor from string.
-///
-/// \c srv_str must be formatted as follows:
-/// \code <Priority> <Weight> <Port> <Target>
-/// \endcode
-/// where
-/// - <Priority>, <Weight>, and <Port> are an unsigned 16-bit decimal
-/// integer.
-/// - <Target> is a valid textual representation of domain name.
-///
-/// An example of valid string is:
-/// \code "1 5 1500 example.com." \endcode
-///
-/// <b>Exceptions</b>
-///
-/// If <Target> is not a valid domain name, a corresponding exception from
-/// the \c Name class will be thrown;
-/// if %any of the other bullet points above is not met, an exception of
-/// class \c InvalidRdataText will be thrown.
-/// This constructor internally involves resource allocation, and if it fails
-/// a corresponding standard exception will be thrown.
-SRV::SRV(const string& srv_str) :
- impl_(NULL)
-{
- istringstream iss(srv_str);
-
- try {
- const int32_t priority = tokenToNum<int32_t, 16>(getToken(iss));
- const int32_t weight = tokenToNum<int32_t, 16>(getToken(iss));
- const int32_t port = tokenToNum<int32_t, 16>(getToken(iss));
- const Name targetname(getToken(iss));
-
- if (!iss.eof()) {
- isc_throw(InvalidRdataText, "Unexpected input for SRV RDATA: " <<
- srv_str);
- }
-
- impl_ = new SRVImpl(priority, weight, port, targetname);
- } catch (StringTokenError ste) {
- isc_throw(InvalidRdataText, "Invalid SRV text: " <<
- ste.what() << ": " << srv_str);
- }
-}
-
-/// \brief Constructor from wire-format data.
-///
-/// When a read operation on \c buffer fails (e.g., due to a corrupted
-/// message) a corresponding exception from the \c InputBuffer class will
-/// be thrown.
-/// If the wire-format data does not end with a valid domain name,
-/// a corresponding exception from the \c Name class will be thrown.
-/// In addition, this constructor internally involves resource allocation,
-/// and if it fails a corresponding standard exception will be thrown.
-///
-/// According to RFC2782, the Target field must be a non compressed form
-/// of domain name. But this implementation accepts a %SRV RR even if that
-/// field is compressed as suggested in RFC3597.
-///
-/// \param buffer A buffer storing the wire format data.
-/// \param rdata_len The length of the RDATA in bytes, normally expected
-/// to be the value of the RDLENGTH field of the corresponding RR.
-SRV::SRV(InputBuffer& buffer, size_t rdata_len) {
- if (rdata_len < 6) {
- isc_throw(InvalidRdataLength, "SRV too short");
- }
-
- uint16_t priority = buffer.readUint16();
- uint16_t weight = buffer.readUint16();
- uint16_t port = buffer.readUint16();
- const Name targetname(buffer);
-
- impl_ = new SRVImpl(priority, weight, port, targetname);
-}
-
-/// \brief The copy constructor.
-///
-/// It internally allocates a resource, and if it fails a corresponding
-/// standard exception will be thrown.
-/// This constructor never throws an exception otherwise.
-SRV::SRV(const SRV& source) :
- Rdata(), impl_(new SRVImpl(*source.impl_))
-{}
-
-SRV&
-SRV::operator=(const SRV& source) {
- if (impl_ == source.impl_) {
- return (*this);
- }
-
- SRVImpl* newimpl = new SRVImpl(*source.impl_);
- delete impl_;
- impl_ = newimpl;
-
- return (*this);
-}
-
-SRV::~SRV() {
- delete impl_;
-}
-
-/// \brief Convert the \c SRV to a string.
-///
-/// The output of this method is formatted as described in the "from string"
-/// constructor (\c SRV(const std::string&))).
-///
-/// If internal resource allocation fails, a corresponding
-/// standard exception will be thrown.
-///
-/// \return A \c string object that represents the \c SRV object.
-string
-SRV::toText() const {
- using namespace boost;
- return (lexical_cast<string>(impl_->priority_) +
- " " + lexical_cast<string>(impl_->weight_) +
- " " + lexical_cast<string>(impl_->port_) +
- " " + impl_->target_.toText());
-}
-
-/// \brief Render the \c SRV in the wire format without name compression.
-///
-/// If internal resource allocation fails, a corresponding
-/// standard exception will be thrown.
-/// This method never throws an exception otherwise.
-///
-/// \param buffer An output buffer to store the wire data.
-void
-SRV::toWire(OutputBuffer& buffer) const {
- buffer.writeUint16(impl_->priority_);
- buffer.writeUint16(impl_->weight_);
- buffer.writeUint16(impl_->port_);
- impl_->target_.toWire(buffer);
-}
-
-/// \brief Render the \c SRV in the wire format with taking into account
-/// compression.
-///
-/// As specified in RFC2782, the Target field (a domain name) will not be
-/// compressed. However, the domain name could be a target of compression
-/// of other compressible names (though pretty unlikely), the offset
-/// information of the algorithm name may be recorded in \c renderer.
-///
-/// If internal resource allocation fails, a corresponding
-/// standard exception will be thrown.
-/// This method never throws an exception otherwise.
-///
-/// \param renderer DNS message rendering context that encapsulates the
-/// output buffer and name compression information.
-void
-SRV::toWire(AbstractMessageRenderer& renderer) const {
- renderer.writeUint16(impl_->priority_);
- renderer.writeUint16(impl_->weight_);
- renderer.writeUint16(impl_->port_);
- renderer.writeName(impl_->target_, false);
-}
-
-/// \brief Compare two instances of \c SRV RDATA.
-///
-/// See documentation in \c Rdata.
-int
-SRV::compare(const Rdata& other) const {
- const SRV& other_srv = dynamic_cast<const SRV&>(other);
-
- if (impl_->priority_ != other_srv.impl_->priority_) {
- return (impl_->priority_ < other_srv.impl_->priority_ ? -1 : 1);
- }
- if (impl_->weight_ != other_srv.impl_->weight_) {
- return (impl_->weight_ < other_srv.impl_->weight_ ? -1 : 1);
- }
- if (impl_->port_ != other_srv.impl_->port_) {
- return (impl_->port_ < other_srv.impl_->port_ ? -1 : 1);
- }
-
- return (compareNames(impl_->target_, other_srv.impl_->target_));
-}
-
-uint16_t
-SRV::getPriority() const {
- return (impl_->priority_);
-}
-
-uint16_t
-SRV::getWeight() const {
- return (impl_->weight_);
-}
-
-uint16_t
-SRV::getPort() const {
- return (impl_->port_);
-}
-
-const Name&
-SRV::getTarget() const {
- return (impl_->target_);
-}
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/in_1/srv_33.h b/src/lib/dns/rdata/in_1/srv_33.h
deleted file mode 100644
index d067021..0000000
--- a/src/lib/dns/rdata/in_1/srv_33.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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 <stdint.h>
-
-#include <dns/name.h>
-#include <dns/rdata.h>
-
-// BEGIN_HEADER_GUARD
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-struct SRVImpl;
-
-/// \brief \c rdata::SRV class represents the SRV RDATA as defined %in
-/// RFC2782.
-///
-/// This class implements the basic interfaces inherited from the abstract
-/// \c rdata::Rdata class, and provides trivial accessors specific to the
-/// SRV RDATA.
-class SRV : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
-
- /// \brief Assignment operator.
- ///
- /// It internally allocates a resource, and if it fails a corresponding
- /// standard exception will be thrown.
- /// This operator never throws an exception otherwise.
- ///
- /// This operator provides the strong exception guarantee: When an
- /// exception is thrown the content of the assignment target will be
- /// intact.
- SRV& operator=(const SRV& source);
-
- /// \brief The destructor.
- ~SRV();
-
- ///
- /// Specialized methods
- ///
-
- /// \brief Return the value of the priority field.
- ///
- /// This method never throws an exception.
- uint16_t getPriority() const;
-
- /// \brief Return the value of the weight field.
- ///
- /// This method never throws an exception.
- uint16_t getWeight() const;
-
- /// \brief Return the value of the port field.
- ///
- /// This method never throws an exception.
- uint16_t getPort() const;
-
- /// \brief Return the value of the target field.
- ///
- /// \return A reference to a \c Name class object corresponding to the
- /// internal target name.
- ///
- /// This method never throws an exception.
- const Name& getTarget() const;
-
-private:
- SRVImpl* impl_;
-};
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index bd6fbe2..3a249c1 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -41,7 +41,6 @@ run_unittests_SOURCES += rdata_nsecbitmap_unittest.cc
run_unittests_SOURCES += rdata_nsec3param_unittest.cc
run_unittests_SOURCES += rdata_rrsig_unittest.cc
run_unittests_SOURCES += rdata_rp_unittest.cc
-run_unittests_SOURCES += rdata_srv_unittest.cc
run_unittests_SOURCES += rdata_tsig_unittest.cc
run_unittests_SOURCES += rrset_unittest.cc rrsetlist_unittest.cc
run_unittests_SOURCES += question_unittest.cc
diff --git a/src/lib/dns/tests/rdata_srv_unittest.cc b/src/lib/dns/tests/rdata_srv_unittest.cc
deleted file mode 100644
index 3394f43..0000000
--- a/src/lib/dns/tests/rdata_srv_unittest.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for generic
-// 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 <util/buffer.h>
-#include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-
-#include <gtest/gtest.h>
-
-#include <dns/tests/unittest_util.h>
-#include <dns/tests/rdata_unittest.h>
-
-using isc::UnitTestUtil;
-using namespace std;
-using namespace isc::dns;
-using namespace isc::util;
-using namespace isc::dns::rdata;
-
-namespace {
-class Rdata_SRV_Test : public RdataTest {
- // there's nothing to specialize
-};
-
-string srv_txt("1 5 1500 a.example.com.");
-string srv_txt2("1 5 1400 example.com.");
-string too_long_label("012345678901234567890123456789"
- "0123456789012345678901234567890123");
-
-// 1 5 1500 a.example.com.
-const uint8_t wiredata_srv[] = {
- 0x00, 0x01, 0x00, 0x05, 0x05, 0xdc, 0x01, 0x61, 0x07, 0x65, 0x78,
- 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00};
-// 1 5 1400 example.com.
-const uint8_t wiredata_srv2[] = {
- 0x00, 0x01, 0x00, 0x05, 0x05, 0x78, 0x07, 0x65, 0x78, 0x61, 0x6d,
- 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00};
-
-const in::SRV rdata_srv(srv_txt);
-const in::SRV rdata_srv2(srv_txt2);
-
-TEST_F(Rdata_SRV_Test, createFromText) {
- EXPECT_EQ(1, rdata_srv.getPriority());
- EXPECT_EQ(5, rdata_srv.getWeight());
- EXPECT_EQ(1500, rdata_srv.getPort());
- EXPECT_EQ(Name("a.example.com."), rdata_srv.getTarget());
-}
-
-TEST_F(Rdata_SRV_Test, badText) {
- // priority is too large (2814...6 is 2^48)
- EXPECT_THROW(in::SRV("281474976710656 5 1500 a.example.com."),
- InvalidRdataText);
- // weight is too large
- EXPECT_THROW(in::SRV("1 281474976710656 1500 a.example.com."),
- InvalidRdataText);
- // port is too large
- EXPECT_THROW(in::SRV("1 5 281474976710656 a.example.com."),
- InvalidRdataText);
- // incomplete text
- EXPECT_THROW(in::SRV("1 5 a.example.com."),
- InvalidRdataText);
- EXPECT_THROW(in::SRV("1 5 1500a.example.com."),
- InvalidRdataText);
- // bad name
- EXPECT_THROW(in::SRV("1 5 1500 a.example.com." + too_long_label),
- TooLongLabel);
-}
-
-TEST_F(Rdata_SRV_Test, assignment) {
- in::SRV copy((string(srv_txt2)));
- copy = rdata_srv;
- EXPECT_EQ(0, copy.compare(rdata_srv));
-
- // Check if the copied data is valid even after the original is deleted
- in::SRV* copy2 = new in::SRV(rdata_srv);
- in::SRV copy3((string(srv_txt2)));
- copy3 = *copy2;
- delete copy2;
- EXPECT_EQ(0, copy3.compare(rdata_srv));
-
- // Self assignment
- copy = copy;
- EXPECT_EQ(0, copy.compare(rdata_srv));
-}
-
-TEST_F(Rdata_SRV_Test, createFromWire) {
- EXPECT_EQ(0, rdata_srv.compare(
- *rdataFactoryFromFile(RRType("SRV"), RRClass("IN"),
- "rdata_srv_fromWire")));
- // RDLENGTH is too short
- EXPECT_THROW(rdataFactoryFromFile(RRType("SRV"), RRClass("IN"),
- "rdata_srv_fromWire", 23),
- InvalidRdataLength);
- // RDLENGTH is too long
- EXPECT_THROW(rdataFactoryFromFile(RRType("SRV"), RRClass("IN"),
- "rdata_srv_fromWire", 46),
- InvalidRdataLength);
- // incomplete name. the error should be detected in the name constructor
- EXPECT_THROW(rdataFactoryFromFile(RRType("SRV"), RRClass("IN"),
- "rdata_cname_fromWire", 69),
- DNSMessageFORMERR);
- // parse compressed target name
- EXPECT_EQ(0, rdata_srv.compare(
- *rdataFactoryFromFile(RRType("SRV"), RRClass("IN"),
- "rdata_srv_fromWire", 89)));
-}
-
-TEST_F(Rdata_SRV_Test, toWireBuffer) {
- rdata_srv.toWire(obuffer);
- EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
- obuffer.getData(), obuffer.getLength(),
- wiredata_srv, sizeof(wiredata_srv));
- obuffer.clear();
- rdata_srv2.toWire(obuffer);
- EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
- obuffer.getData(), obuffer.getLength(),
- wiredata_srv2, sizeof(wiredata_srv2));
-}
-
-TEST_F(Rdata_SRV_Test, toWireRenderer) {
- rdata_srv.toWire(renderer);
- EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
- obuffer.getData(), obuffer.getLength(),
- wiredata_srv, sizeof(wiredata_srv));
- renderer.clear();
- rdata_srv2.toWire(renderer);
- EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
- obuffer.getData(), obuffer.getLength(),
- wiredata_srv2, sizeof(wiredata_srv2));
-}
-
-TEST_F(Rdata_SRV_Test, toText) {
- EXPECT_EQ(srv_txt, rdata_srv.toText());
- EXPECT_EQ(srv_txt2, rdata_srv2.toText());
-}
-
-TEST_F(Rdata_SRV_Test, compare) {
- // test RDATAs, sorted in the ascendent order.
- vector<in::SRV> compare_set;
- compare_set.push_back(in::SRV("1 5 1500 a.example.com."));
- compare_set.push_back(in::SRV("2 5 1500 a.example.com."));
- compare_set.push_back(in::SRV("2 6 1500 a.example.com."));
- compare_set.push_back(in::SRV("2 6 1600 a.example.com."));
- compare_set.push_back(in::SRV("2 6 1600 example.com."));
-
- EXPECT_EQ(0, compare_set[0].compare(
- in::SRV("1 5 1500 a.example.com.")));
-
- vector<in::SRV>::const_iterator it;
- vector<in::SRV>::const_iterator it_end = compare_set.end();
- for (it = compare_set.begin(); it != it_end - 1; ++it) {
- EXPECT_GT(0, (*it).compare(*(it + 1)));
- EXPECT_LT(0, (*(it + 1)).compare(*it));
- }
-
- // comparison attempt between incompatible RR types should be rejected
- EXPECT_THROW(rdata_srv.compare(*RdataTest::rdata_nomatch), bad_cast);
-}
-}
diff --git a/src/lib/dns/tests/testdata/Makefile.am b/src/lib/dns/tests/testdata/Makefile.am
index 60735e9..257f2f3 100644
--- a/src/lib/dns/tests/testdata/Makefile.am
+++ b/src/lib/dns/tests/testdata/Makefile.am
@@ -101,7 +101,6 @@ EXTRA_DIST += rdata_rp_fromWire3.spec rdata_rp_fromWire4.spec
EXTRA_DIST += rdata_rp_fromWire5.spec rdata_rp_fromWire6.spec
EXTRA_DIST += rdata_rp_toWire1.spec rdata_rp_toWire2.spec
EXTRA_DIST += rdata_soa_fromWire rdata_soa_toWireUncompressed.spec
-EXTRA_DIST += rdata_srv_fromWire
EXTRA_DIST += rdata_txt_fromWire1 rdata_txt_fromWire2.spec
EXTRA_DIST += rdata_txt_fromWire3.spec rdata_txt_fromWire4.spec
EXTRA_DIST += rdata_txt_fromWire5.spec rdata_unknown_fromWire
diff --git a/src/lib/dns/tests/testdata/rdata_srv_fromWire b/src/lib/dns/tests/testdata/rdata_srv_fromWire
deleted file mode 100644
index dac87e9..0000000
--- a/src/lib/dns/tests/testdata/rdata_srv_fromWire
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# various kinds of SRV RDATA stored in an input buffer
-#
-# RDLENGHT=21 bytes
-# 0 1
- 00 15
-# 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2(bytes)
- 00 01 00 05 05 dc 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-# short length
-# 3 4
- 00 12
-# 5 6 7 8 9 30 1 2 3 4 5 6 7 8 9 40 1 2 3 4 5
- 00 01 00 05 05 dc 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-# length too long
-# 6 7
- 00 19
-#
-# 8 9 50 1 2 3 4 5 6 7 8 9 60 1 2 3 4 5 6 7 8
- 00 01 00 05 05 dc 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-#
-# incomplete target name
-# 9 70
- 00 12
-# 1 2 3 4 5 6 7 8 9 80 1 2 3 4 5 6 7 8
- 00 01 00 05 05 dc 01 61 07 65 78 61 6d 70 6c 65 03 63
-#
-#
-# Valid compressed target name: 'a' + pointer
-# 9 90
- 00 0a
-#
-# 1 2 3 4 5 6 7 8 9 100
- 00 01 00 05 05 dc 01 61 c0 0a
diff --git a/src/lib/python/isc/Makefile.am b/src/lib/python/isc/Makefile.am
index d94100b..b391c1e 100644
--- a/src/lib/python/isc/Makefile.am
+++ b/src/lib/python/isc/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = datasrc cc config log net notify util testutils acl bind10
+SUBDIRS = datasrc cc config log net notify util testutils acl
python_PYTHON = __init__.py
diff --git a/src/lib/python/isc/bind10/Makefile.am b/src/lib/python/isc/bind10/Makefile.am
deleted file mode 100644
index 43a7605..0000000
--- a/src/lib/python/isc/bind10/Makefile.am
+++ /dev/null
@@ -1,4 +0,0 @@
-SUBDIRS = . tests
-
-python_PYTHON = __init__.py sockcreator.py
-pythondir = $(pyexecdir)/isc/bind10
diff --git a/src/lib/python/isc/bind10/__init__.py b/src/lib/python/isc/bind10/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/lib/python/isc/bind10/sockcreator.py b/src/lib/python/isc/bind10/sockcreator.py
deleted file mode 100644
index 9fcc74e..0000000
--- a/src/lib/python/isc/bind10/sockcreator.py
+++ /dev/null
@@ -1,226 +0,0 @@
-# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-#
-# 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.
-
-import socket
-import struct
-import os
-import subprocess
-from bind10_messages import *
-from libutil_io_python import recv_fd
-
-logger = isc.log.Logger("boss")
-
-"""
-Module that comunicates with the privileged socket creator (b10-sockcreator).
-"""
-
-class CreatorError(Exception):
- """
- Exception for socket creator related errors.
-
- It has two members: fatal and errno and they are just holding the values
- passed to the __init__ function.
- """
-
- def __init__(self, message, fatal, errno=None):
- """
- Creates the exception. The message argument is the usual string.
- The fatal one tells if the error is fatal (eg. the creator crashed)
- and errno is the errno value returned from socket creator, if
- applicable.
- """
- Exception.__init__(self, message)
- self.fatal = fatal
- self.errno = errno
-
-class Parser:
- """
- This class knows the sockcreator language. It creates commands, sends them
- and receives the answers and parses them.
-
- It does not start it, the communication channel must be provided.
-
- In theory, anything here can throw a fatal CreatorError exception, but it
- happens only in case something like the creator process crashes. Any other
- occasions are mentioned explicitly.
- """
-
- def __init__(self, creator_socket):
- """
- Creates the parser. The creator_socket is socket to the socket creator
- process that will be used for communication. However, the object must
- have a read_fd() method to read the file descriptor. This slightly
- unusual trick with modifying an object is used to easy up testing.
-
- You can use WrappedSocket in production code to add the method to any
- ordinary socket.
- """
- self.__socket = creator_socket
- logger.info(BIND10_SOCKCREATOR_INIT)
-
- def terminate(self):
- """
- Asks the creator process to terminate and waits for it to close the
- socket. Does not return anything. Raises a CreatorError if there is
- still data on the socket, if there is an error closing the socket,
- or if the socket had already been closed.
- """
- if self.__socket is None:
- raise CreatorError('Terminated already', True)
- logger.info(BIND10_SOCKCREATOR_TERMINATE)
- try:
- self.__socket.sendall(b'T')
- # Wait for an EOF - it will return empty data
- eof = self.__socket.recv(1)
- if len(eof) != 0:
- raise CreatorError('Protocol error - data after terminated',
- True)
- self.__socket = None
- except socket.error as se:
- self.__socket = None
- raise CreatorError(str(se), True)
-
- def get_socket(self, address, port, socktype):
- """
- Asks the socket creator process to create a socket. Pass an address
- (the isc.net.IPaddr object), port number and socket type (either
- string "UDP", "TCP" or constant socket.SOCK_DGRAM or
- socket.SOCK_STREAM.
-
- Blocks until it is provided by the socket creator process (which
- should be fast, as it is on localhost) and returns the file descriptor
- number. It raises a CreatorError exception if the creation fails.
- """
- if self.__socket is None:
- raise CreatorError('Socket requested on terminated creator', True)
- # First, assemble the request from parts
- logger.info(BIND10_SOCKET_GET, address, port, socktype)
- data = b'S'
- if socktype == 'UDP' or socktype == socket.SOCK_DGRAM:
- data += b'U'
- elif socktype == 'TCP' or socktype == socket.SOCK_STREAM:
- data += b'T'
- else:
- raise ValueError('Unknown socket type: ' + str(socktype))
- if address.family == socket.AF_INET:
- data += b'4'
- elif address.family == socket.AF_INET6:
- data += b'6'
- else:
- raise ValueError('Unknown address family in address')
- data += struct.pack('!H', port)
- data += address.addr
- try:
- # Send the request
- self.__socket.sendall(data)
- answer = self.__socket.recv(1)
- if answer == b'S':
- # Success!
- result = self.__socket.read_fd()
- logger.info(BIND10_SOCKET_CREATED, result)
- return result
- elif answer == b'E':
- # There was an error, read the error as well
- error = self.__socket.recv(1)
- errno = struct.unpack('i',
- self.__read_all(len(struct.pack('i',
- 0))))
- if error == b'S':
- cause = 'socket'
- elif error == b'B':
- cause = 'bind'
- else:
- self.__socket = None
- logger.fatal(BIND10_SOCKCREATOR_BAD_CAUSE, error)
- raise CreatorError('Unknown error cause' + str(answer), True)
- logger.error(BIND10_SOCKET_ERROR, cause, errno[0],
- os.strerror(errno[0]))
- raise CreatorError('Error creating socket on ' + cause, False,
- errno[0])
- else:
- self.__socket = None
- logger.fatal(BIND10_SOCKCREATOR_BAD_RESPONSE, answer)
- raise CreatorError('Unknown response ' + str(answer), True)
- except socket.error as se:
- self.__socket = None
- logger.fatal(BIND10_SOCKCREATOR_TRANSPORT_ERROR, str(se))
- raise CreatorError(str(se), True)
-
- def __read_all(self, length):
- """
- Keeps reading until length data is read or EOF or error happens.
-
- EOF is considered error as well and throws a CreatorError.
- """
- result = b''
- while len(result) < length:
- data = self.__socket.recv(length - len(result))
- if len(data) == 0:
- self.__socket = None
- logger.fatal(BIND10_SOCKCREATOR_EOF)
- raise CreatorError('Unexpected EOF', True)
- result += data
- return result
-
-class WrappedSocket:
- """
- This class wraps a socket and adds a read_fd method, so it can be used
- for the Parser class conveniently. It simply copies all its guts into
- itself and implements the method.
- """
- def __init__(self, socket):
- # Copy whatever can be copied from the socket
- for name in dir(socket):
- if name not in ['__class__', '__weakref__']:
- setattr(self, name, getattr(socket, name))
- # Keep the socket, so we can prevent it from being garbage-collected
- # and closed before we are removed ourself
- self.__orig_socket = socket
-
- def read_fd(self):
- """
- Read the file descriptor from the socket.
- """
- return recv_fd(self.fileno())
-
-# FIXME: Any idea how to test this? Starting an external process doesn't sound
-# OK
-class Creator(Parser):
- """
- This starts the socket creator and allows asking for the sockets.
- """
- def __init__(self, path):
- (local, remote) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
- # Popen does not like, for some reason, having the same socket for
- # stdin as well as stdout, so we dup it before passing it there.
- remote2 = socket.fromfd(remote.fileno(), socket.AF_UNIX,
- socket.SOCK_STREAM)
- env = os.environ
- env['PATH'] = path
- self.__process = subprocess.Popen(['b10-sockcreator'], env=env,
- stdin=remote.fileno(),
- stdout=remote2.fileno())
- remote.close()
- remote2.close()
- Parser.__init__(self, WrappedSocket(local))
-
- def pid(self):
- return self.__process.pid
-
- def kill(self):
- logger.warn(BIND10_SOCKCREATOR_KILL)
- if self.__process is not None:
- self.__process.kill()
- self.__process = None
diff --git a/src/lib/python/isc/bind10/tests/Makefile.am b/src/lib/python/isc/bind10/tests/Makefile.am
deleted file mode 100644
index f498b86..0000000
--- a/src/lib/python/isc/bind10/tests/Makefile.am
+++ /dev/null
@@ -1,29 +0,0 @@
-PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
-#PYTESTS = args_test.py bind10_test.py
-# NOTE: this has a generated test found in the builddir
-PYTESTS = sockcreator_test.py
-
-EXTRA_DIST = $(PYTESTS)
-
-# If necessary (rare cases), explicitly specify paths to dynamic libraries
-# required by loadable python modules.
-LIBRARY_PATH_PLACEHOLDER =
-if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/cc/.libs:$(abs_top_builddir)/src/lib/config/.libs:$(abs_top_builddir)/src/lib/log/.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
-check-local:
-if ENABLE_PYTHON_COVERAGE
- touch $(abs_top_srcdir)/.coverage
- rm -f .coverage
- ${LN_S} $(abs_top_srcdir)/.coverage .coverage
-endif
- for pytest in $(PYTESTS) ; do \
- echo Running test: $$pytest ; \
- $(LIBRARY_PATH_PLACEHOLDER) \
- env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_srcdir)/src/bin:$(abs_top_builddir)/src/bin/bind10:$(abs_top_builddir)/src/lib/util/io/.libs \
- BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \
- $(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
- done
-
diff --git a/src/lib/python/isc/bind10/tests/sockcreator_test.py b/src/lib/python/isc/bind10/tests/sockcreator_test.py
deleted file mode 100644
index 4453184..0000000
--- a/src/lib/python/isc/bind10/tests/sockcreator_test.py
+++ /dev/null
@@ -1,327 +0,0 @@
-# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-#
-# 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.
-
-# This test file is generated .py.in -> .py just to be in the build dir,
-# same as the rest of the tests. Saves a lot of stuff in makefile.
-
-"""
-Tests for the bind10.sockcreator module.
-"""
-
-import unittest
-import struct
-import socket
-from isc.net.addr import IPAddr
-import isc.log
-from libutil_io_python import send_fd
-from isc.bind10.sockcreator import Parser, CreatorError, WrappedSocket
-
-class FakeCreator:
- """
- Class emulating the socket to the socket creator. It can be given expected
- data to receive (and check) and responses to give to the Parser class
- during testing.
- """
-
- class InvalidPlan(Exception):
- """
- Raised when someone wants to recv when sending is planned or vice
- versa.
- """
- pass
-
- class InvalidData(Exception):
- """
- Raises when the data passed to sendall are not the same as expected.
- """
- pass
-
- def __init__(self, plan):
- """
- Create the object. The plan variable contains list of expected actions,
- in form:
-
- [('r', 'Data to return from recv'), ('s', 'Data expected on sendall'),
- , ('d', 'File descriptor number to return from read_sock'), ('e',
- None), ...]
-
- It modifies the array as it goes.
- """
- self.__plan = plan
-
- def __get_plan(self, expected):
- if len(self.__plan) == 0:
- raise InvalidPlan('Nothing more planned')
- (kind, data) = self.__plan[0]
- if kind == 'e':
- self.__plan.pop(0)
- raise socket.error('False socket error')
- if kind != expected:
- raise InvalidPlan('Planned ' + kind + ', but ' + expected +
- 'requested')
- return data
-
- def recv(self, maxsize):
- """
- Emulate recv. Returs maxsize bytes from the current recv plan. If
- there are data left from previous recv call, it is used first.
-
- If no recv is planned, raises InvalidPlan.
- """
- data = self.__get_plan('r')
- result, rest = data[:maxsize], data[maxsize:]
- if len(rest) > 0:
- self.__plan[0] = ('r', rest)
- else:
- self.__plan.pop(0)
- return result
-
- def read_fd(self):
- """
- Emulate the reading of file descriptor. Returns one from a plan.
-
- It raises InvalidPlan if no socket is planned now.
- """
- fd = self.__get_plan('f')
- self.__plan.pop(0)
- return fd
-
- def sendall(self, data):
- """
- Checks that the data passed are correct according to plan. It raises
- InvalidData if the data differs or InvalidPlan when sendall is not
- expected.
- """
- planned = self.__get_plan('s')
- dlen = len(data)
- prefix, rest = planned[:dlen], planned[dlen:]
- if prefix != data:
- raise InvalidData('Expected "' + str(prefix)+ '", got "' +
- str(data) + '"')
- if len(rest) > 0:
- self.__plan[0] = ('s', rest)
- else:
- self.__plan.pop(0)
-
- def all_used(self):
- """
- Returns if the whole plan was consumed.
- """
- return len(self.__plan) == 0
-
-class ParserTests(unittest.TestCase):
- """
- Testcases for the Parser class.
-
- A lot of these test could be done by
- `with self.assertRaises(CreatorError) as cm`. But some versions of python
- take the scope wrong and don't work, so we use the primitive way of
- try-except.
- """
- def __terminate(self):
- creator = FakeCreator([('s', b'T'), ('r', b'')])
- parser = Parser(creator)
- self.assertEqual(None, parser.terminate())
- self.assertTrue(creator.all_used())
- return parser
-
- def test_terminate(self):
- """
- Test if the command to terminate is correct and it waits for reading the
- EOF.
- """
- self.__terminate()
-
- def __terminate_raises(self, parser):
- """
- Check that terminate() raises a fatal exception.
- """
- try:
- parser.terminate()
- self.fail("Not raised")
- except CreatorError as ce:
- self.assertTrue(ce.fatal)
- self.assertEqual(None, ce.errno)
-
- def test_terminate_error1(self):
- """
- Test it reports an exception when there's error terminating the creator.
- This one raises an error when receiving the EOF.
- """
- creator = FakeCreator([('s', b'T'), ('e', None)])
- parser = Parser(creator)
- self.__terminate_raises(parser)
-
- def test_terminate_error2(self):
- """
- Test it reports an exception when there's error terminating the creator.
- This one raises an error when sending data.
- """
- creator = FakeCreator([('e', None)])
- parser = Parser(creator)
- self.__terminate_raises(parser)
-
- def test_terminate_error3(self):
- """
- Test it reports an exception when there's error terminating the creator.
- This one sends data when it should have terminated.
- """
- creator = FakeCreator([('s', b'T'), ('r', b'Extra data')])
- parser = Parser(creator)
- self.__terminate_raises(parser)
-
- def test_terminate_twice(self):
- """
- Test we can't terminate twice.
- """
- parser = self.__terminate()
- self.__terminate_raises(parser)
-
- def test_crash(self):
- """
- Tests that the parser correctly raises exception when it crashes
- unexpectedly.
- """
- creator = FakeCreator([('s', b'SU4\0\0\0\0\0\0'), ('r', b'')])
- parser = Parser(creator)
- try:
- parser.get_socket(IPAddr('0.0.0.0'), 0, 'UDP')
- self.fail("Not raised")
- except CreatorError as ce:
- self.assertTrue(creator.all_used())
- # Is the exception correct?
- self.assertTrue(ce.fatal)
- self.assertEqual(None, ce.errno)
-
- def test_error(self):
- """
- Tests that the parser correctly raises non-fatal exception when
- the socket can not be created.
- """
- # We split the int to see if it can cope with data coming in
- # different packets
- intpart = struct.pack('@i', 42)
- creator = FakeCreator([('s', b'SU4\0\0\0\0\0\0'), ('r', b'ES' +
- intpart[:1]), ('r', intpart[1:])])
- parser = Parser(creator)
- try:
- parser.get_socket(IPAddr('0.0.0.0'), 0, 'UDP')
- self.fail("Not raised")
- except CreatorError as ce:
- self.assertTrue(creator.all_used())
- # Is the exception correct?
- self.assertFalse(ce.fatal)
- self.assertEqual(42, ce.errno)
-
- def __error(self, plan):
- creator = FakeCreator(plan)
- parser = Parser(creator)
- try:
- parser.get_socket(IPAddr('0.0.0.0'), 0, socket.SOCK_DGRAM)
- self.fail("Not raised")
- except CreatorError as ce:
- self.assertTrue(creator.all_used())
- self.assertTrue(ce.fatal)
-
- def test_error_send(self):
- self.__error([('e', None)])
-
- def test_error_recv(self):
- self.__error([('s', b'SU4\0\0\0\0\0\0'), ('e', None)])
-
- def test_error_read_fd(self):
- self.__error([('s', b'SU4\0\0\0\0\0\0'), ('r', b'S'), ('e', None)])
-
- def __create(self, addr, socktype, encoded):
- creator = FakeCreator([('s', b'S' + encoded), ('r', b'S'), ('f', 42)])
- parser = Parser(creator)
- self.assertEqual(42, parser.get_socket(IPAddr(addr), 42, socktype))
-
- def test_create1(self):
- self.__create('192.0.2.0', 'UDP', b'U4\0\x2A\xC0\0\x02\0')
-
- def test_create2(self):
- self.__create('2001:db8::', socket.SOCK_STREAM,
- b'T6\0\x2A\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\0\0')
-
- def test_create_terminated(self):
- """
- Test we can't request sockets after it was terminated.
- """
- parser = self.__terminate()
- try:
- parser.get_socket(IPAddr('0.0.0.0'), 0, 'UDP')
- self.fail("Not raised")
- except CreatorError as ce:
- self.assertTrue(ce.fatal)
- self.assertEqual(None, ce.errno)
-
- def test_invalid_socktype(self):
- """
- Test invalid socket type is rejected
- """
- self.assertRaises(ValueError, Parser(FakeCreator([])).get_socket,
- IPAddr('0.0.0.0'), 42, 'RAW')
-
- def test_invalid_family(self):
- """
- Test it rejects invalid address family.
- """
- # Note: this produces a bad logger output, since this address
- # can not be converted to string, so the original message with
- # placeholders is output. This should not happen in practice, so
- # it is harmless.
- addr = IPAddr('0.0.0.0')
- addr.family = 42
- self.assertRaises(ValueError, Parser(FakeCreator([])).get_socket,
- addr, 42, socket.SOCK_DGRAM)
-
-class WrapTests(unittest.TestCase):
- """
- Tests for the wrap_socket function.
- """
- def test_wrap(self):
- # We construct two pairs of socket. The receiving side of one pair will
- # be wrapped. Then we send one of the other pair through this pair and
- # check the received one can be used as a socket
-
- # The transport socket
- (t1, t2) = socket.socketpair()
- # The payload socket
- (p1, p2) = socket.socketpair()
-
- t2 = WrappedSocket(t2)
-
- # Transfer the descriptor
- send_fd(t1.fileno(), p1.fileno())
- p1 = socket.fromfd(t2.read_fd(), socket.AF_UNIX, socket.SOCK_STREAM)
-
- # Now, pass some data trough the socket
- p1.send(b'A')
- data = p2.recv(1)
- self.assertEqual(b'A', data)
-
- # Test the wrapping didn't hurt the socket's usual methods
- t1.send(b'B')
- data = t2.recv(1)
- self.assertEqual(b'B', data)
- t2.send(b'C')
- data = t1.recv(1)
- self.assertEqual(b'C', data)
-
-if __name__ == '__main__':
- isc.log.init("bind10") # FIXME Should this be needed?
- isc.log.resetUnitTestRootLogger()
- unittest.main()
diff --git a/src/lib/resolve/tests/Makefile.am b/src/lib/resolve/tests/Makefile.am
index cf05d9b..ee311a6 100644
--- a/src/lib/resolve/tests/Makefile.am
+++ b/src/lib/resolve/tests/Makefile.am
@@ -31,7 +31,6 @@ 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/util/libutil.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/lib/util/strutil.cc b/src/lib/util/strutil.cc
index ed7fc9b..161f9ac 100644
--- a/src/lib/util/strutil.cc
+++ b/src/lib/util/strutil.cc
@@ -132,17 +132,6 @@ format(const std::string& format, const std::vector<std::string>& args) {
return (result);
}
-std::string
-getToken(std::istringstream& iss) {
- string token;
- iss >> token;
- if (iss.bad() || iss.fail()) {
- isc_throw(StringTokenError, "could not read token from string");
- }
- return (token);
-}
-
-
} // namespace str
} // namespace util
} // namespace isc
diff --git a/src/lib/util/strutil.h b/src/lib/util/strutil.h
index 021c236..e044c15 100644
--- a/src/lib/util/strutil.h
+++ b/src/lib/util/strutil.h
@@ -18,10 +18,7 @@
#include <algorithm>
#include <cctype>
#include <string>
-#include <sstream>
#include <vector>
-#include <exceptions/exceptions.h>
-#include <boost/lexical_cast.hpp>
namespace isc {
namespace util {
@@ -29,16 +26,6 @@ namespace str {
/// \brief A Set of C++ Utilities for Manipulating Strings
-///
-/// \brief A standard string util exception that is thrown if getToken or
-/// numToToken are called with bad input data
-///
-class StringTokenError : public Exception {
-public:
- StringTokenError(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
/// \brief Normalize Backslash
///
/// Only relevant to Windows, this replaces all "\" in a string with "/" and
@@ -153,55 +140,6 @@ std::string format(const std::string& format,
const std::vector<std::string>& args);
-/// \brief Returns one token from the given stringstream
-///
-/// Using the >> operator, with basic error checking
-///
-/// \exception StringTokenError if the token cannot be read from the stream
-///
-/// \param iss stringstream to read one token from
-///
-/// \return the first token read from the stringstream
-std::string getToken(std::istringstream& iss);
-
-/// \brief Converts a string token to an *unsigned* integer.
-///
-/// The value is converted using a lexical cast, with error and bounds
-/// checking.
-///
-/// NumType is a *signed* integral type (e.g. int32_t) that is sufficiently
-/// wide to store resulting integers.
-///
-/// BitSize is the maximum number of bits that the resulting integer can take.
-/// This function first checks whether the given token can be converted to
-/// an integer of NumType type. It then confirms the conversion result is
-/// within the valid range, i.e., [0, 2^BitSize - 1]. The second check is
-/// necessary because lexical_cast<T> where T is an unsigned integer type
-/// doesn't correctly reject negative numbers when compiled with SunStudio.
-///
-/// \exception StringTokenError if the value is out of range, or if it
-/// could not be converted
-///
-/// \param num_token the string token to convert
-///
-/// \return the converted value, of type NumType
-template <typename NumType, int BitSize>
-NumType
-tokenToNum(const std::string& num_token) {
- NumType num;
- try {
- num = boost::lexical_cast<NumType>(num_token);
- } catch (const boost::bad_lexical_cast& ex) {
- isc_throw(StringTokenError, "Invalid SRV numeric parameter: " <<
- num_token);
- }
- if (num < 0 || num >= (static_cast<NumType>(1) << BitSize)) {
- isc_throw(StringTokenError, "Numeric SRV parameter out of range: " <<
- num);
- }
- return (num);
-}
-
} // namespace str
} // namespace util
} // namespace isc
diff --git a/src/lib/util/tests/strutil_unittest.cc b/src/lib/util/tests/strutil_unittest.cc
index 74bc17d..cd3a9ca 100644
--- a/src/lib/util/tests/strutil_unittest.cc
+++ b/src/lib/util/tests/strutil_unittest.cc
@@ -12,8 +12,6 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <stdint.h>
-
#include <string>
#include <gtest/gtest.h>
@@ -24,9 +22,17 @@ using namespace isc;
using namespace isc::util;
using namespace std;
+class StringUtilTest : public ::testing::Test {
+protected:
+ StringUtilTest()
+ {
+ }
+};
+
+
// Check for slash replacement
-TEST(StringUtilTest, Slash) {
+TEST_F(StringUtilTest, Slash) {
string instring = "";
isc::util::str::normalizeSlash(instring);
@@ -43,7 +49,7 @@ TEST(StringUtilTest, Slash) {
// Check that leading and trailing space trimming works
-TEST(StringUtilTest, Trim) {
+TEST_F(StringUtilTest, Trim) {
// Empty and full string.
EXPECT_EQ("", isc::util::str::trim(""));
@@ -65,7 +71,7 @@ TEST(StringUtilTest, Trim) {
// returned vector; if not as expected, the following references may be invalid
// so should not be used.
-TEST(StringUtilTest, Tokens) {
+TEST_F(StringUtilTest, Tokens) {
vector<string> result;
// Default delimiters
@@ -151,7 +157,7 @@ TEST(StringUtilTest, Tokens) {
// Changing case
-TEST(StringUtilTest, ChangeCase) {
+TEST_F(StringUtilTest, ChangeCase) {
string mixed("abcDEFghiJKLmno123[]{=+--+]}");
string upper("ABCDEFGHIJKLMNO123[]{=+--+]}");
string lower("abcdefghijklmno123[]{=+--+]}");
@@ -167,7 +173,7 @@ TEST(StringUtilTest, ChangeCase) {
// Formatting
-TEST(StringUtilTest, Formatting) {
+TEST_F(StringUtilTest, Formatting) {
vector<string> args;
args.push_back("arg1");
@@ -207,63 +213,3 @@ TEST(StringUtilTest, Formatting) {
string format9 = "%s %s";
EXPECT_EQ(format9, isc::util::str::format(format9, args));
}
-
-TEST(StringUtilTest, getToken) {
- string s("a b c");
- istringstream ss(s);
- EXPECT_EQ("a", isc::util::str::getToken(ss));
- EXPECT_EQ("b", isc::util::str::getToken(ss));
- EXPECT_EQ("c", isc::util::str::getToken(ss));
- EXPECT_THROW(isc::util::str::getToken(ss), isc::util::str::StringTokenError);
-}
-
-int32_t tokenToNumCall_32_16(const string& token) {
- return isc::util::str::tokenToNum<int32_t, 16>(token);
-}
-
-int16_t tokenToNumCall_16_8(const string& token) {
- return isc::util::str::tokenToNum<int16_t, 8>(token);
-}
-
-TEST(StringUtilTest, tokenToNum) {
- uint32_t num32 = tokenToNumCall_32_16("0");
- EXPECT_EQ(0, num32);
- num32 = tokenToNumCall_32_16("123");
- EXPECT_EQ(123, num32);
- num32 = tokenToNumCall_32_16("65535");
- EXPECT_EQ(65535, num32);
-
- EXPECT_THROW(tokenToNumCall_32_16(""),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_32_16("a"),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_32_16("-1"),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_32_16("65536"),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_32_16("1234567890"),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_32_16("-1234567890"),
- isc::util::str::StringTokenError);
-
- uint16_t num16 = tokenToNumCall_16_8("123");
- EXPECT_EQ(123, num16);
- num16 = tokenToNumCall_16_8("0");
- EXPECT_EQ(0, num16);
- num16 = tokenToNumCall_16_8("255");
- EXPECT_EQ(255, num16);
-
- EXPECT_THROW(tokenToNumCall_16_8(""),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_16_8("a"),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_16_8("-1"),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_16_8("256"),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_16_8("1234567890"),
- isc::util::str::StringTokenError);
- EXPECT_THROW(tokenToNumCall_16_8("-1234567890"),
- isc::util::str::StringTokenError);
-
-}
More information about the bind10-changes
mailing list