Browse Source

sync with trunk for merge

git-svn-id: svn://bind10.isc.org/svn/bind10/experiments/python-binding@2346 e5f2f494-b856-4b98-b285-d166d9295462
Jelte Jansen 15 years ago
parent
commit
7cdceb252e
100 changed files with 1830 additions and 916 deletions
  1. 69 3
      ChangeLog
  2. 47 13
      configure.ac
  3. 6 3
      src/bin/auth/Makefile.am
  4. 8 1
      src/bin/auth/asio_link.cc
  5. 1 1
      src/bin/auth/asio_link.h
  6. 16 2
      src/bin/auth/auth_srv.cc
  7. 2 2
      src/bin/auth/main.cc
  8. 2 2
      src/bin/auth/tests/Makefile.am
  9. 109 29
      src/bin/bind10/bind10.py.in
  10. 134 0
      src/bin/bind10/tests/args_test.py
  11. 2 1
      src/bin/bind10/tests/bind10_test.in
  12. 1 1
      src/bin/bindctl/bindcmd.py
  13. 3 1
      src/bin/cfgmgr/Makefile.am
  14. 7 1
      src/bin/cfgmgr/b10-cfgmgr.py.in
  15. 13 0
      src/bin/cfgmgr/tests/Makefile.am
  16. 95 0
      src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
  17. 1 1
      src/bin/cmdctl/cmdctl.py.in
  18. 1 1
      src/bin/host/Makefile.am
  19. 2 0
      src/bin/host/host.cc
  20. 26 20
      src/bin/loadzone/Makefile.am
  21. 16 6
      src/bin/loadzone/b10-loadzone.py.in
  22. 25 0
      src/bin/loadzone/tests/correct/Makefile.am
  23. 75 0
      src/bin/loadzone/tests/correct/correct_test.sh.in
  24. 14 0
      src/bin/loadzone/tests/correct/example.db
  25. 8 0
      src/bin/loadzone/tests/correct/get_zonedatas.py
  26. 4 0
      src/bin/loadzone/tests/correct/inclsub.db
  27. 23 0
      src/bin/loadzone/tests/correct/include.db
  28. 79 0
      src/bin/loadzone/tests/correct/known.test.out
  29. 21 0
      src/bin/loadzone/tests/correct/mix1.db
  30. 3 0
      src/bin/loadzone/tests/correct/mix1sub1.db
  31. 3 0
      src/bin/loadzone/tests/correct/mix1sub2.db
  32. 21 0
      src/bin/loadzone/tests/correct/mix2.db
  33. 3 0
      src/bin/loadzone/tests/correct/mix2sub1.txt
  34. 3 0
      src/bin/loadzone/tests/correct/mix2sub2.txt
  35. 17 0
      src/bin/loadzone/tests/correct/ttl1.db
  36. 17 0
      src/bin/loadzone/tests/correct/ttl2.db
  37. 18 0
      src/bin/loadzone/tests/correct/ttlext.db
  38. 25 0
      src/bin/loadzone/tests/error/Makefile.am
  39. 11 0
      src/bin/loadzone/tests/error/error.known
  40. 82 0
      src/bin/loadzone/tests/error/error_test.sh.in
  41. 13 0
      src/bin/loadzone/tests/error/formerr1.db
  42. 12 0
      src/bin/loadzone/tests/error/formerr2.db
  43. 12 0
      src/bin/loadzone/tests/error/formerr3.db
  44. 12 0
      src/bin/loadzone/tests/error/formerr4.db
  45. 13 0
      src/bin/loadzone/tests/error/formerr5.db
  46. 1 0
      src/bin/loadzone/tests/error/include.txt
  47. 12 0
      src/bin/loadzone/tests/error/keyerror1.db
  48. 12 0
      src/bin/loadzone/tests/error/keyerror2.db
  49. 13 0
      src/bin/loadzone/tests/error/keyerror3.db
  50. 11 0
      src/bin/loadzone/tests/error/originerr1.db
  51. 12 0
      src/bin/loadzone/tests/error/originerr2.db
  52. 0 0
      src/bin/loadzone/tests/normal/Kexample.com.+005+04456.key
  53. 0 0
      src/bin/loadzone/tests/normal/Kexample.com.+005+04456.private
  54. 0 0
      src/bin/loadzone/tests/normal/Kexample.com.+005+33495.key
  55. 0 0
      src/bin/loadzone/tests/normal/Kexample.com.+005+33495.private
  56. 0 0
      src/bin/loadzone/tests/normal/Ksql1.example.com.+005+12447.key
  57. 0 0
      src/bin/loadzone/tests/normal/Ksql1.example.com.+005+12447.private
  58. 0 0
      src/bin/loadzone/tests/normal/Ksql1.example.com.+005+33313.key
  59. 0 0
      src/bin/loadzone/tests/normal/Ksql1.example.com.+005+33313.private
  60. 0 0
      src/bin/loadzone/tests/normal/Ksql2.example.com.+005+38482.key
  61. 0 0
      src/bin/loadzone/tests/normal/Ksql2.example.com.+005+38482.private
  62. 0 0
      src/bin/loadzone/tests/normal/Ksql2.example.com.+005+63192.key
  63. 0 0
      src/bin/loadzone/tests/normal/Ksql2.example.com.+005+63192.private
  64. 0 0
      src/bin/loadzone/tests/normal/README
  65. 0 0
      src/bin/loadzone/tests/normal/dsset-subzone.example.com
  66. 0 0
      src/bin/loadzone/tests/normal/example.com
  67. 0 0
      src/bin/loadzone/tests/normal/example.com.signed
  68. 0 0
      src/bin/loadzone/tests/normal/sql1.example.com
  69. 0 0
      src/bin/loadzone/tests/normal/sql1.example.com.signed
  70. 0 0
      src/bin/loadzone/tests/normal/sql2.example.com
  71. 0 0
      src/bin/loadzone/tests/normal/sql2.example.com.signed
  72. 1 1
      src/bin/xfrin/tests/Makefile.am
  73. 15 1
      src/bin/xfrin/xfrin.py.in
  74. 1 1
      src/bin/xfrout/tests/Makefile.am
  75. 16 8
      src/bin/xfrout/tests/xfrout_test.py
  76. 70 47
      src/bin/xfrout/xfrout.py.in
  77. 31 1
      src/bin/xfrout/xfrout.spec.pre.in
  78. 6 4
      src/lib/cc/Makefile.am
  79. 11 4
      src/lib/cc/session.cc
  80. 4 1
      src/lib/cc/session_unittests.cc
  81. 5 0
      src/lib/config/tests/Makefile.am
  82. 21 19
      src/lib/datasrc/data_source.cc
  83. 2 4
      src/lib/datasrc/sqlite3_datasrc.cc
  84. 2 2
      src/lib/datasrc/tests/Makefile.am
  85. 30 4
      src/lib/datasrc/tests/datasrc_unittest.cc
  86. 431 667
      src/lib/datasrc/tests/test_datasrc.cc
  87. 1 0
      src/lib/datasrc/tests/test_datasrc.h
  88. 1 0
      src/lib/datasrc/tests/testdata/example.org
  89. BIN
      src/lib/datasrc/tests/testdata/example.org.sqlite3
  90. 24 46
      src/lib/dns/Makefile.am
  91. 1 1
      src/lib/dns/message.cc
  92. 1 1
      src/lib/dns/name.cc
  93. 13 8
      src/lib/dns/python/Makefile.am
  94. 1 1
      src/lib/dns/python/tests/Makefile.am
  95. 2 4
      src/lib/dns/rrsetlist.cc
  96. 1 1
      src/lib/dns/rrsetlist.h
  97. 1 1
      src/lib/dns/tests/Makefile.am
  98. 1 1
      src/lib/python/isc/Makefile.am
  99. 1 0
      src/lib/python/isc/__init__.py
  100. 0 0
      src/lib/python/isc/datasrc/master.py

+ 69 - 3
ChangeLog

@@ -1,11 +1,73 @@
-  53.   [bug]      zhanglikun
+  65.  [func]       shentingting
+    Added verbose options to exactly what is happening with loadzone.
+	Added loadzone test suite of different file formats to load.
+	(Trac #197, #199, #244, #161, #198, #174, #175, svn r2340)
+
+  64.  [func]       jerry
+    Added python logging framework. It is for testing and experimenting
+	with logging ideas. Currently, it supports three channels(file, 
+	syslog and stderr) and five levels(debug, info, warning, error and
+	critical).
+	(Trac #176, svn r2338)
+
+  63.  [func]       shane
+    Added initial support for setuid(), using the "-u" flag. This will
+    be replaced in the future, but for now provides a reasonable 
+    starting point.
+    (Trac #180, svn r2330)
+
+  62.  [func]		jelte
+	bin/xfrin: Use the database_file as configured in Auth to transfers
+	bin/xfrout: Use the database_file as configured in Auth to transfers
+
+  61.  [bug]		jelte
+	bin/auth: Enable b10-auth to be launched in source tree
+	(i.e. use a zone database file relative to that)
+
+  60.	[build]		jinmei
+	Supported SunStudio C++ compiler.  Note: gtest still doesn't work.
+	(Trac #251, svn r2310)
+
+  59.	[bug]		jinmei
+	lib/datasrc,bin/auth: The authoritative server could return a
+	SERVFAIL with a partial answer if it finds a data source broken
+	while looking for an answer.  This can happen, for example, if a
+	zone that doesn't have an NS RR is configured and loaded as a
+	sqlite3 data source. (Trac #249, r2286)
+
+  58.	[bug]		jinmei
+	Worked around an interaction issue between ASIO and standard C++
+	library headers.  Without this ASIO didn't work: sometimes the
+	application crashes, sometimes it blocked in the ASIO module.
+	(Trac #248, svn r2187, r2190)
+
+  57.	[func]		jinmei
+	lib/datasrc: used a simpler version of Name::split (change 31) for
+	better readability.  No behavior change. (Trac #200, svn r2159)
+
+  56.	[func]*		jinmei
+	lib/dns: renamed the library name to libdns++ to avoid confusion
+	with the same name of library of BIND 9.
+	(Trac #190, svn r2153)
+
+  55.	[bug]		shane
+	bin/xfrout: xfrout exception on Ctrl-C now no longer generates
+	exception for 'Interrupted system call'
+	(Track #136, svn r2147)
+
+  54.	[bug]		zhanglikun
+	bin/xfrout: Enable b10-xfrout can be launched in source
+	code tree.
+	(Trac #224, svn r2103)
+
+  53.	[bug]		zhanglikun
 	bin/bindctl: Generate a unique session ID by using 
 	socket.gethostname() instead of socket.gethostbyname(), 
 	since the latter one could make bindctl	stall if its own 
 	host name can't be resolved.
 	(Trac #228, svn r2096)
 
-  52.   [func]      zhanglikun
+  52.	[func]		zhanglikun
 	bin/xfrout: When xfrout is launched, check whether the
 	socket file is being used by one running xfrout process, 
 	if it is, exit from python.	If the file isn't a socket file 
@@ -67,6 +129,10 @@ bind10-devel-20100602 released on June 2, 2010
 	Renamed libauth to libdatasrc.
 
   38.   [bug]           zhanglikun
+	Send command 'shutdown' to Xfrin and Xfrout when boss receive SIGINT.
+	Remove unused socket file when Xfrout process exits. Make sure Xfrout
+	exit by itself when it receives SIGINT, instead of being killed by the
+	signal SIGTERM or SIGKILL sent from boss.
 	(Trac #135, #151, #134, svn r1797)
 
   37.   [build]         jinmei
@@ -127,7 +193,7 @@ bind10-devel-20100421 released on April 21, 2010
 
   24.	[func]
 	Support case-sensitive name compression in MessageRenderer.
-	(svn r1704)
+	(Trac #142, svn r1704)
 
   23.	[func]
 	Support a simple name with possible compression. (svn r1701)

+ 47 - 13
configure.ac

@@ -9,11 +9,23 @@ AC_CONFIG_HEADERS([config.h])
 
 # Checks for programs.
 AC_PROG_CXX
-AC_PROG_CC
 AC_PROG_LIBTOOL
 
 # Use C++ language
-AC_LANG_CPLUSPLUS
+AC_LANG([C++])
+
+# Identify the compiler: this check must be after AC_PROG_CXX and AC_LANG.
+AM_CONDITIONAL(USE_GXX, test "X${GXX}" = "Xyes")
+AC_CHECK_DECL([__SUNPRO_CC], [SUNCXX="yes"], [SUNCXX="no"])
+
+# OS dependent compiler flags
+case "$host" in
+*-solaris*)
+	# Solaris requires special definitions to get some standard libraries
+	# (e.g. getopt(3)) available with common used header files.
+	CPPFLAGS="$CPPFLAGS -D_XPG4_2 -D__EXTENSIONS__"
+	;;
+esac
 
 m4_define([_AM_PYTHON_INTERPRETER_LIST], [python python3 python3.1])
 AC_ARG_WITH([pythonpath],
@@ -93,8 +105,8 @@ AC_SUBST(PYTHON_LIB)
 
 # TODO: check for _sqlite3.py module
 
-#
-# B10_CXXFLAGS is the default C++ compiler flags.  This will (and should) be
+# Compiler dependent settings: define some mandatory CXXFLAGS here.
+# We also use a separate variable B10_CXXFLAGS.  This will (and should) be
 # used as the default value for each specifc AM_CXXFLAGS:
 # AM_CXXFLAGS = $(B10_CXXFLAGS)
 # AM_CXXFLAGS += ... # add module specific flags
@@ -103,17 +115,24 @@ AC_SUBST(PYTHON_LIB)
 # gcc's -Wno-XXX option must be specified after -Wall or -Wextra, we cannot
 # specify the default warning flags in CXXFLAGS and let specific modules
 # "override" the default.
-#
-B10_CXXFLAGS=
 
-if test "X$GCC" = "Xyes"; then
-B10_CXXFLAGS="-g -Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
+CXXFLAGS=-g
+werror_ok=0
+
+# SunStudio compiler requires special compiler options for boost
+# (http://blogs.sun.com/sga/entry/boost_mini_howto)
+if test "$SUNCXX" = "yes"; then
+CXXFLAGS="$CXXFLAGS -library=stlport4 -features=tmplife -features=tmplrefstatic"
+fi
+
+# gcc specific settings:
+if test "X$GXX" = "Xyes"; then
+B10_CXXFLAGS="-Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
 UNUSED_PARAM_ATTRIBUTE='__attribute__((unused))'
 
 # Certain versions of gcc (g++) have a bug that incorrectly warns about
 # the use of anonymous name spaces even if they're closed in a single
 # translation unit.  For these versions we have to disable -Werror.
-werror_ok=0
 CXXFLAGS_SAVED="$CXXFLAGS"
 CXXFLAGS="$CXXFLAGS $B10_CXXFLAGS -Werror"
 AC_MSG_CHECKING(for in-TU anonymous namespace breakage)
@@ -124,13 +143,13 @@ namespace isc {class Bar {Foo foo_;};} ],,
 	 B10_CXXFLAGS="$B10_CXXFLAGS -Werror"],
 	[AC_MSG_RESULT(yes)])
 CXXFLAGS="$CXXFLAGS_SAVED"
-fi				dnl GCC = yes
+fi				dnl GXX = yes
 
 AM_CONDITIONAL(GCC_WERROR_OK, test $werror_ok = 1)
 AC_DEFINE_UNQUOTED(UNUSED_PARAM, $UNUSED_PARAM_ATTRIBUTE, Define to compiler keyword indicating a function argument is intentionally unused)
 
 # produce PIC unless we disable shared libraries. need this for python bindings.
-if test $enable_shared != "no" -a "X$GCC" = "Xyes"; then
+if test $enable_shared != "no" -a "X$GXX" = "Xyes"; then
    B10_CXXFLAGS="$B10_CXXFLAGS -fPIC"
 fi
 
@@ -270,6 +289,11 @@ AC_SUBST(GTEST_INCLUDES)
 AC_SUBST(GTEST_LDFLAGS)
 AC_SUBST(GTEST_LDADD)
 
+dnl check for pkg-config itself so we don't try the m4 macro without pkg-config
+AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes, no)
+if test "x$HAVE_PKG_CONFIG" = "xno" ; then
+  AC_MSG_ERROR(Please install pkg-config)
+fi
 PKG_CHECK_MODULES(SQLITE, sqlite3 >= 3.3.9, enable_features="$enable_features SQLite3")
 
 # I can't get some of the #include <asio.hpp> right without this
@@ -319,7 +343,7 @@ fi
 # run time performance.  Hpefully we can find a better solution or the ASIO
 # code will be updated by the time we really need it.
 AC_CHECK_HEADERS(sys/devpoll.h, ac_cv_have_devpoll=yes, ac_cv_have_devpoll=no)
-if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GCC" = "Xyes"; then
+if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GXX" = "Xyes"; then
 	CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_DEV_POLL=1"
 fi
 
@@ -348,8 +372,11 @@ AC_CONFIG_FILES([Makefile
                  src/bin/bindctl/Makefile
                  src/bin/bindctl/tests/Makefile
                  src/bin/cfgmgr/Makefile
+                 src/bin/cfgmgr/tests/Makefile
                  src/bin/host/Makefile
                  src/bin/loadzone/Makefile
+                 src/bin/loadzone/tests/correct/Makefile
+                 src/bin/loadzone/tests/error/Makefile
                  src/bin/msgq/Makefile
                  src/bin/msgq/tests/Makefile
                  src/bin/auth/Makefile
@@ -368,6 +395,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/python/isc/cc/tests/Makefile
                  src/lib/python/isc/config/Makefile
                  src/lib/python/isc/config/tests/Makefile
+                 src/lib/python/isc/log/Makefile
+                 src/lib/python/isc/log/tests/Makefile
                  src/lib/config/Makefile
                  src/lib/config/tests/Makefile
                  src/lib/dns/Makefile
@@ -380,6 +409,7 @@ AC_CONFIG_FILES([Makefile
                  src/lib/xfr/Makefile
                ])
 AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
+           src/bin/cfgmgr/tests/b10-cfgmgr_test.py
            src/bin/cmdctl/cmdctl.py
            src/bin/cmdctl/run_b10-cmdctl.sh
            src/bin/cmdctl/tests/cmdctl_test
@@ -398,6 +428,8 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            src/bin/bindctl/bindctl-source.py
            src/bin/bindctl/tests/bindctl_test
            src/bin/loadzone/run_loadzone.sh
+           src/bin/loadzone/tests/correct/correct_test.sh
+           src/bin/loadzone/tests/error/error_test.sh
            src/bin/loadzone/b10-loadzone.py
            src/bin/usermgr/run_b10-cmdctl-usermgr.sh
            src/bin/usermgr/b10-cmdctl-usermgr.py
@@ -409,7 +441,7 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            src/lib/config/tests/data_def_unittests_config.h
            src/lib/python/isc/config/tests/config_test
            src/lib/python/isc/cc/tests/cc_test
-           src/lib/dns/python/tests/libdns_python_test
+           src/lib/python/isc/log/tests/log_test
            src/lib/dns/gen-rdatacode.py
            src/lib/python/bind10_config.py
            src/lib/dns/tests/testdata/gen-wiredata.py
@@ -425,6 +457,8 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            chmod +x src/bin/bindctl/tests/bindctl_test
            chmod +x src/bin/bindctl/run_bindctl.sh
            chmod +x src/bin/loadzone/run_loadzone.sh
+           chmod +x src/bin/loadzone/tests/correct/correct_test.sh
+           chmod +x src/bin/loadzone/tests/error/error_test.sh
            chmod +x src/bin/usermgr/run_b10-cmdctl-usermgr.sh
            chmod +x src/bin/msgq/run_msgq.sh
            chmod +x src/bin/msgq/tests/msgq_test

+ 6 - 3
src/bin/auth/Makefile.am

@@ -36,7 +36,10 @@ lib_LIBRARIES = libasio_link.a
 libasio_link_a_SOURCES = asio_link.cc asio_link.h
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # B10_CXXFLAGS)
-libasio_link_a_CXXFLAGS = $(AM_CXXFLAGS) -Wno-unused-parameter
+libasio_link_a_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_GXX
+libasio_link_a_CXXFLAGS += -Wno-unused-parameter
+endif
 libasio_link_a_CPPFLAGS = $(AM_CPPFLAGS)
 
 BUILT_SOURCES = spec_config.h 
@@ -45,9 +48,9 @@ b10_auth_SOURCES = auth_srv.cc auth_srv.h
 b10_auth_SOURCES += common.h
 b10_auth_SOURCES += main.cc
 b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a
-b10_auth_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a
+b10_auth_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
 b10_auth_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
-b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.a
+b10_auth_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
 b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 b10_auth_LDADD += $(top_builddir)/src/bin/auth/libasio_link.a
 b10_auth_LDADD += $(SQLITE_LIBS)

+ 8 - 1
src/bin/auth/asio_link.cc

@@ -16,6 +16,7 @@
 
 #include <config.h>
 
+#include <unistd.h>             // for some IPC/network system calls
 #include <asio.hpp>
 #include <boost/bind.hpp>
 
@@ -66,7 +67,13 @@ void
 dispatch_axfr_query(const int tcp_sock, char const axfr_query[],
                     const uint16_t query_len)
 {
-    string path(UNIX_SOCKET_FILE);
+    string path;
+    if (getenv("B10_FROM_BUILD")) {
+        path = string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn";
+    } else {
+        path = UNIX_SOCKET_FILE;
+    }
+    
     if (getenv("B10_FROM_BUILD")) {
         path = string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn";
     }

+ 1 - 1
src/bin/auth/asio_link.h

@@ -24,7 +24,7 @@ struct IOServiceImpl;
 
 class IOService {
 public:
-    IOService(AuthSrv* auth_server, const char* port,
+    IOService(AuthSrv* auth_server, const char* const port,
               const bool use_ipv4, const bool use_ipv6);
     ~IOService();
     void run();

+ 16 - 2
src/bin/auth/auth_srv.cc

@@ -243,7 +243,8 @@ AuthSrv::processMessage(InputBuffer& request_buffer, Message& message,
         impl_->data_sources_.doQuery(query);
     } catch (const Exception& ex) {
         if (impl_->verbose_mode_) {
-            cerr << "[b10-auth] Internal error, returning SERVFAIL: " << ex.what() << endl;
+            cerr << "[b10-auth] Internal error, returning SERVFAIL: " <<
+                ex.what() << endl;
         }
         makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
                          impl_->verbose_mode_);
@@ -273,9 +274,22 @@ AuthSrvImpl::setDbFile(const isc::data::ElementPtr config) {
         bool is_default;
         string item("database_file");
         ElementPtr value = cs_->getValue(is_default, item);
-        db_file_ = value->stringValue();
         final = Element::createFromString("{}");
+
+        // If the value is the default, and we are running from
+        // a specific directory ('from build'), we need to use
+        // a different value than the default (which may not exist)
+        // (btw, this should not be done here in the end, i think
+        //  the from-source script should have a check for this,
+        //  but for that we need offline access to config, so for
+        //  now this is a decent solution)
+        if (is_default && getenv("B10_FROM_BUILD")) {
+            value = Element::create(string(getenv("B10_FROM_BUILD")) +
+                                    "/bind10_zones.sqlite3");
+        }
         final->set(item, value);
+
+        db_file_ = value->stringValue();
     } else {
         return (answer);
     }

+ 2 - 2
src/bin/auth/main.cc

@@ -148,12 +148,12 @@ main(int argc, char* argv[]) {
         io_service = new asio_link::IOService(auth_server, port, use_ipv4,
                                               use_ipv6);
 
-        ModuleCCSession cs(specfile, io_service->get_io_service(), my_config_handler, my_command_handler);
+        ModuleCCSession cs(specfile, io_service->get_io_service(),
+                           my_config_handler, my_command_handler);
 
         auth_server->setConfigSession(&cs);
         auth_server->updateConfig(ElementPtr());
 
-        
         cout << "[b10-auth] Server started." << endl;
         io_service->run();
     } catch (const std::exception& ex) {

+ 2 - 2
src/bin/auth/tests/Makefile.am

@@ -20,9 +20,9 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
 run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a
-run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns.a
+run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns++.a
 run_unittests_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 endif
 

+ 109 - 29
src/bin/bind10/bind10.py.in

@@ -57,6 +57,9 @@ import time
 import select
 import random
 from optparse import OptionParser, OptionValueError
+import io
+import pwd
+import posix
 
 import isc.cc
 
@@ -108,21 +111,38 @@ to avoid being restarted at exactly 10 seconds."""
             when = time.time()
         return max(when, self.restart_time)
 
+class ProcessInfoError(Exception): pass
+
 class ProcessInfo:
     """Information about a process"""
 
     dev_null = open(os.devnull, "w")
 
     def __init__(self, name, args, env={}, dev_null_stdout=False,
-                 dev_null_stderr=False):
+                 dev_null_stderr=False, uid=None, username=None):
         self.name = name 
         self.args = args
         self.env = env
         self.dev_null_stdout = dev_null_stdout
         self.dev_null_stderr = dev_null_stderr
         self.restart_schedule = RestartSchedule()
+        self.uid = uid
+        self.username = username
         self._spawn()
 
+    def _setuid(self):
+        """Function used before running a program that needs to run as a
+        different user."""
+        if self.uid is not None:
+            try:
+                posix.setuid(self.uid)
+            except OSError as e:
+                if e.errno == errno.EPERM:
+                    # if we failed to change user due to permission report that
+                    raise ProcessInfoError("Unable to change to user %s (uid %d)" % (self.username, self.uid))
+                else:
+                    # otherwise simply re-raise whatever error we found
+                    raise
 
     def _spawn(self):
         if self.dev_null_stdout:
@@ -138,14 +158,15 @@ class ProcessInfo:
         # on construction (self.env).
         spawn_env = os.environ
         spawn_env.update(self.env)
-        if not 'B10_FROM_SOURCE' in os.environ:
+        if 'B10_FROM_SOURCE' not in os.environ:
             spawn_env['PATH'] = "@@LIBEXECDIR@@:" + spawn_env['PATH']
         self.process = subprocess.Popen(self.args,
                                         stdin=subprocess.PIPE,
                                         stdout=spawn_stdout,
                                         stderr=spawn_stderr,
                                         close_fds=True,
-                                        env=spawn_env,)
+                                        env=spawn_env,
+                                        preexec_fn=self._setuid)
         self.pid = self.process.pid
         self.restart_schedule.set_run_start_time()
 
@@ -155,7 +176,8 @@ class ProcessInfo:
 class BoB:
     """Boss of BIND class."""
     
-    def __init__(self, msgq_socket_file=None, auth_port=5300, verbose=False):
+    def __init__(self, msgq_socket_file=None, auth_port=5300, verbose=False,
+                 setuid=None, username=None):
         """Initialize the Boss of BIND. This is a singleton (only one
         can run).
         
@@ -171,6 +193,8 @@ class BoB:
         self.processes = {}
         self.dead_processes = {}
         self.runnable = False
+        self.uid = setuid
+        self.username = username
 
     def config_handler(self, new_config):
         if self.verbose:
@@ -225,12 +249,14 @@ class BoB:
                 sys.stdout.write("[bind10] Starting b10-msgq\n")
         try:
             c_channel = ProcessInfo("b10-msgq", ["b10-msgq"], c_channel_env,
-                                    True, not self.verbose)
+                                    True, not self.verbose, uid=self.uid,
+                                    username=self.username)
         except Exception as e:
             return "Unable to start b10-msgq; " + str(e)
         self.processes[c_channel.pid] = c_channel
         if self.verbose:
-            sys.stdout.write("[bind10] Started b10-msgq (PID %d)\n" % c_channel.pid)
+            sys.stdout.write("[bind10] Started b10-msgq (PID %d)\n" % 
+                             c_channel.pid)
 
         # now connect to the c-channel
         cc_connect_start = time.time()
@@ -250,7 +276,8 @@ class BoB:
             sys.stdout.write("[bind10] Starting b10-cfgmgr\n")
         try:
             bind_cfgd = ProcessInfo("b10-cfgmgr", ["b10-cfgmgr"],
-                                    c_channel_env)
+                                    c_channel_env, uid=self.uid,
+                                    username=self.username)
         except Exception as e:
             c_channel.process.kill()
             return "Unable to start b10-cfgmgr; " + str(e)
@@ -272,23 +299,6 @@ class BoB:
         if self.verbose:
             sys.stdout.write("[bind10] ccsession started\n")
 
-        # start the xfrout before auth-server, to make sure every xfr-query can
-        # be processed properly.
-        xfrout_args = ['b10-xfrout']
-        if self.verbose:
-            sys.stdout.write("[bind10] Starting b10-xfrout\n")
-            xfrout_args += ['-v']
-        try:
-            xfrout = ProcessInfo("b10-xfrout", xfrout_args, 
-                                 c_channel_env )
-        except Exception as e:
-            c_channel.process.kill()
-            bind_cfgd.process.kill()
-            return "Unable to start b10-xfrout; " + str(e)
-        self.processes[xfrout.pid] = xfrout
-        if self.verbose:
-            sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % xfrout.pid)
-
         # start b10-auth
         # XXX: this must be read from the configuration manager in the future
         authargs = ['b10-auth', '-p', str(self.auth_port)]
@@ -308,6 +318,28 @@ class BoB:
         if self.verbose:
             sys.stdout.write("[bind10] Started b10-auth (PID %d)\n" % auth.pid)
 
+        # everything after the authoritative server can run as non-root
+        if self.uid is not None:
+            posix.setuid(self.uid)
+
+        # start the xfrout before auth-server, to make sure every xfr-query can
+        # be processed properly.
+        xfrout_args = ['b10-xfrout']
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-xfrout\n")
+            xfrout_args += ['-v']
+        try:
+            xfrout = ProcessInfo("b10-xfrout", xfrout_args, 
+                                 c_channel_env )
+        except Exception as e:
+            c_channel.process.kill()
+            bind_cfgd.process.kill()
+            return "Unable to start b10-xfrout; " + str(e)
+        self.processes[xfrout.pid] = xfrout
+        if self.verbose:
+            sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % 
+                             xfrout.pid)
+
         # start b10-xfrin
         xfrin_args = ['b10-xfrin']
         if self.verbose:
@@ -324,7 +356,8 @@ class BoB:
             return "Unable to start b10-xfrin; " + str(e)
         self.processes[xfrind.pid] = xfrind
         if self.verbose:
-            sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % xfrind.pid)
+            sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % 
+                             xfrind.pid)
 
         # start the b10-cmdctl
         # XXX: we hardcode port 8080
@@ -344,7 +377,8 @@ class BoB:
             return "Unable to start b10-cmdctl; " + str(e)
         self.processes[cmd_ctrld.pid] = cmd_ctrld
         if self.verbose:
-            sys.stdout.write("[bind10] Started b10-cmdctl (PID %d)\n" % cmd_ctrld.pid)
+            sys.stdout.write("[bind10] Started b10-cmdctl (PID %d)\n" % 
+                             cmd_ctrld.pid)
 
         self.runnable = True
 
@@ -435,11 +469,16 @@ class BoB:
                 sys.stdout.write("[bind10] Unknown child pid %d exited.\n" % pid)
 
     def restart_processes(self):
-        """Restart any dead processes."""
+        """Restart any dead processes.
+        Returns the time when the next process is ready to be restarted. 
+          If the server is shutting down, returns 0.
+          If there are no processes, returns None.
+        The values returned can be safely passed into select() as the 
+        timeout value."""
         next_restart = None
         # if we're shutting down, then don't restart
         if not self.runnable:
-            return next_restart
+            return 0
         # otherwise look through each dead process and try to restart
         still_dead = {}
         now = time.time()
@@ -510,6 +549,10 @@ def check_port(option, opt_str, value, parser):
 def main():
     global options
     global boss_of_bind
+    # Enforce line buffering on stdout, even when not a TTY
+    sys.stdout = io.TextIOWrapper(sys.stdout.detach(), line_buffering=True)
+
+
     # Parse any command-line options.
     parser = OptionParser(version=__version__)
     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
@@ -520,7 +563,42 @@ def main():
     parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
                       type="string", default=None,
                       help="UNIX domain socket file the b10-msgq daemon will use")
+    parser.add_option("-u", "--user", dest="user",
+                      type="string", default=None,
+                      help="Change user after startup (must run as root)")
     (options, args) = parser.parse_args()
+    if args:
+        parser.print_help()
+        sys.exit(1)
+
+    # Check user ID.
+    setuid = None
+    username = None
+    if options.user:
+        # Try getting information about the user, assuming UID passed.
+        try:
+            pw_ent = pwd.getpwuid(int(options.user))
+            setuid = pw_ent.pw_uid
+            username = pw_ent.pw_name
+        except ValueError:
+            pass
+        except KeyError:
+            pass
+
+        # Next try getting information about the user, assuming user name 
+        # passed.
+        # If the information is both a valid user name and user number, we
+        # prefer the name because we try it second. A minor point, hopefully.
+        try:
+            pw_ent = pwd.getpwnam(options.user)
+            setuid = pw_ent.pw_uid
+            username = pw_ent.pw_name
+        except KeyError:
+            pass
+
+        if setuid is None:
+            sys.stderr.write("bind10: invalid user: '%s'\n" % options.user)
+            sys.exit(1)
 
     # Announce startup.
     if options.verbose:
@@ -543,11 +621,12 @@ def main():
 
     # Go bob!
     boss_of_bind = BoB(options.msgq_socket_file, int(options.auth_port),
-                       options.verbose)
+                       options.verbose, setuid, username)
     startup_result = boss_of_bind.startup()
     if startup_result:
         sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
         sys.exit(1)
+    sys.stdout.write("[bind10] BIND 10 started\n")
 
     # In our main loop, we check for dead processes or messages 
     # on the c-channel.
@@ -584,6 +663,7 @@ def main():
     # shutdown
     signal.signal(signal.SIGCHLD, signal.SIG_DFL)
     boss_of_bind.shutdown()
+    sys.exit(0)
 
 if __name__ == "__main__":
     main()

+ 134 - 0
src/bin/bind10/tests/args_test.py

@@ -0,0 +1,134 @@
+"""
+This program tests the boss process to make sure that it runs while
+dropping permissions. It must be run as a user that can set permission.
+"""
+import unittest
+import os
+import sys
+import subprocess
+import select
+import time
+import pwd
+
+# Set to a valid user name on the system to run setuid() test
+#SUID_USER=None
+SUID_USER="shane"
+
+BIND10_EXE="../run_bind10.sh"
+TIMEOUT=3
+
+class TestBossArgs(unittest.TestCase):
+    def _waitForString(self, bob, s):
+        found_string = False
+        start_time = time.time()
+        while time.time() < start_time + TIMEOUT:
+            (r,w,x) = select.select((bob.stdout,), (), (), TIMEOUT) 
+            if bob.stdout in r:
+                s = bob.stdout.readline()
+                if s == '':
+                    break
+                if s.startswith(s): 
+                    found_string = True
+                    break
+        return found_string
+
+    def testNoArgs(self):
+        """Run bind10 without any arguments"""
+        bob = subprocess.Popen(args=(BIND10_EXE,),
+                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        started_ok = self._waitForString(bob, '[bind10] BIND 10 started')
+        time.sleep(0.1)
+        bob.terminate()
+        bob.wait()
+        self.assertTrue(started_ok)
+
+    def testBadOption(self):
+        """Run bind10 with a bogus option"""
+        bob = subprocess.Popen(args=(BIND10_EXE, "--badoption"),
+                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(bob, 'bind10: error: no such option: --badoption')
+        time.sleep(0.1)
+        bob.terminate()
+        self.assertTrue(bob.wait() == 2)
+        self.assertTrue(failed)
+
+    def testArgument(self):
+        """Run bind10 with an argument (this is not allowed)"""
+        bob = subprocess.Popen(args=(BIND10_EXE, "argument"),
+                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(bob, 'Usage: bind10 [options]')
+        time.sleep(0.1)
+        bob.terminate()
+        self.assertTrue(bob.wait() == 1)
+        self.assertTrue(failed)
+
+    def testBadUser(self):
+        """Run bind10 with a bogus user"""
+        bob = subprocess.Popen(args=(BIND10_EXE, "-u", "bogus_user"),
+                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(bob, "bind10: invalid user: 'bogus_user'")
+        time.sleep(0.1)
+        bob.terminate()
+        self.assertTrue(bob.wait() == 1)
+        self.assertTrue(failed)
+
+    def testBadUid(self):
+        """Run bind10 with a bogus user ID"""
+        bob = subprocess.Popen(args=(BIND10_EXE, "-u", "999999999"),
+                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(bob, "bind10: invalid user: '999999999'")
+        time.sleep(0.1)
+        bob.terminate()
+        self.assertTrue(bob.wait() == 1)
+        self.assertTrue(failed)
+
+    def testFailSetUser(self):
+        """Try the -u option when we don't run as root"""
+        global SUID_USER
+        if SUID_USER is None:
+            self.skipTest("test needs a valid user (set when run)")
+        if os.getuid() == 0:
+            self.skipTest("test must not be run as root (uid is 0)")
+        # XXX: we depend on the "nobody" user
+        bob = subprocess.Popen(args=(BIND10_EXE, "-u", "nobody"),
+                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        failed = self._waitForString(bob, "[bind10] Error on startup: Unable to start b10-msgq; Unable to change to user nobody")
+        time.sleep(0.1)
+        bob.terminate()
+        self.assertTrue(bob.wait() == 1)
+        self.assertTrue(failed)
+
+    def testSetUser(self):
+        """Try the -u option"""
+        global SUID_USER
+        if SUID_USER is None:
+            self.skipTest("test needs a valid user (set when run)")
+        if os.getuid() != 0:
+            self.skipTest("test must run as root (uid is not 0)")
+        if os.geteuid() != 0:
+            self.skipTest("test must run as root (euid is not 0)")
+
+        bob = subprocess.Popen(args=(BIND10_EXE, "-u", SUID_USER),
+                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        started_ok = self._waitForString(bob, '[bind10] BIND 10 started')
+        self.assertTrue(started_ok)
+        ps = subprocess.Popen(args=("ps", "axo", "user,pid"),
+                              stdout=subprocess.PIPE)
+        s = ps.stdout.readline()
+        ps_user = None
+        while True:
+            s = ps.stdout.readline()
+            if s == '': break
+            (user, pid) = s.split()
+            if int(pid) == bob.pid:
+                ps_user = user.decode()
+                break
+        self.assertTrue(ps_user is not None)
+        self.assertTrue(ps_user == SUID_USER)
+        time.sleep(0.1)
+        bob.terminate()
+        x = bob.wait()
+        self.assertTrue(bob.wait() == 0)
+
+if __name__ == '__main__':
+    unittest.main()

+ 2 - 1
src/bin/bind10/tests/bind10_test.in

@@ -27,5 +27,6 @@ PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_srcdir@/src/bin/bind10
 export PYTHONPATH
 
 cd ${BIND10_PATH}/tests
-exec ${PYTHON_EXEC} -O bind10_test.py $*
+${PYTHON_EXEC} -O bind10_test.py $*
+exec ${PYTHON_EXEC} -O args_test.py $*
 

+ 1 - 1
src/bin/bindctl/bindcmd.py

@@ -87,7 +87,7 @@ class BindCmdInterpreter(Cmd):
         '''Generate one session id for the connection. '''
         rand = os.urandom(16)
         now = time.time()
-        session_id = sha1(("%s%s%s" %(rand, now, 
+        session_id = sha1(("%s%s%s" %(rand, now,
                                       socket.gethostname())).encode())
         digest = session_id.hexdigest()
         return digest

+ 3 - 1
src/bin/cfgmgr/Makefile.am

@@ -1,8 +1,10 @@
+SUBDIRS = tests
+
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
 pkglibexec_SCRIPTS = b10-cfgmgr
 
-CLEANFILES = b10-cfgmgr
+CLEANFILES = b10-cfgmgr b10-cfgmgr.pyc
 
 b10_cfgmgrdir = @localstatedir@/@PACKAGE@
 #B10_cfgmgr_DATA = 

+ 7 - 1
src/bin/cfgmgr/b10-cfgmgr.py.in

@@ -15,6 +15,8 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+# $Id$
+
 import sys; sys.path.append ('@@PYTHONPATH@@')
 
 from isc.config.cfgmgr import ConfigManager
@@ -38,7 +40,8 @@ def signal_handler(signal, frame):
     if cm:
         cm.running = False
 
-if __name__ == "__main__":
+def main():
+    global cm
     try:
         cm = ConfigManager(DATA_PATH)
         signal.signal(signal.SIGINT, signal_handler)
@@ -53,3 +56,6 @@ if __name__ == "__main__":
         print("[b10-cfgmgr] Interrupted, exiting")
     if cm:
         cm.write_config()
+
+if __name__ == "__main__":
+    main()

+ 13 - 0
src/bin/cfgmgr/tests/Makefile.am

@@ -0,0 +1,13 @@
+PYTESTS = b10-cfgmgr_test.py
+
+EXTRA_DIST = $(PYTESTS)
+
+# later will have configure option to choose this, like: coverage run --branch
+PYCOVERAGE = $(PYTHON)
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+	for pytest in $(PYTESTS) ; do \
+	echo Running test: $$pytest ; \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr \
+	$(PYCOVERAGE) $(abs_builddir)/$$pytest ; \
+	done

+ 95 - 0
src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in

@@ -0,0 +1,95 @@
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: cfgmgr_test.py 2126 2010-06-16 14:40:22Z jelte $
+
+#
+# Tests for the configuration manager run script
+#
+
+import unittest
+import os
+import sys
+
+class MyConfigManager:
+    def __init__(self, path):
+        self._path = path
+        self.read_config_called = False
+        self.notify_boss_called = False
+        self.run_called = False
+        self.write_config_called = False
+        self.running = True
+
+    def read_config(self):
+        self.read_config_called = True
+
+    def notify_boss(self):
+        self.notify_boss_called = True
+
+    def run(self):
+        self.run_called = True
+
+    def write_config(self):
+        self.write_config_called = True
+
+class TestConfigManagerStartup(unittest.TestCase):
+    def test_cfgmgr(self):
+        # some creative module use;
+        # b10-cfgmgr has a hypen, so we use __import__
+        # this also gives us the chance to override the imported
+        # module ConfigManager in it.
+        b = __import__("b10-cfgmgr")
+        b.ConfigManager = MyConfigManager
+
+        b.main()
+
+        self.assertTrue(b.cm.read_config_called)
+        self.assertTrue(b.cm.notify_boss_called)
+        self.assertTrue(b.cm.run_called)
+        self.assertTrue(b.cm.write_config_called)
+
+        self.assertTrue(b.cm.running)
+        b.signal_handler(None, None)
+        self.assertFalse(b.cm.running)
+
+        # TODO: take value from the 'global config module'
+        # (and rename the .in away from this file again)
+        data_path = "@localstatedir@/@PACKAGE@".replace("${prefix}", "@prefix@")
+        self.assertEqual(data_path, b.DATA_PATH)
+
+        # remove the 'module' again, or later tests may fail
+        # (if it is already present it won't be loaded again)
+        sys.modules.pop("b10-cfgmgr")
+
+    def test_cfgmgr_from_source(self):
+        tmp_env_var = "/just/some/dir"
+        env_var = None
+        if "B10_FROM_SOURCE" in os.environ:
+            env_var = os.environ["B10_FROM_SOURCE"]
+
+        os.environ["B10_FROM_SOURCE"] = tmp_env_var
+        b = __import__("b10-cfgmgr", globals(), locals())
+        b.ConfigManager = MyConfigManager
+        self.assertEqual(tmp_env_var, b.DATA_PATH)
+
+        if env_var != None:
+            os.environ["B10_FROM_SOURCE"] = env_var
+
+        sys.modules.pop("b10-cfgmgr")
+
+
+if __name__ == '__main__':
+    unittest.main()
+

+ 1 - 1
src/bin/cmdctl/cmdctl.py.in

@@ -416,7 +416,7 @@ def set_signal_handler():
 def run(addr = 'localhost', port = 8080, idle_timeout = 1200, verbose = False):
     ''' Start cmdctl as one https server. '''
     if verbose:
-        sys.stdout.write("[b10-cmdctl] starting on :%s port:%d\n" %(addr, port))
+        sys.stdout.write("[b10-cmdctl] starting on %s port:%d\n" %(addr, port))
     httpd = SecureHTTPServer((addr, port), SecureHTTPRequestHandler, idle_timeout, verbose)
     httpd.serve_forever()
 

+ 1 - 1
src/bin/host/Makefile.am

@@ -7,7 +7,7 @@ CLEANFILES = *.gcno *.gcda
 
 bin_PROGRAMS = host
 host_SOURCES = host.cc
-host_LDADD = $(top_builddir)/src/lib/dns/.libs/libdns.a
+host_LDADD = $(top_builddir)/src/lib/dns/.libs/libdns++.a
 host_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 
 #man_MANS = host.1

+ 2 - 0
src/bin/host/host.cc

@@ -19,6 +19,8 @@
 #include <sys/time.h>       // for gettimeofday
 #include <sys/socket.h>     // networking functions and definitions on FreeBSD
 
+#include <unistd.h>
+
 #include <string>
 #include <iostream>
 

+ 26 - 20
src/bin/loadzone/Makefile.am

@@ -1,3 +1,5 @@
+SUBDIRS = tests/correct
+SUBDIRS += tests/error
 bin_SCRIPTS = b10-loadzone
 
 CLEANFILES = b10-loadzone
@@ -22,23 +24,27 @@ install-data-local:
 	$(mkinstalldirs) $(DESTDIR)/@localstatedir@/@PACKAGE@
 # TODO: permissions handled later
 
-EXTRA_DIST += testdata/README
-EXTRA_DIST += testdata/dsset-subzone.example.com.
-EXTRA_DIST += testdata/example.com
-EXTRA_DIST += testdata/example.com.signed
-EXTRA_DIST += testdata/Kexample.com.+005+04456.key
-EXTRA_DIST += testdata/Kexample.com.+005+04456.private
-EXTRA_DIST += testdata/Kexample.com.+005+33495.key
-EXTRA_DIST += testdata/Kexample.com.+005+33495.private
-EXTRA_DIST += testdata/Ksql1.example.com.+005+12447.key
-EXTRA_DIST += testdata/Ksql1.example.com.+005+12447.private
-EXTRA_DIST += testdata/Ksql1.example.com.+005+33313.key
-EXTRA_DIST += testdata/Ksql1.example.com.+005+33313.private
-EXTRA_DIST += testdata/Ksql2.example.com.+005+38482.key
-EXTRA_DIST += testdata/Ksql2.example.com.+005+38482.private
-EXTRA_DIST += testdata/Ksql2.example.com.+005+63192.key
-EXTRA_DIST += testdata/Ksql2.example.com.+005+63192.private
-EXTRA_DIST += testdata/sql1.example.com
-EXTRA_DIST += testdata/sql1.example.com.signed
-EXTRA_DIST += testdata/sql2.example.com
-EXTRA_DIST += testdata/sql2.example.com.signed
+EXTRA_DIST += tests/normal/README
+EXTRA_DIST += tests/normal/dsset-subzone.example.com
+EXTRA_DIST += tests/normal/example.com
+EXTRA_DIST += tests/normal/example.com.signed
+EXTRA_DIST += tests/normal/Kexample.com.+005+04456.key
+EXTRA_DIST += tests/normal/Kexample.com.+005+04456.private
+EXTRA_DIST += tests/normal/Kexample.com.+005+33495.key
+EXTRA_DIST += tests/normal/Kexample.com.+005+33495.private
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+12447.key
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+12447.private
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+33313.key
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+33313.private
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+38482.key
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+38482.private
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+63192.key
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+63192.private
+EXTRA_DIST += tests/normal/sql1.example.com
+EXTRA_DIST += tests/normal/sql1.example.com.signed
+EXTRA_DIST += tests/normal/sql2.example.com
+EXTRA_DIST += tests/normal/sql2.example.com.signed
+
+pytest:
+	$(SHELL) tests/correct/correct_test.sh
+	$(SHELL) tests/error/error_test.sh

+ 16 - 6
src/bin/loadzone/b10-loadzone.py.in

@@ -19,7 +19,8 @@ import sys; sys.path.append ('@@PYTHONPATH@@')
 import re, getopt
 import isc.datasrc
 from isc.datasrc.master import MasterFile
-
+import time
+import os
 #########################################################################
 # usage: print usage note and exit
 #########################################################################
@@ -57,23 +58,32 @@ def main():
     if len(args) != 1:
         usage()
     zonefile = args[0]
-
+    verbose = os.isatty(sys.stdout.fileno())
     try:
-        master = MasterFile(zonefile, initial_origin)
+        master = MasterFile(zonefile, initial_origin, verbose)
     except Exception as e:
-        print("Error reading zone file: " + str(e))
+        sys.stderr.write("Error reading zone file: %s\n" % str(e))
         exit(1)
 
     try:
         zone = master.zonename()
+        if verbose:
+            sys.stdout.write("Using SQLite3 database file %s\n" % dbfile)
+            sys.stdout.write("Zone name is %s\n" % zone)
+            sys.stdout.write("Loading file \"%s\"\n" % zonefile)
     except Exception as e:
-        print("Error reading zone file: " + str(e))
+        sys.stdout.write("\n")
+        sys.stderr.write("Error reading zone file: %s\n" % str(e))
         exit(1)
 
     try:
         isc.datasrc.sqlite3_ds.load(dbfile, zone, master.zonedata)
+        if verbose:
+            master.closeverbose()
+            sys.stdout.write("\nDone.\n")
     except Exception as e:
-        print("Error loading database: " + str(e))
+        sys.stdout.write("\n")
+        sys.stderr.write("Error loading database: %s\n"% str(e))
         exit(1)
 
 if __name__ == "__main__":

+ 25 - 0
src/bin/loadzone/tests/correct/Makefile.am

@@ -0,0 +1,25 @@
+PYTESTS = correct_test.sh
+EXTRA_DIST = get_zonedatas.py
+EXTRA_DIST += include.db
+EXTRA_DIST += inclsub.db
+EXTRA_DIST += known.test.out
+EXTRA_DIST += mix1.db
+EXTRA_DIST += mix1sub1.db
+EXTRA_DIST += mix1sub2.db
+EXTRA_DIST += mix2.db
+EXTRA_DIST += mix2sub1.txt
+EXTRA_DIST += mix2sub2.txt
+EXTRA_DIST += ttl1.db
+EXTRA_DIST += ttl2.db
+EXTRA_DIST += ttlext.db
+EXTRA_DIST += example.db
+
+# later will have configure option to choose this, like: coverage run --branch
+PYCOVERAGE = $(PYTHON)
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+	for pytest in $(PYTESTS) ; do \
+	echo Running test: $$pytest ; \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
+	$(SHELL) $(abs_builddir)/$$pytest ; \
+	done

+ 75 - 0
src/bin/loadzone/tests/correct/correct_test.sh.in

@@ -0,0 +1,75 @@
+#! /bin/sh
+
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@}
+export PYTHON_EXEC
+
+PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python
+export PYTHONPATH
+
+LOADZONE_PATH=@abs_top_builddir@/src/bin/loadzone
+TEST_FILE_PATH=@abs_top_srcdir@/src/bin/loadzone/tests/correct
+TEST_OUTPUT_PATH=@abs_top_builddir@/src/bin/loadzone//tests/correct
+
+status=0
+echo "Loadzone include. from include.db file"
+cd ${TEST_FILE_PATH}
+${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 include.db >> /dev/null
+
+echo "loadzone  ttl1. from ttl1.db file"
+${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 ttl1.db >> /dev/null
+
+echo "loadzone ttl2. from ttl2.db file"
+${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 ttl2.db >> /dev/null
+
+echo "loadzone mix1. from mix1.db"
+${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 mix1.db >> /dev/null
+
+echo "loadzone mix2. from mix2.db"
+${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 mix2.db >> /dev/null
+
+echo "loadzone ttlext. from ttlext.db"
+${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 ttlext.db >> /dev/null
+
+echo "loadzone example.com. from example.db"
+${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 example.db >> /dev/null
+
+echo "I:test master file \$INCLUDE semantics"
+echo "I:test master file BIND 8 compatibility TTL and \$TTL semantics"
+echo "I:test master file RFC1035 TTL and \$TTL semantics"
+echo "I:test master file BIND8 compatibility and mixed \$INCLUDE with \$TTL semantics"
+echo "I:test master file RFC1035 TTL and mixed \$INCLUDE with \$TTL semantics"
+echo "I:test master file BIND9 extenstion of TTL"
+echo "I:test master file RFC1035 missing CLASS, TTL, NAME semantics"
+
+${PYTHON_EXEC} ${TEST_FILE_PATH}/get_zonedatas.py ${TEST_OUTPUT_PATH}/zone.sqlite3 > ${TEST_OUTPUT_PATH}/test.out
+echo "Compare test results."
+diff ${TEST_OUTPUT_PATH}/test.out ${TEST_FILE_PATH}/known.test.out || status=1
+
+echo "Clean tmp files."
+rm -f ${TEST_OUTPUT_PATH}/zone.sqlite3
+rm -f ${TEST_OUTPUT_PATH}/test.out
+echo "I:exit status: $status"
+echo "------------------------------------------------------------------------------"
+echo "Ran 7 test files"
+echo ""
+if [ "$status" -eq 1 ] ;then
+    echo "ERROR"
+else
+    echo "OK"
+fi
+exit $status

+ 14 - 0
src/bin/loadzone/tests/correct/example.db

@@ -0,0 +1,14 @@
+;This file includes all kinds of rr form. missing name, ttl and class or not.
+$ORIGIN example.com.
+$TTL 60
+@    IN SOA   ns1.example.com. hostmaster.example.com. (1 43200 900 1814400 7200)
+     IN     20      NS  ns1
+                    NS  ns2
+ns1  IN     30      A   192.168.1.102
+            70      NS  ns3
+     IN             NS  ns4
+     10     IN      MX  10  mail.example.com.
+ns2         80      A   1.1.1.1
+ns3  IN             A   2.2.2.2
+ns4                 A   3.3.3.3
+ns5  90     IN      A   4.4.4.4

+ 8 - 0
src/bin/loadzone/tests/correct/get_zonedatas.py

@@ -0,0 +1,8 @@
+from isc.datasrc import sqlite3_ds
+import sys
+ZONE_FILE = sys.argv[1]
+zonename_set = ["include.", "ttl1.", "ttl2.", "mix1.", "mix2.", "ttlext.", "example.com."]
+for zone_name in zonename_set:
+    for rr_data in sqlite3_ds.get_zone_datas(zone_name, ZONE_FILE):
+        data_len = len(rr_data[2])
+        sys.stdout.write(rr_data[2] + '\t\t' + str(rr_data[4]) + '\tIN\t' + rr_data[5] + '\t' + rr_data[7] + '\n')

+ 4 - 0
src/bin/loadzone/tests/correct/inclsub.db

@@ -0,0 +1,4 @@
+a    300		A	10.0.1.1
+$ORIGIN foo
+b	 300     	A	10.0.2.2
+

+ 23 - 0
src/bin/loadzone/tests/correct/include.db

@@ -0,0 +1,23 @@
+$ORIGIN include.   ; initialize origin
+$TTL 300
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+
+ns			A	127.0.0.1
+
+a			A	10.0.0.1
+$INCLUDE inclsub.db sub   ;  a.include. is the relative domain name origin for the included file
+; use the current domain name
+            A	99.99.99.99
+b			A	10.0.0.2
+$ORIGIN b
+$INCLUDE inclsub.db
+; use the current domain name
+			A	10.0.0.99
+c			A	10.0.0.3

+ 79 - 0
src/bin/loadzone/tests/correct/known.test.out

@@ -0,0 +1,79 @@
+include.		300	IN	SOA	ns.include. hostmaster.include. 1 3600 1800 1814400 3600
+include.		300	IN	NS	ns.include.
+ns.include.		300	IN	A	127.0.0.1
+a.include.		300	IN	A	10.0.0.1
+a.sub.include.		300	IN	A	10.0.1.1
+b.foo.sub.include.		300	IN	A	10.0.2.2
+a.include.		300	IN	A	99.99.99.99
+b.include.		300	IN	A	10.0.0.2
+a.b.include.		300	IN	A	10.0.1.1
+b.foo.b.include.		300	IN	A	10.0.2.2
+b.include.		300	IN	A	10.0.0.99
+c.b.include.		300	IN	A	10.0.0.3
+ttl1.		3	IN	SOA	ns.ttl1. hostmaster.ttl1. 1 3600 1800 1814400 3
+ttl1.		3	IN	NS	ns.ttl1.
+ns.ttl1.		3	IN	A	10.53.0.1
+a.ttl1.		3	IN	TXT	"soa minttl 3"
+b.ttl1.		2	IN	TXT	"explicit ttl 2"
+c.ttl1.		3	IN	TXT	"soa minttl 3"
+d.ttl1.		1	IN	TXT	"default ttl 1"
+e.ttl1.		4	IN	TXT	"explicit ttl 4"
+f.ttl1.		1	IN	TXT	"default ttl 1"
+ttl2.		1	IN	SOA	ns.ttl2. hostmaster.ttl2. 1 3600 1800 1814400 3
+ttl2.		1	IN	NS	ns.ttl2.
+ns.ttl2.		1	IN	A	10.53.0.1
+a.ttl2.		1	IN	TXT	"inherited ttl 1"
+b.ttl2.		2	IN	TXT	"explicit ttl 2"
+c.ttl2.		2	IN	TXT	"inherited ttl 2"
+d.ttl2.		3	IN	TXT	"default ttl 3"
+e.ttl2.		2	IN	TXT	"explicit ttl 2"
+f.ttl2.		3	IN	TXT	"default ttl 3"
+mix1.		3	IN	SOA	ns.mix1. hostmaster.mix1. 1 3600 1800 1814400 3
+mix1.		3	IN	NS	ns.mix1.
+ns.mix1.		3	IN	A	10.53.0.1
+a.mix1.		3	IN	TXT	"soa minttl 3"
+b.mix1.		2	IN	TXT	"explicit ttl 2"
+a.mix1.		3	IN	TXT	"soa minttl 3"
+b.foo.mix1.		3	IN	TXT	"soa minttl 3"
+c.mix1.		3	IN	TXT	"soa minttl 3"
+d.mix1.		1	IN	TXT	"default ttl 1"
+e.mix1.		4	IN	TXT	"explicit ttl 4"
+f.mix1.		1	IN	TXT	"default ttl 1"
+i.mix1.		1	IN	TXT	"default ttl 1"
+g.mix1.		5	IN	TXT	"default ttl 5"
+h.mix1.		5	IN	TXT	"the include ttl 5"
+mix2.		1	IN	SOA	ns.mix2. hostmaster.mix2. 1 3600 1800 1814400 3
+mix2.		1	IN	NS	ns.mix2.
+ns.mix2.		1	IN	A	10.53.0.1
+a.mix2.		1	IN	TXT	"inherited ttl 1"
+h.mix2.		1	IN	TXT	"inherited ttl 1"
+g.mix2.		6	IN	TXT	"inherited ttl 6"
+b.mix2.		6	IN	TXT	"explicit ttl 6"
+c.mix2.		2	IN	TXT	"inherited ttl 2"
+m.mix2.		6	IN	TXT	"explicit ttl 6"
+d.mix2.		3	IN	TXT	"default ttl 3"
+e.mix2.		2	IN	TXT	"explicit ttl 2"
+n.mix2.		3	IN	TXT	"default ttl 3"
+f.mix2.		3	IN	TXT	"default ttl 3"
+g.mix2.		5	IN	TXT	"default ttl 5"
+f.mix2.		5	IN	TXT	"default ttl 5"
+ttlext.		3	IN	SOA	ns.ttlext. hostmaster.ttlext. 1 3600 1800 1814400 3
+ttlext.		3	IN	NS	ns.ttlext.
+ns.ttlext.		3	IN	A	10.53.0.1
+a.ttlext.		3	IN	TXT	"soa minttl 3"
+b.ttlext.		2	IN	TXT	"explicit ttl 2"
+c.ttlext.		3	IN	TXT	"soa minttl 3"
+d.ttlext.		600	IN	TXT	"default ttl 600"
+e.ttlext.		4	IN	TXT	"explicit ttl 4"
+f.ttlext.		600	IN	TXT	"default ttl 600"
+example.com.		60	IN	SOA	ns1.example.com. hostmaster.example.com. 1 43200 900 1814400 7200
+example.com.		20	IN	NS	ns1.example.com.
+example.com.		60	IN	NS	ns2.example.com.
+ns1.example.com.		30	IN	A	192.168.1.102
+ns1.example.com.		70	IN	NS	ns3.example.com.
+ns1.example.com.		60	IN	NS	ns4.example.com.
+ns1.example.com.		10	IN	MX	10 mail.example.com.
+ns2.example.com.		80	IN	A	1.1.1.1
+ns3.example.com.		60	IN	A	2.2.2.2
+ns4.example.com.		60	IN	A	3.3.3.3
+ns5.example.com.		90	IN	A	4.4.4.4

+ 21 - 0
src/bin/loadzone/tests/correct/mix1.db

@@ -0,0 +1,21 @@
+; $Id: ttl1.db,v 1.6 2007/06/19 23:47:04 tbox Exp $
+$ORIGIN mix1.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3
+				)
+			NS	ns
+ns			A	10.53.0.1
+a			TXT	"soa minttl 3"
+b		2	TXT	"explicit ttl 2"
+$INCLUDE mix1sub1.db
+c			TXT	"soa minttl 3"
+$TTL 1
+d			TXT	"default ttl 1"
+e		4	TXT	"explicit ttl 4"
+f			TXT	"default ttl 1"
+$INCLUDE mix1sub2.db
+h       5   TXT "the include ttl 5"

+ 3 - 0
src/bin/loadzone/tests/correct/mix1sub1.db

@@ -0,0 +1,3 @@
+a                       TXT      "soa minttl 3"
+$ORIGIN foo
+b                       TXT      "soa minttl 3"

+ 3 - 0
src/bin/loadzone/tests/correct/mix1sub2.db

@@ -0,0 +1,3 @@
+i                       TXT      "default ttl 1"
+$TTL   5
+g                       TXT      "default ttl 5"

+ 21 - 0
src/bin/loadzone/tests/correct/mix2.db

@@ -0,0 +1,21 @@
+$ORIGIN mix2.
+@		1	IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3
+				)
+			NS	ns
+ns			A	10.53.0.1
+a			TXT	"inherited ttl 1"
+$INCLUDE mix2sub1.txt
+b			TXT	"explicit ttl 6"
+c		2	TXT	"inherited ttl 2"
+m           TXT "explicit ttl 6"
+$TTL 3
+d			TXT	"default ttl 3"
+e		2	TXT	"explicit ttl 2"
+n           TXT "default ttl 3"
+$INCLUDE mix2sub2.txt
+f			TXT	"default ttl 5"

+ 3 - 0
src/bin/loadzone/tests/correct/mix2sub1.txt

@@ -0,0 +1,3 @@
+h                       TXT     "inherited ttl 1"
+$TTL 6
+g                       TXT     "inherited ttl 6"

+ 3 - 0
src/bin/loadzone/tests/correct/mix2sub2.txt

@@ -0,0 +1,3 @@
+f                       TXT     "default  ttl 3"
+$TTL 5
+g                       TXT     "default  ttl 5"

+ 17 - 0
src/bin/loadzone/tests/correct/ttl1.db

@@ -0,0 +1,17 @@
+$ORIGIN ttl1.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3
+				)
+			NS	ns
+ns			A	10.53.0.1
+a			TXT	"soa minttl 3"
+b		2	TXT	"explicit ttl 2"
+c			TXT	"soa minttl 3"
+$TTL 1
+d			TXT	"default ttl 1"
+e		4	TXT	"explicit ttl 4"
+f			TXT	"default ttl 1"

+ 17 - 0
src/bin/loadzone/tests/correct/ttl2.db

@@ -0,0 +1,17 @@
+$ORIGIN ttl2.
+@		1	IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3
+				)
+			NS	ns
+ns			A	10.53.0.1
+a			TXT	"inherited ttl 1"
+b		2	TXT	"explicit ttl 2"
+c			TXT	"inherited ttl 2"
+$TTL 3    ; a new ttl
+d			TXT	"default ttl 3"
+e		2	TXT	"explicit ttl 2"
+f			TXT	"default ttl 3"

+ 18 - 0
src/bin/loadzone/tests/correct/ttlext.db

@@ -0,0 +1,18 @@
+; $Id: ttl1.db,v 1.6 2007/06/19 23:47:04 tbox Exp $
+$ORIGIN ttlext.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3
+				)
+			NS	ns
+ns			A	10.53.0.1
+a			TXT	"soa minttl 3"
+b		2S	TXT	"explicit ttl 2"
+c			TXT	"soa minttl 3"
+$TTL 10M  ; bind9 extention ttl
+d			TXT	"default ttl 600"
+e		4	TXT	"explicit ttl 4"
+f			TXT	"default ttl 600"

+ 25 - 0
src/bin/loadzone/tests/error/Makefile.am

@@ -0,0 +1,25 @@
+PYTESTS = error_test.sh
+
+EXTRA_DIST = error.known
+EXTRA_DIST += formerr1.db 
+EXTRA_DIST += formerr2.db
+EXTRA_DIST += formerr3.db
+EXTRA_DIST += formerr4.db
+EXTRA_DIST += formerr5.db
+EXTRA_DIST += include.txt
+EXTRA_DIST += keyerror1.db
+EXTRA_DIST += keyerror2.db
+EXTRA_DIST += keyerror3.db
+#EXTRA_DIST += nofilenane.db
+EXTRA_DIST += originerr1.db
+EXTRA_DIST += originerr2.db
+
+# later will have configure option to choose this, like: coverage run --branch
+PYCOVERAGE = $(PYTHON)
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+	for pytest in $(PYTESTS) ; do \
+	echo Running test: $$pytest ; \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
+	$(SHELL) $(abs_builddir)/$$pytest ; \
+	done

+ 11 - 0
src/bin/loadzone/tests/error/error.known

@@ -0,0 +1,11 @@
+Error reading zone file: Cannot parse RR, No $ORIGIN: @ IN SOA ns hostmaster 1 3600 1800 1814400 3600
+Error reading zone file: $ORIGIN is not absolute in record:$ORIGIN com
+Error reading zone file: Cannot parse RR: $TL 300
+Error reading zone file: Cannot parse RR: $OIGIN com.
+Error loading database: Error while loading com.: Cannot parse RR: $INLUDE file.txt
+Error loading database: Error while loading com.: Invalid $include format
+Error loading database: Error while loading com.: Cannot parse RR, No $ORIGIN:  include.txt sub
+Error reading zone file: Invalid TTL: ""
+Error reading zone file: Invalid TTL: "M"
+Error loading database: Error while loading com.: Cannot parse RR: b "no type error!"
+Error reading zone file: Could not open bogusfile

+ 82 - 0
src/bin/loadzone/tests/error/error_test.sh.in

@@ -0,0 +1,82 @@
+#! /bin/sh
+
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@}
+export PYTHON_EXEC
+
+PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python
+export PYTHONPATH
+
+LOADZONE_PATH=@abs_top_builddir@/src/bin/loadzone
+TEST_OUTPUT_PATH=@abs_top_builddir@/src/bin/loadzone/tests/error
+TEST_FILE_PATH=@abs_top_srcdir@/src/bin/loadzone/tests/error
+
+cd ${LOADZONE_PATH}/tests/error
+
+export LOADZONE_PATH
+status=0
+
+echo "PYTHON PATH: $PYTHONPATH"
+
+echo "Test no \$ORIGIN error in zone file"
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/originerr1.db 1> /dev/null 2> error.out
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/originerr2.db 1> /dev/null 2>> error.out
+
+echo "Test: key word TTL spell error"
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/keyerror1.db 1> /dev/null 2>> error.out
+
+echo "Test: key word ORIGIN spell error"
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/keyerror2.db 1> /dev/null 2>> error.out
+
+echo "Test: key INCLUDE spell error"
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/keyerror3.db 1> /dev/null 2>> error.out
+
+echo "Test: include formal error, miss filename"
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/formerr1.db 1> /dev/null 2>>error.out
+
+echo "Test: include form error, domain is not absolute"
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/formerr2.db 1> /dev/null 2>> error.out
+
+echo "Test: TTL form error, no ttl value"
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/formerr3.db 1> /dev/null 2>> error.out
+
+echo "Test: TTL form error, ttl value error"
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/formerr4.db 1> /dev/null 2>> error.out
+
+echo "Test: rr form error, no type"
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  ${TEST_FILE_PATH}/formerr5.db 1> /dev/null 2>> error.out
+
+echo "Test: zone file is bogus"
+# since bogusfile doesn't exist anyway, we *don't* specify the directory
+${LOADZONE_PATH}/b10-loadzone -d zone.sqlite3  bogusfile 1> /dev/null 2>> error.out
+
+diff error.out ${TEST_FILE_PATH}/error.known || status=1
+
+echo "Clean tmp file."
+rm -f error.out
+rm -f zone.sqlite3
+
+echo "I:exit status:$status"
+echo "-----------------------------------------------------------------------------"
+echo "Ran 11 test files"
+echo ""
+if [ "$status" -eq 1 ];then
+    echo "ERROR"
+else 
+    echo "OK"
+fi
+exit $status

+ 13 - 0
src/bin/loadzone/tests/error/formerr1.db

@@ -0,0 +1,13 @@
+$TTL 300
+$ORIGIN com.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+ns			A	127.0.0.1
+$INCLUDE
+a			A	10.0.0.1

+ 12 - 0
src/bin/loadzone/tests/error/formerr2.db

@@ -0,0 +1,12 @@
+$TTL 300
+com.			IN SOA	ns.com. hostmaster.com. (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns.example.com.
+ns.com.			A	127.0.0.1
+$INCLUDE include.txt sub
+a.com.			A	10.0.0.1

+ 12 - 0
src/bin/loadzone/tests/error/formerr3.db

@@ -0,0 +1,12 @@
+$TTL 
+$ORIGIN com.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+ns			A	127.0.0.1
+a			A	10.0.0.1

+ 12 - 0
src/bin/loadzone/tests/error/formerr4.db

@@ -0,0 +1,12 @@
+$TTL M
+$ORIGIN com.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+ns			A	127.0.0.1
+a			A	10.0.0.1

+ 13 - 0
src/bin/loadzone/tests/error/formerr5.db

@@ -0,0 +1,13 @@
+$TTL 2M
+$ORIGIN com.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+ns			A	127.0.0.1 ; ip value
+b               "no type error!"
+a			A	10.0.0.1

+ 1 - 0
src/bin/loadzone/tests/error/include.txt

@@ -0,0 +1 @@
+a  300 A 127.0.0.1

+ 12 - 0
src/bin/loadzone/tests/error/keyerror1.db

@@ -0,0 +1,12 @@
+$TL 300
+@ORIGIN com.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+ns			A	127.0.0.1
+a			A	10.0.0.1

+ 12 - 0
src/bin/loadzone/tests/error/keyerror2.db

@@ -0,0 +1,12 @@
+$TTL 300
+$OIGIN com.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+ns			A	127.0.0.1
+a			A	10.0.0.1

+ 13 - 0
src/bin/loadzone/tests/error/keyerror3.db

@@ -0,0 +1,13 @@
+$TTL 300
+$ORIGIN com.
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+ns			A	127.0.0.1
+$INLUDE file.txt
+a			A	10.0.0.1

+ 11 - 0
src/bin/loadzone/tests/error/originerr1.db

@@ -0,0 +1,11 @@
+$TTL 300
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+ns			A	127.0.0.1
+a			A	10.0.0.1

+ 12 - 0
src/bin/loadzone/tests/error/originerr2.db

@@ -0,0 +1,12 @@
+$TTL 300
+$ORIGIN com
+@			IN SOA	ns hostmaster (
+				1        ; serial
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	ns
+ns			A	127.0.0.1
+a			A	10.0.0.1

src/bin/loadzone/testdata/Kexample.com.+005+04456.key → src/bin/loadzone/tests/normal/Kexample.com.+005+04456.key


src/bin/loadzone/testdata/Kexample.com.+005+04456.private → src/bin/loadzone/tests/normal/Kexample.com.+005+04456.private


src/bin/loadzone/testdata/Kexample.com.+005+33495.key → src/bin/loadzone/tests/normal/Kexample.com.+005+33495.key


src/bin/loadzone/testdata/Kexample.com.+005+33495.private → src/bin/loadzone/tests/normal/Kexample.com.+005+33495.private


src/bin/loadzone/testdata/Ksql1.example.com.+005+12447.key → src/bin/loadzone/tests/normal/Ksql1.example.com.+005+12447.key


src/bin/loadzone/testdata/Ksql1.example.com.+005+12447.private → src/bin/loadzone/tests/normal/Ksql1.example.com.+005+12447.private


src/bin/loadzone/testdata/Ksql1.example.com.+005+33313.key → src/bin/loadzone/tests/normal/Ksql1.example.com.+005+33313.key


src/bin/loadzone/testdata/Ksql1.example.com.+005+33313.private → src/bin/loadzone/tests/normal/Ksql1.example.com.+005+33313.private


src/bin/loadzone/testdata/Ksql2.example.com.+005+38482.key → src/bin/loadzone/tests/normal/Ksql2.example.com.+005+38482.key


src/bin/loadzone/testdata/Ksql2.example.com.+005+38482.private → src/bin/loadzone/tests/normal/Ksql2.example.com.+005+38482.private


src/bin/loadzone/testdata/Ksql2.example.com.+005+63192.key → src/bin/loadzone/tests/normal/Ksql2.example.com.+005+63192.key


src/bin/loadzone/testdata/Ksql2.example.com.+005+63192.private → src/bin/loadzone/tests/normal/Ksql2.example.com.+005+63192.private


src/bin/loadzone/testdata/README → src/bin/loadzone/tests/normal/README


src/bin/loadzone/testdata/dsset-subzone.example.com. → src/bin/loadzone/tests/normal/dsset-subzone.example.com


src/bin/loadzone/testdata/example.com → src/bin/loadzone/tests/normal/example.com


src/bin/loadzone/testdata/example.com.signed → src/bin/loadzone/tests/normal/example.com.signed


src/bin/loadzone/testdata/sql1.example.com → src/bin/loadzone/tests/normal/sql1.example.com


src/bin/loadzone/testdata/sql1.example.com.signed → src/bin/loadzone/tests/normal/sql1.example.com.signed


src/bin/loadzone/testdata/sql2.example.com → src/bin/loadzone/tests/normal/sql2.example.com


src/bin/loadzone/testdata/sql2.example.com.signed → src/bin/loadzone/tests/normal/sql2.example.com.signed


+ 1 - 1
src/bin/xfrin/tests/Makefile.am

@@ -7,6 +7,6 @@ PYCOVERAGE = $(PYTHON)
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python \
+	env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

+ 15 - 1
src/bin/xfrin/xfrin.py.in

@@ -40,11 +40,14 @@ except ImportError as e:
 # installed on the system
 if "B10_FROM_BUILD" in os.environ:
     SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrin"
+    AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
 else:
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
     SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+    AUTH_SPECFILE_PATH = SPECFILE_PATH
 SPECFILE_LOCATION = SPECFILE_PATH + "/xfrin.spec"
+AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + "/auth.spec"
 
 
 __version__ = 'BIND10'
@@ -434,7 +437,18 @@ a separate method for the convenience of unit tests.
         db_file = args.get('db_file')
         if not db_file:
             #TODO, the db file path should be got in auth server's configuration
-            db_file = '@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3'
+            # if we need access to this configuration more often, we
+            # should add it on start, and not remove it here
+            # (or, if we have writable ds, we might not need this in
+            # the first place)
+            self._cc.add_remote_config(AUTH_SPECFILE_LOCATION)
+            db_file, is_default = self._cc.get_remote_config_value("Auth", "database_file")
+            if is_default and "B10_FROM_BUILD" in os.environ:
+                # this too should be unnecessary, but currently the
+                # 'from build' override isn't stored in the config
+                # (and we don't have writable datasources yet)
+                db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
+            self._cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
 
         return (zone_name, master_addrinfo, db_file)
 

+ 1 - 1
src/bin/xfrout/tests/Makefile.am

@@ -7,6 +7,6 @@ PYCOVERAGE = $(PYTHON)
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
+	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

+ 16 - 8
src/bin/xfrout/tests/xfrout_test.py

@@ -75,7 +75,8 @@ class TestXfroutSession(unittest.TestCase):
 
     def setUp(self):
         request = MySocket(socket.AF_INET,socket.SOCK_STREAM)
-        self.xfrsess = MyXfroutSession(request, None, None)
+        self.log = isc.log.NSLogger('xfrout', '',  severity = 'critical', log_to_console = False )
+        self.xfrsess = MyXfroutSession(request, None, None, self.log)
         self.xfrsess.server = Dbserver()
         self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
         self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
@@ -193,7 +194,7 @@ class TestXfroutSession(unittest.TestCase):
 
     def test_dns_xfrout_start_formerror(self):
         # formerror
-        self.assertRaises(MessageTooShort, self.xfrsess.dns_xfrout_start, self.sock, b"\xd6=\x00\x00\x00\x01\x00")
+        self.xfrsess.dns_xfrout_start(self.sock, b"\xd6=\x00\x00\x00\x01\x00")
         sent_data = self.sock.readsent()
         self.assertEqual(len(sent_data), 0)
     
@@ -236,26 +237,33 @@ class TestXfroutSession(unittest.TestCase):
         reply_msg = self.sock.read_msg()
         self.assertEqual(reply_msg.get_rr_count(Section.ANSWER()), 2)
 
-        # set event
-        self.xfrsess.server._shutdown_event.set()
-        self.assertRaises(XfroutException, self.xfrsess._reply_xfrout_query, self.getmsg(), self.sock, "example.com.")
+class MyCCSession():
+    def __init__(self):
+        pass
+
+    def get_remote_config_value(self, module_name, identifier):
+        if module_name == "Auth" and identifier == "database_file":
+            return "initdb.file", False
+        else:
+            return "unknown", False
+    
 
 class MyUnixSockServer(UnixSockServer):
     def __init__(self):
         self._lock = threading.Lock()
         self._transfers_counter = 0
         self._shutdown_event = threading.Event()
-        self._db_file = "initdb.file"
         self._max_transfers_out = 10
+        self._cc = MyCCSession()
+        self._log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False )
 
 class TestUnixSockServer(unittest.TestCase):
     def setUp(self):
         self.unix = MyUnixSockServer()
      
     def test_updata_config_data(self):
-        self.unix.update_config_data({'transfers_out':10, 'db_file':"db.file"})
+        self.unix.update_config_data({'transfers_out':10 })
         self.assertEqual(self.unix._max_transfers_out, 10)
-        self.assertEqual(self.unix._db_file, "db.file")
 
     def test_get_db_file(self):
         self.assertEqual(self.unix.get_db_file(), "initdb.file")

+ 70 - 47
src/bin/xfrout/xfrout.py.in

@@ -26,8 +26,10 @@ from isc.datasrc import sqlite3_ds
 from socketserver import *
 import os
 from isc.config.ccsession import *
+from isc.log.log import *
 from isc.cc import SessionError
 import socket
+import select
 import errno
 from optparse import OptionParser, OptionValueError
 try:
@@ -40,22 +42,25 @@ except ImportError as e:
 
 if "B10_FROM_BUILD" in os.environ:
     SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
-    UNIX_SOCKET_FILE = os.environ["B10_FROM_SOURCE"] + "/auth_xfrout_conn"
+    AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
+    UNIX_SOCKET_FILE= os.environ["B10_FROM_BUILD"] + "/auth_xfrout_conn"
 else:
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
     SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+    AUTH_SPECFILE_PATH = SPECFILE_PATH
     UNIX_SOCKET_FILE = "@@LOCALSTATEDIR@@/auth_xfrout_conn"
-SPECFILE_LOCATION = SPECFILE_PATH + "/xfrout.spec"
 
+SPECFILE_LOCATION = SPECFILE_PATH + "/xfrout.spec"
+AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + os.sep + "auth.spec"
 MAX_TRANSFERS_OUT = 10
-verbose_mode = False
-
-
-class XfroutException(Exception): pass
-class TmpException(Exception): pass
+VERBOSE_MODE = False
 
 class XfroutSession(BaseRequestHandler):
+    def __init__(self, request, client_address, server, log):
+        BaseRequestHandler.__init__(self, request, client_address, server)
+        self._log = log
+
     def handle(self):
         fd = recv_fd(self.request.fileno())
         
@@ -63,8 +68,7 @@ class XfroutSession(BaseRequestHandler):
             # This may happen when one xfrout process try to connect to
             # xfrout unix socket server, to check whether there is another
             # xfrout running. 
-            print("[b10-xfrout] Failed to receive the FD for XFR connection, "
-                  "maybe because another xfrout process was started.")
+            self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
             return
 
         data_len = self.request.recv(2)
@@ -73,9 +77,8 @@ class XfroutSession(BaseRequestHandler):
         sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
         try:
             self.dns_xfrout_start(sock, msgdata)
-        except TmpException as e:
-            if verbose_mode:
-                self.log_msg(str(e))
+        except Exception as e:
+            self._log.log_message("error", str(e))
 
         sock.shutdown(socket.SHUT_RDWR)
         sock.close()
@@ -88,9 +91,8 @@ class XfroutSession(BaseRequestHandler):
         try:
             msg = Message(Message.PARSE)
             Message.from_wire(msg, mdata)
-        except TmpException as err:
-            if verbose_mode:
-                self.log_msg(str(err))
+        except Exception as err:
+            self._log.log_message("error", str(err))
             return Rcode.FORMERR(), None
 
         return Rcode.NOERROR(), msg
@@ -180,16 +182,11 @@ class XfroutSession(BaseRequestHandler):
             return self. _reply_query_with_error_rcode(msg, sock, rcode_)
 
         try:
-            if verbose_mode:
-                self.log_msg("transfer of '%s/IN': AXFR started" % zone_name)
-
+            self._log.log_message("info", "transfer of '%s/IN': AXFR started" % zone_name)
             self._reply_xfrout_query(msg, sock, zone_name)
-
-            if verbose_mode:
-                self.log_msg("transfer of '%s/IN': AXFR end" % zone_name)
-        except TmpException as err:
-            if verbose_mode:
-                sys.stderr.write("[b10-xfrout] %s\n" % str(err))
+            self._log.log_message("info", "transfer of '%s/IN': AXFR end" % zone_name)
+        except Exception as err:
+            self._log.log_message("error", str(err))
 
         self.server.decrease_transfers_counter()
         return    
@@ -261,7 +258,7 @@ class XfroutSession(BaseRequestHandler):
         # the message length to know if the rrset has been added sucessfully.
         for rr_data in sqlite3_ds.get_zone_datas(zone_name, self.server.get_db_file()):
             if  self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
-                raise XfroutException("shutdown!")
+                self._log.log_message("error", "shutdown!")
 
             # TODO: RRType.SOA() ?
             if RRType(rr_data[5]) == RRType("SOA"): #ignore soa record
@@ -281,21 +278,24 @@ class XfroutSession(BaseRequestHandler):
 
         self._send_message_with_last_soa(msg, sock, rrset_soa)
 
-    def log_msg(self, msg):
-        print('[b10-xfrout] ', msg)
-   
 
 class UnixSockServer(ThreadingUnixStreamServer):
     '''The unix domain socket server which accept xfr query sent from auth server.'''
 
-    def __init__(self, sock_file, handle_class, shutdown_event, config_data):
+    def __init__(self, sock_file, handle_class, shutdown_event, config_data, cc, log):
         self._remove_unused_sock_file(sock_file)
         self._sock_file = sock_file
         ThreadingUnixStreamServer.__init__(self, sock_file, handle_class)
         self._lock = threading.Lock()
         self._transfers_counter = 0
         self._shutdown_event = shutdown_event
+        self._log = log
         self.update_config_data(config_data)
+        self._cc = cc
+
+    def finish_request(self, request, client_address):
+        '''Finish one request by instantiating RequestHandlerClass.'''
+        self.RequestHandlerClass(request, client_address, self, self._log)
 
     def _remove_unused_sock_file(self, sock_file):
         '''Try to remove the socket file. If the file is being used 
@@ -332,23 +332,28 @@ class UnixSockServer(ThreadingUnixStreamServer):
         ThreadingUnixStreamServer.shutdown(self)
         try:
             os.unlink(self._sock_file)
-        except:
-            pass
+        except Exception as e:
+            self._log.log_message("error", str(e))
 
     def update_config_data(self, new_config):
         '''Apply the new config setting of xfrout module. '''
-
+        self._log.log_message('info', 'update config data start.')
         self._lock.acquire()
         self._max_transfers_out = new_config.get('transfers_out')
-        self._db_file = new_config.get('db_file')
+        self._log.log_message('info', 'max transfer out : %d', self._max_transfers_out)
         self._lock.release()
+        self._log.log_message('info', 'update config data complete.')
 
     def get_db_file(self):
-        self._lock.acquire()
-        file = self._db_file
-        self._lock.release()
+        file, is_default = self._cc.get_remote_config_value("Auth", "database_file")
+        # this too should be unnecessary, but currently the
+        # 'from build' override isn't stored in the config
+        # (and we don't have indirect python access to datasources yet)
+        if is_default and "B10_FROM_BUILD" in os.environ:
+            file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
         return file
 
+
     def increase_transfers_counter(self):
         '''Return False, if counter + 1 > max_transfers_out, or else
         return True
@@ -367,29 +372,45 @@ class UnixSockServer(ThreadingUnixStreamServer):
         self._lock.release()
 
 def listen_on_xfr_query(unix_socket_server):
-
     '''Listen xfr query in one single thread. Polls for shutdown 
     every 0.1 seconds, is there a better time?
     '''
-    unix_socket_server.serve_forever(poll_interval = 0.1)
+
+    while True:
+        try:
+            unix_socket_server.serve_forever(poll_interval = 0.1)
+        except select.error as err:
+            # serve_forever() calls select.select(), which can be 
+            # interrupted.
+            # If it is interrupted, it raises select.error with the 
+            # errno set to EINTR. We ignore this case, and let the
+            # normal program flow continue by trying serve_forever()
+            # again.
+            if err.args[0] != errno.EINTR: raise
+
    
 
 class XfroutServer:
     def __init__(self):
         self._unix_socket_server = None
+        self._log = None
         self._listen_sock_file = UNIX_SOCKET_FILE 
         self._shutdown_event = threading.Event()
         self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
+        self._cc.add_remote_config(AUTH_SPECFILE_LOCATION);
         self._config_data = self._cc.get_full_config()
         self._cc.start()
+        self._log = isc.log.NSLogger(self._config_data.get('log_name'), self._config_data.get('log_file'),
+                                self._config_data.get('log_severity'), self._config_data.get('log_versions'),
+                                self._config_data.get('log_max_bytes'), True)
         self._start_xfr_query_listener()
 
-
     def _start_xfr_query_listener(self):
         '''Start a new thread to accept xfr query. '''
     
         self._unix_socket_server = UnixSockServer(self._listen_sock_file, XfroutSession, 
-                                                  self._shutdown_event, self._config_data);
+                                                  self._shutdown_event, self._config_data,
+                                                  self._cc, self._log);
         listener = threading.Thread(target = listen_on_xfr_query, args = (self._unix_socket_server,))
         listener.start()
 
@@ -403,6 +424,9 @@ class XfroutServer:
                 continue
             self._config_data[key] = new_config[key]
         
+        if self._log:
+            self._log.update_config(new_config)
+
         if self._unix_socket_server:
             self._unix_socket_server.update_config_data(self._config_data)
 
@@ -428,8 +452,7 @@ class XfroutServer:
 
     def command_handler(self, cmd, args):
         if cmd == "shutdown":
-            if verbose_mode:
-                print("[b10-xfrout] Received shutdown command")
+            self._log.log_message("info", "Received shutdown command.")
             self.shutdown()
             answer = create_answer(0)
         else: 
@@ -464,18 +487,18 @@ if '__main__' == __name__:
         parser = OptionParser()
         set_cmd_options(parser)
         (options, args) = parser.parse_args()
-        verbose_mode = options.verbose
+        VERBOSE_MODE = options.verbose
 
         set_signal_handler()
         xfrout_server = XfroutServer()
         xfrout_server.run()
     except KeyboardInterrupt:
-        print("[b10-xfrout] exit xfrout process")
+        sys.stderr.write("[b10-xfrout] exit xfrout process")
     except SessionError as e:
-        print('[b10-xfrout] Error creating xfrout, '
-              'is the command channel daemon running?' )
+        sys.stderr.write("[b10-xfrout] Error creating xfrout," 
+                           "is the command channel daemon running?")
     except ModuleCCSessionError as e:
-        print('[b10-xfrout] exit xfrout process:', e)
+        sys.stderr.write("info", '[b10-xfrout] exit xfrout process:', e)
 
     if xfrout_server:
         xfrout_server.shutdown()

+ 31 - 1
src/bin/xfrout/xfrout.spec.pre.in

@@ -12,7 +12,37 @@
          "item_name": "db_file",
          "item_type": "string",
          "item_optional": False,
-         "item_default": '@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3'
+         "item_default": "@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3"
+       },
+       {
+         "item_name": "log_name",
+         "item_type": "string",
+         "item_optional": False,
+         "item_default": "Xfrout"
+       },
+       {
+         "item_name": "log_file",
+    	 "item_type": "string",
+         "item_optional": False,
+         "item_default": "@@LOCALSTATEDIR@@/@PACKAGE@/log/Xfrout.log"
+       },
+       {
+         "item_name": "log_severity",
+    	 "item_type": "string",
+         "item_optional": False,
+    	 "item_default": "debug"
+       },
+       {
+         "item_name": "log_versions",
+    	 "item_type": "integer",
+         "item_optional": False,
+    	 "item_default": 5
+       },
+       {
+         "item_name": "log_max_bytes",
+    	 "item_type": "integer",
+         "item_optional": False,
+    	 "item_default": 1048576
        }
       ],
       "commands": [

+ 6 - 4
src/lib/cc/Makefile.am

@@ -6,10 +6,12 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 # error.  Unfortunately there doesn't seem to be an easy way to selectively
 # avoid the error.  As a short term workaround we suppress this warning
 # for the entire this module.  See also src/bin/auth/Makefile.am.
+if USE_GXX
 AM_CXXFLAGS += -Wno-unused-parameter
+endif
 
-lib_LIBRARIES = libcc.a
-libcc_a_SOURCES = data.cc data.h session.cc session.h
+lib_LTLIBRARIES = libcc.la
+libcc_la_SOURCES = data.cc data.h session.cc session.h
 
 CLEANFILES = *.gcno *.gcda session_config.h
 
@@ -27,8 +29,8 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 # TODO: remove PTHREAD_LDFLAGS (and from configure too)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) $(PTHREAD_LDFLAGS)
 
-run_unittests_LDADD = libcc.a $(GTEST_LDADD)
-run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns.a
+run_unittests_LDADD = libcc.la $(GTEST_LDADD)
+run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns++.a
 run_unittests_LDADD +=  $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 
 endif

+ 11 - 4
src/lib/cc/session.cc

@@ -19,6 +19,17 @@
 
 #include <stdint.h>
 
+// XXX: there seems to be a strange dependency between ASIO and std library
+// definitions.  On some platforms if we include std headers before ASIO
+// headers unexpected behaviors will happen.
+// A middle term solution is to generalize our local wrapper interface
+// (currently only available for the auth server), where all such portability
+// issues are hidden, and to have other modules use the wrapper.
+#include <unistd.h>             // for some IPC/network system calls
+#include <asio.hpp>
+#include <asio/error_code.hpp>
+#include <asio/system_error.hpp>
+
 #include <cstdio>
 #include <vector>
 #include <iostream>
@@ -29,10 +40,6 @@
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
 
-#include <asio.hpp>
-#include <asio/error_code.hpp>
-#include <asio/system_error.hpp>
-
 #include <exceptions/exceptions.h>
 
 #include "data.h"

+ 4 - 1
src/lib/cc/session_unittests.cc

@@ -15,10 +15,13 @@
 // $Id: data_unittests.cc 1899 2010-05-21 12:03:59Z jelte $
 
 #include "config.h"
+
+// XXX: the ASIO header must be included before others.  See session.cc.
+#include <asio.hpp>
+
 #include <gtest/gtest.h>
 #include <session.h>
 
-#include <asio.hpp>
 #include <exceptions/exceptions.h>
 
 using namespace isc::cc;

+ 5 - 0
src/lib/config/tests/Makefile.am

@@ -2,7 +2,9 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 # see src/lib/cc/Makefile.am for -Wno-unused-parameter
+if USE_GXX
 AM_CXXFLAGS += -Wno-unused-parameter
+endif
 
 CLEANFILES = *.gcno *.gcda
 
@@ -20,6 +22,9 @@ run_unittests_LDADD =  $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 run_unittests_LDADD += libfake_session.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+# link *only* to data.o from lib/cc (more importantly, don't link in
+# the session class provided there, since we use our own fake_session
+# here)
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/data.o
 
 endif

+ 21 - 19
src/lib/datasrc/data_source.cc

@@ -192,7 +192,7 @@ refQuery(const Name& name, const RRClass& qclass, const DataSrc* ds,
         // Lookup failed
         return (false);
     }
-    
+
     // Referral bit is expected, so clear it when checking flags
     if ((newtask.flags & ~DataSrc::REFERRAL) != 0) {
         return (false);
@@ -202,18 +202,18 @@ refQuery(const Name& name, const RRClass& qclass, const DataSrc* ds,
 }
 
 // Match downward, from the zone apex to the query name, looking for
-// referrals.
+// referrals.  Note that we exclude the apex name and query name themselves;
+// they'll be handled in a normal lookup in the zone.
 inline bool
 hasDelegation(const DataSrc* ds, const Name* zonename, Query& q,
               QueryTaskPtr task)
 {
-    const int nlen = task->qname.getLabelCount();
-    const int diff = nlen - zonename->getLabelCount();
+    const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
     if (diff > 1) {
         bool found = false;
         RRsetList ref;
-        for (int i = diff; i > 1; --i) {
-            const Name sub(task->qname.split(i - 1, nlen - i));
+        for (int i = diff - 1; i > 0; --i) {
+            const Name sub(task->qname.split(i));
             if (refQuery(sub, q.qclass(), ds, zonename, ref)) {
                 found = true;
                 break;
@@ -360,11 +360,11 @@ proveNX(Query& q, QueryTaskPtr task, const DataSrc* ds,
 
         // Find the closest provable enclosing name for QNAME
         Name enclosure(zonename);
-        const int nlen = task->qname.getLabelCount();
-        const int diff = nlen - enclosure.getLabelCount();
+        const int diff = task->qname.getLabelCount() -
+            enclosure.getLabelCount();
         string hash2;
         for (int i = 1; i <= diff; ++i) {
-            enclosure = task->qname.split(i, nlen - i);
+            enclosure = task->qname.split(i);
             string nodehash(nsec3->getHash(enclosure));
             if (nodehash == hash1) {
                 break;
@@ -434,8 +434,7 @@ tryWildcard(Query& q, QueryTaskPtr task, const DataSrc* ds,
         return (DataSrc::SUCCESS);
     }
 
-    const int nlen = task->qname.getLabelCount();
-    const int diff = nlen - zonename->getLabelCount();
+    const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
     if (diff < 1) {
         return (DataSrc::SUCCESS);
     }
@@ -445,7 +444,7 @@ tryWildcard(Query& q, QueryTaskPtr task, const DataSrc* ds,
     bool cname = false;
 
     for (int i = 1; i <= diff; ++i) {
-        const Name& wname(star.concatenate(task->qname.split(i, nlen - i)));
+        const Name& wname(star.concatenate(task->qname.split(i)));
         QueryTask newtask(wname, task->qclass, task->qtype, Section::ANSWER(),
                           QueryTask::AUTH_QUERY); 
         result = doQueryTask(ds, zonename, newtask, wild);
@@ -541,8 +540,7 @@ DataSrc::doQuery(Query& q) {
         // (Note that RRtype DS queries need to go to the parent.)
         const int nlabels = task->qname.getLabelCount() - 1;
         NameMatch match(nlabels != 0 && task->qtype == RRType::DS() ?
-                        task->qname.split(1, task->qname.getLabelCount() - 1) :
-                        task->qname);
+                        task->qname.split(1) : task->qname);
         findClosestEnclosure(match, task->qclass);
         const DataSrc* datasource = match.bestDataSrc();
         const Name* zonename = match.closestName();
@@ -615,9 +613,12 @@ DataSrc::doQuery(Query& q) {
                     // the authority section.
                     RRsetList auth;
                     if (!refQuery(*zonename, q.qclass(), datasource, zonename,
-                                  auth)) {
-                        m.setRcode(Rcode::SERVFAIL());
-                        return;
+                                  auth) ||
+                        !auth.findRRset(RRType::NS(),
+                                        datasource->getClass())) {
+                        isc_throw(DataSourceError,
+                                  "NS RR not found in " << *zonename << "/" <<
+                                  datasource->getClass());
                     }
 
                     copyAuth(q, auth);
@@ -706,8 +707,9 @@ DataSrc::doQuery(Query& q) {
 
                 result = addSOA(q, zonename, datasource);
                 if (result != SUCCESS) {
-                    m.setRcode(Rcode::SERVFAIL());
-                    return;
+                    isc_throw(DataSourceError,
+                              "SOA RR not found in" << *zonename <<
+                              "/" << datasource->getClass());
                 }
             }
 

+ 2 - 4
src/lib/datasrc/sqlite3_datasrc.cc

@@ -330,7 +330,7 @@ int
 Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const {
     const unsigned int nlabels = name.getLabelCount();
     for (unsigned int i = 0; i < nlabels; ++i) {
-        const Name matchname(name.split(i, nlabels - i));
+        const Name matchname(name.split(i));
         const int rc = hasExactZone(matchname.toText().c_str());
         if (rc >= 0) {
             if (position != NULL) {
@@ -356,9 +356,7 @@ Sqlite3DataSrc::findClosestEnclosure(NameMatch& match,
         return;
     }
 
-    match.update(*this, match.qname().split(position,
-                                            match.qname().getLabelCount() -
-                                            position));
+    match.update(*this, match.qname().split(position));
 }
 
 DataSrc::Result

+ 2 - 2
src/lib/datasrc/tests/Makefile.am

@@ -22,8 +22,8 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
 run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a 
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a 
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a 
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a 
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 endif
 

+ 30 - 4
src/lib/datasrc/tests/datasrc_unittest.cc

@@ -540,6 +540,15 @@ TEST_F(DataSrcTest, Dname) {
     EXPECT_TRUE(it->isLast());
 }
 
+TEST_F(DataSrcTest, DnameExact) {
+    // The example.org test zone has a DNAME RR for dname2.foo.example.org.
+    // A query for that name with a different RR type than DNAME shouldn't
+    // confuse delegation processing.
+    createAndProcessQuery(Name("dname2.foo.example.org"), RRClass::IN(),
+                          RRType::A());
+    headerCheck(msg, Rcode::NOERROR(), true, true, true, 0, 1, 0);
+}
+
 TEST_F(DataSrcTest, Cname) {
     readAndProcessQuery("q_cname");
 
@@ -761,7 +770,7 @@ TEST_F(DataSrcTest, DS) {
 }
 
 TEST_F(DataSrcTest, CNAMELoop) {
-    createAndProcessQuery(Name("loop1.example.com"), RRClass::IN(),
+    createAndProcessQuery(Name("one.loop.example"), RRClass::IN(),
                           RRType::A());
 }
 
@@ -843,8 +852,8 @@ TEST_F(DataSrcTest, AddRemoveDataSrc) {
     EXPECT_EQ(0, ds.dataSrcCount());
 }
 
-#if 0                           // currently fails
-TEST_F(DataSrcTest, synthesizedCnameTooLong) {
+// currently fails
+TEST_F(DataSrcTest, DISABLED_synthesizedCnameTooLong) {
     // qname has the possible max length (255 octets).  it matches a DNAME,
     // and the synthesized CNAME would exceed the valid length.
     createAndProcessQuery(
@@ -854,6 +863,23 @@ TEST_F(DataSrcTest, synthesizedCnameTooLong) {
              "0123456789abcdef0123456789abcdef0123456789a.dname.example.org."),
         RRClass::IN(), RRType::A());
 }
-#endif
+
+TEST_F(DataSrcTest, noNSZone) {
+    EXPECT_THROW(createAndProcessQuery(Name("www.nons.example"),
+                                       RRClass::IN(), RRType::A()),
+                 DataSourceError);
+}
+
+TEST_F(DataSrcTest, noNSButDnameZone) {
+    EXPECT_THROW(createAndProcessQuery(Name("www.nons-dname.example"),
+                                       RRClass::IN(), RRType::A()),
+                 DataSourceError);
+}
+
+TEST_F(DataSrcTest, noSOAZone) {
+    EXPECT_THROW(createAndProcessQuery(Name("notexist.nosoa.example"),
+                                       RRClass::IN(), RRType::A()),
+                 DataSourceError);
+}
 
 }

File diff suppressed because it is too large
+ 431 - 667
src/lib/datasrc/tests/test_datasrc.cc


+ 1 - 0
src/lib/datasrc/tests/test_datasrc.h

@@ -96,6 +96,7 @@ private:
         ADDRESS,
         DELEGATION
     };
+    class RRsetMatch;
 
     void findRecords(const isc::dns::Name& name, const isc::dns::RRType& rdtype,
                      isc::dns::RRsetList& target,

+ 1 - 0
src/lib/datasrc/tests/testdata/example.org

@@ -11,3 +11,4 @@ mail.example.org. A 192.0.2.10
 sub.example.org. NS ns.sub.example.org.
 ns.sub.example.org. A 192.0.2.101
 dname.example.org. DNAME dname.example.info.
+dname2.foo.example.org. DNAME dname2.example.info.

BIN
src/lib/datasrc/tests/testdata/example.org.sqlite3


+ 24 - 46
src/lib/dns/Makefile.am

@@ -55,52 +55,30 @@ EXTRA_DIST += rdata/hs_4/a_1.h
 BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc
 #TODO: check this###BUILT_SOURCES = rdataclass.h rdataclass.cc
 
-lib_LTLIBRARIES = libdns.la
+lib_LTLIBRARIES = libdns++.la
 
-libdns_la_SOURCES = base32.h base32.cc
-libdns_la_SOURCES += base64.h base64.cc
-libdns_la_SOURCES += buffer.h
-libdns_la_SOURCES += dnssectime.h dnssectime.cc
-libdns_la_SOURCES += exceptions.h exceptions.cc
-libdns_la_SOURCES += hex.h hex.cc
-libdns_la_SOURCES += message.h message.cc
-libdns_la_SOURCES += messagerenderer.h messagerenderer.cc
-libdns_la_SOURCES += name.h name.cc
-libdns_la_SOURCES += rdata.h rdata.cc
-libdns_la_SOURCES += rrclass.cc
-libdns_la_SOURCES += rrparamregistry.h
-libdns_la_SOURCES += rrset.h rrset.cc
-libdns_la_SOURCES += rrsetlist.h rrsetlist.cc
-libdns_la_SOURCES += rrttl.h rrttl.cc
-libdns_la_SOURCES += rrtype.cc
-libdns_la_SOURCES += question.h question.cc
-libdns_la_SOURCES += sha1.h sha1.cc
-libdns_la_SOURCES += tsig.h tsig.cc
+libdns___la_SOURCES = base32.h base32.cc
+libdns___la_SOURCES += base64.h base64.cc
+libdns___la_SOURCES += buffer.h
+libdns___la_SOURCES += dnssectime.h dnssectime.cc
+libdns___la_SOURCES += exceptions.h exceptions.cc
+libdns___la_SOURCES += hex.h hex.cc
+libdns___la_SOURCES += message.h message.cc
+libdns___la_SOURCES += messagerenderer.h messagerenderer.cc
+libdns___la_SOURCES += name.h name.cc
+libdns___la_SOURCES += rdata.h rdata.cc
+libdns___la_SOURCES += rrclass.cc
+libdns___la_SOURCES += rrparamregistry.h
+libdns___la_SOURCES += rrset.h rrset.cc
+libdns___la_SOURCES += rrsetlist.h rrsetlist.cc
+libdns___la_SOURCES += rrttl.h rrttl.cc
+libdns___la_SOURCES += rrtype.cc
+libdns___la_SOURCES += question.h question.cc
+libdns___la_SOURCES += sha1.h sha1.cc
+libdns___la_SOURCES += tsig.h tsig.cc
 
-
-#if HAVE_BOOST_PYTHON
-## This is a loadable module for python scripts, so we use the prefix "pyexec"
-## to make sure the object files will be installed in the appropriate place
-## for this purpose.
-#pyexec_LTLIBRARIES = bind10_dns.la
-#bind10_dns_la_SOURCES = python_dns.cc
-#bind10_dns_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-#bind10_dns_la_CXXFLAGS = $(AM_CXXFLAGS) $(B10_CXXFLAGS)
-#if GCC_WERROR_OK
-## XXX: Boost.Python triggers strict aliasing violation, so if we use -Werror
-## we need to suppress the warnings.
-#bind10_dns_la_CXXFLAGS += -fno-strict-aliasing
-#endif
-#bind10_dns_la_LDFLAGS = $(BOOST_LDFLAGS) $(PYTHON_LDFLAGS)
-## Python prefers .so, while some OSes (specifically MacOS) use a different
-## suffix for dynamic objects.  -module is necessary to work this around.
-#bind10_dns_la_LDFLAGS += -module
-#bind10_dns_la_LIBADD = $(top_builddir)/src/lib/dns/libdns.la
-#bind10_dns_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-#bind10_dns_la_LIBADD += $(BOOST_PYTHON_LIB) $(PYTHON_LIB)
-#endif
-
-nodist_libdns_la_SOURCES = rdataclass.cc rrclass.h rrtype.h rrparamregistry.cc
+nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h
+nodist_libdns___la_SOURCES += rrparamregistry.cc
 
 rrclass.h: rrclass-placeholder.h
 rrtype.h: rrtype-placeholder.h
@@ -108,8 +86,8 @@ rrparamregistry.cc: rrparamregistry-placeholder.cc
 rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
 	./gen-rdatacode.py
 
-libdns_includedir = $(includedir)/dns
-libdns_include_HEADERS = \
+libdns++_includedir = $(includedir)/dns
+libdns++_include_HEADERS = \
 	buffer.h \
 	dnssectime.h \
 	exceptions.h \

+ 1 - 1
src/lib/dns/message.cc

@@ -923,7 +923,7 @@ SectionIterator<T>::operator*() const {
 template <typename T>
 const T*
 SectionIterator<T>::operator->() const {
-    return (impl_->it_.operator->());
+    return (&(operator*()));
 }
 
 template <typename T>

+ 1 - 1
src/lib/dns/name.cc

@@ -267,7 +267,7 @@ Name::Name(const std::string &namestring, bool downcase) {
         if (state == ft_ordinary) {
             assert(count != 0);
             ndata.at(offsets.back()) = count;
-            
+
             offsets.push_back(ndata.size());
             // add a trailing \0
             ndata.push_back('\0');

+ 13 - 8
src/lib/dns/python/Makefile.am

@@ -13,17 +13,22 @@ libdns_python_la_SOURCES = libdns_python.cc libdns_python_common.cc
 libdns_python_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
 libdns_python_la_LDFLAGS = $(PYTHON_LDFLAGS)
 
-#libdns_python_rrset_la_SOURCES = rrset_python.cc
-#libdns_python_rrset_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-#libdns_python_rrset_la_LDFLAGS = $(PYTHON_LDFLAGS) libdns_python_name.la
-
-#libdns_python_rrset_la_SOURCES = rrset_python.cc
-#libdns_python_rrset_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-#libdns_python_rrset_la_LDFLAGS = $(PYTHON_LDFLAGS)
+# directly included from source files, so these don't have their own
+# rules
+EXTRA_DIST = libdns_python_common.h
+EXTRA_DIST += messagerenderer_python.cc
+EXTRA_DIST += message_python.cc
+EXTRA_DIST += rrclass_python.cc
+EXTRA_DIST += name_python.cc
+EXTRA_DIST += rrset_python.cc
+EXTRA_DIST += question_python.cc
+EXTRA_DIST += rrttl_python.cc
+EXTRA_DIST += rdata_python.cc
+EXTRA_DIST += rrtype_python.cc
 
 # Python prefers .so, while some OSes (specifically MacOS) use a different
 # suffix for dynamic objects.  -module is necessary to work this around.
 libdns_python_la_LDFLAGS += -module
-libdns_python_la_LIBADD = $(top_builddir)/src/lib/dns/libdns.la
+libdns_python_la_LIBADD = $(top_builddir)/src/lib/dns/libdns++.la
 libdns_python_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 libdns_python_la_LIBADD += $(PYTHON_LIB)

+ 1 - 1
src/lib/dns/python/tests/Makefile.am

@@ -16,7 +16,7 @@ PYCOVERAGE = $(PYTHON)
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_srcdir)/src/lib/dns/python/.libs \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
 	TESTDATA_PATH=$(abs_top_srcdir)/src/lib/dns/tests/testdata \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

+ 2 - 4
src/lib/dns/rrsetlist.cc

@@ -29,8 +29,7 @@ namespace isc {
 namespace dns {
 
 void
-RRsetList::addRRset(RRsetPtr rrsetptr)
-{
+RRsetList::addRRset(RRsetPtr rrsetptr) {
     ConstRRsetPtr rrset_found = findRRset(rrsetptr->getType(),
                                           rrsetptr->getClass());
     if (rrset_found != NULL) {
@@ -42,8 +41,7 @@ RRsetList::addRRset(RRsetPtr rrsetptr)
 }
 
 RRsetPtr
-RRsetList::findRRset(const RRType& rrtype, const RRClass& rrclass)
-{
+RRsetList::findRRset(const RRType& rrtype, const RRClass& rrclass) {
     BOOST_FOREACH(RRsetPtr rrsetptr, rrsets_) {
         if ((rrsetptr->getClass() == rrclass) &&
             (rrsetptr->getType() == rrtype)) {

+ 1 - 1
src/lib/dns/rrsetlist.h

@@ -60,7 +60,7 @@ public:
     }
     P operator->() const
     {
-        return (it_.operator->());
+        return (&(operator*()));
     }
     bool operator==(const RRsetListIterator& other)
     {

+ 1 - 1
src/lib/dns/tests/Makefile.am

@@ -40,7 +40,7 @@ run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 endif
 

+ 1 - 1
src/lib/python/isc/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = datasrc cc config # Util
+SUBDIRS = datasrc cc config log # Util
 
 python_PYTHON = __init__.py
 

+ 1 - 0
src/lib/python/isc/__init__.py

@@ -2,3 +2,4 @@ import isc.datasrc
 import isc.cc
 import isc.config
 #import isc.dns
+import isc.log

+ 0 - 0
src/lib/python/isc/datasrc/master.py


Some files were not shown because too many files changed in this diff