Parcourir la source

[master] Merge branch 'trac3796' (statistics interface, part 1)

Conflicts:
	src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
	src/bin/dhcp6/tests/dhcp6_test_utils.cc
Tomek Mrugalski il y a 10 ans
Parent
commit
d3da062d51
53 fichiers modifiés avec 496 ajouts et 4869 suppressions
  1. 1 1
      src/bin/d2/bundy_d2_controller.h
  2. 1 1
      src/bin/d2/d2_process.cc
  3. 1 1
      src/bin/d2/d_cfg_mgr.cc
  4. 1 1
      src/bin/d2/d_controller.cc
  5. 1 1
      src/bin/d2/tests/bundy_d2_controller_unittests.cc
  6. 1 1
      src/bin/d2/tests/d2_controller_unittests.cc
  7. 1 1
      src/bin/d2/tests/d2_process_unittests.cc
  8. 1 1
      src/bin/d2/tests/d_cfg_mgr_unittests.cc
  9. 1 1
      src/bin/d2/tests/d_controller_unittests.cc
  10. 1 2
      src/bin/d2/tests/d_test_stubs.h
  11. 1 1
      src/bin/dhcp4/bundy_controller.cc
  12. 1 2
      src/bin/dhcp4/ctrl_dhcp4_srv.h
  13. 1 1
      src/bin/dhcp4/json_config_parser.cc
  14. 2 1
      src/bin/dhcp4/tests/config_parser_unittest.cc
  15. 1 1
      src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
  16. 1 1
      src/bin/dhcp4/tests/d2_unittest.h
  17. 2 3
      src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
  18. 1 1
      src/bin/dhcp4/tests/dhcp4_test_utils.cc
  19. 1 1
      src/bin/dhcp4/tests/dhcp4_test_utils.h
  20. 1 1
      src/bin/dhcp4/tests/kea_controller_unittest.cc
  21. 1 1
      src/bin/dhcp6/bundy_controller.cc
  22. 1 2
      src/bin/dhcp6/ctrl_dhcp6_srv.h
  23. 1 1
      src/bin/dhcp6/json_config_parser.cc
  24. 2 1
      src/bin/dhcp6/tests/config_parser_unittest.cc
  25. 1 1
      src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
  26. 1 1
      src/bin/dhcp6/tests/d2_unittest.h
  27. 1 1
      src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
  28. 1 1
      src/bin/dhcp6/tests/dhcp6_test_utils.cc
  29. 1 1
      src/bin/dhcp6/tests/hooks_unittest.cc
  30. 1 1
      src/bin/dhcp6/tests/kea_controller_unittest.cc
  31. 3 9
      src/lib/cc/Makefile.am
  32. 12 92
      src/lib/cc/cc_messages.mes
  33. 146 0
      src/lib/cc/command_interpreter.cc
  34. 134 0
      src/lib/cc/command_interpreter.h
  35. 0 58
      src/lib/cc/proto_defs.cc
  36. 0 73
      src/lib/cc/proto_defs.h
  37. 0 552
      src/lib/cc/session.cc
  38. 0 192
      src/lib/cc/session.h
  39. 2 2
      src/lib/cc/tests/Makefile.am
  40. 155 0
      src/lib/cc/tests/command_interpreter_unittests.cc
  41. 0 364
      src/lib/cc/tests/session_unittests.cc
  42. 0 1
      src/lib/config/Makefile.am
  43. 0 994
      src/lib/config/ccsession.cc
  44. 0 788
      src/lib/config/ccsession.h
  45. 2 5
      src/lib/config/tests/Makefile.am
  46. 0 1219
      src/lib/config/tests/ccsession_unittests.cc
  47. 0 274
      src/lib/config/tests/fake_session.cc
  48. 0 120
      src/lib/config/tests/fake_session.h
  49. 1 1
      src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc
  50. 1 1
      src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
  51. 7 6
      src/lib/dhcpsrv/testutils/config_result_check.cc
  52. 0 82
      src/lib/testutils/mockups.h
  53. 0 1
      src/lib/testutils/srv_test.h

+ 1 - 1
src/bin/d2/bundy_d2_controller.h

@@ -18,7 +18,7 @@
 #include <asiolink/io_service.h>
 #include <cc/data.h>
 #include <cc/session.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <d2/d2_log.h>
 #include <d2/d_controller.h>
 #include <d2/d_process.h>

+ 1 - 1
src/bin/d2/d2_process.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <d2/d2_log.h>
 #include <d2/d2_cfg_mgr.h>
 #include <d2/d2_process.h>

+ 1 - 1
src/bin/d2/d_cfg_mgr.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <d2/d2_log.h>
 #include <dhcp/libdhcp++.h>
 #include <d2/d_cfg_mgr.h>

+ 1 - 1
src/bin/d2/d_controller.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 #include <d2/d2_log.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <d2/d_controller.h>
 #include <exceptions/exceptions.h>
 #include <log/logger_support.h>

+ 1 - 1
src/bin/d2/tests/bundy_d2_controller_unittests.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <d_test_stubs.h>
 #include <d2/bundy_d2_controller.h>
 #include <d2/spec_config.h>

+ 1 - 1
src/bin/d2/tests/d2_controller_unittests.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <d_test_stubs.h>
 #include <d2/d2_controller.h>
 #include <d2/d2_process.h>

+ 1 - 1
src/bin/d2/tests/d2_process_unittests.cc

@@ -15,7 +15,7 @@
 #include <config.h>
 
 #include <asiolink/io_service.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <d2/d2_process.h>
 #include <dhcp_ddns/ncr_io.h>
 #include <d_test_stubs.h>

+ 1 - 1
src/bin/d2/tests/d_cfg_mgr_unittests.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <config/module_spec.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <d2/d_cfg_mgr.h>

+ 1 - 1
src/bin/d2/tests/d_controller_unittests.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <d_test_stubs.h>
 #include <d2/spec_config.h>
 

+ 1 - 2
src/bin/d2/tests/d_test_stubs.h

@@ -18,8 +18,7 @@
 #include <asiolink/io_service.h>
 
 #include <cc/data.h>
-#include <cc/session.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 
 #include <d2/d_controller.h>
 #include <d2/d_cfg_mgr.h>

+ 1 - 1
src/bin/dhcp4/bundy_controller.cc

@@ -17,7 +17,7 @@
 #include <asiolink/asiolink.h>
 #include <cc/data.h>
 #include <cc/session.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcp4/json_config_parser.h>
 #include <dhcp4/ctrl_dhcp4_srv.h>

+ 1 - 2
src/bin/dhcp4/ctrl_dhcp4_srv.h

@@ -17,8 +17,7 @@
 
 #include <asiolink/asiolink.h>
 #include <cc/data.h>
-#include <cc/session.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp4/dhcp4_srv.h>
 
 namespace isc {

+ 1 - 1
src/bin/dhcp4/json_config_parser.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp/option_definition.h>

+ 2 - 1
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -17,7 +17,8 @@
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
+#include <config/module_spec.h>
 #include <dhcp4/dhcp4_srv.h>
 #include <dhcp4/json_config_parser.h>
 #include <dhcp/option4_addrlst.h>

+ 1 - 1
src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp4/ctrl_dhcp4_srv.h>
 #include <hooks/hooks_manager.h>

+ 1 - 1
src/bin/dhcp4/tests/d2_unittest.h

@@ -18,7 +18,7 @@
 #define D2_UNITTEST_H
 
 #include <dhcp4/dhcp4_srv.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 
 #include <gtest/gtest.h>
 

+ 2 - 3
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc

@@ -16,7 +16,7 @@
 #include <sstream>
 
 #include <asiolink/io_address.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp4/tests/dhcp4_test_utils.h>
 #include <dhcp/tests/pkt_captures.h>
 #include <dhcp/dhcp4.h>
@@ -42,9 +42,8 @@
 #include <gtest/gtest.h>
 #include <hooks/server_hooks.h>
 #include <hooks/hooks_manager.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <stats/stats_mgr.h>
-
 #include <boost/scoped_ptr.hpp>
 
 #include <iostream>

+ 1 - 1
src/bin/dhcp4/tests/dhcp4_test_utils.cc

@@ -16,7 +16,7 @@
 
 #include <asiolink/io_address.h>
 #include <cc/data.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp4/json_config_parser.h>
 #include <dhcp4/tests/dhcp4_test_utils.h>
 #include <dhcp/option4_addrlst.h>

+ 1 - 1
src/bin/dhcp4/tests/dhcp4_test_utils.h

@@ -30,7 +30,7 @@
 #include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcp4/dhcp4_srv.h>
 #include <asiolink/io_address.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <list>
 
 #include <boost/shared_ptr.hpp>

+ 1 - 1
src/bin/dhcp4/tests/kea_controller_unittest.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcpsrv/cfgmgr.h>

+ 1 - 1
src/bin/dhcp6/bundy_controller.cc

@@ -17,7 +17,7 @@
 #include <asiolink/asiolink.h>
 #include <cc/data.h>
 #include <cc/session.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcpsrv/dhcp_config_parser.h>
 #include <dhcpsrv/cfgmgr.h>

+ 1 - 2
src/bin/dhcp6/ctrl_dhcp6_srv.h

@@ -17,8 +17,7 @@
 
 #include <asiolink/asiolink.h>
 #include <cc/data.h>
-#include <cc/session.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp6/dhcp6_srv.h>
 
 namespace isc {

+ 1 - 1
src/bin/dhcp6/json_config_parser.cc

@@ -16,7 +16,7 @@
 
 #include <asiolink/io_address.h>
 #include <cc/data.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcp6/dhcp6_log.h>

+ 2 - 1
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -14,7 +14,8 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
+#include <config/module_spec.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/iface_mgr.h>

+ 1 - 1
src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcp6/ctrl_dhcp6_srv.h>
 #include <hooks/hooks_manager.h>

+ 1 - 1
src/bin/dhcp6/tests/d2_unittest.h

@@ -18,7 +18,7 @@
 #define D2_UNITTEST_H
 
 #include <dhcp6/dhcp6_srv.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 
 #include <gtest/gtest.h>
 

+ 1 - 1
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -42,7 +42,7 @@
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/tests/dhcp6_client.h>
 #include <dhcp/tests/pkt_captures.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <boost/pointer_cast.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <gtest/gtest.h>

+ 1 - 1
src/bin/dhcp6/tests/dhcp6_test_utils.cc

@@ -16,8 +16,8 @@
 #include <gtest/gtest.h>
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/json_config_parser.h>
-#include <config/ccsession.h>
 #include <util/pointer_util.h>
+#include <cc/command_interpreter.h>
 #include <string.h>
 
 using namespace isc::data;

+ 1 - 1
src/bin/dhcp6/tests/hooks_unittest.cc

@@ -29,7 +29,7 @@
 
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp/tests/pkt_captures.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <boost/scoped_ptr.hpp>
 #include <gtest/gtest.h>
 #include <unistd.h>

+ 1 - 1
src/bin/dhcp6/tests/kea_controller_unittest.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcpsrv/cfgmgr.h>

+ 3 - 9
src/lib/cc/Makefile.am

@@ -2,7 +2,6 @@ SUBDIRS = . tests
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 
 AM_CXXFLAGS = $(KEA_CXXFLAGS)
 if USE_GXX
@@ -15,10 +14,10 @@ AM_CXXFLAGS += -fno-strict-aliasing
 endif
 
 lib_LTLIBRARIES = libkea-cc.la
-libkea_cc_la_SOURCES = data.cc data.h session.cc session.h
+libkea_cc_la_SOURCES = data.cc data.h
+libkea_cc_la_SOURCES += command_interpreter.cc command_interpreter.h
 libkea_cc_la_SOURCES += logger.cc logger.h
 nodist_libkea_cc_la_SOURCES = cc_messages.cc cc_messages.h
-libkea_cc_la_SOURCES += proto_defs.cc proto_defs.h
 libkea_cc_la_LIBADD = $(top_builddir)/src/lib/log/libkea-log.la
 
 CLEANFILES = *.gcno *.gcda session_config.h cc_messages.cc cc_messages.h \
@@ -33,11 +32,6 @@ s-messages: cc_messages.mes
 	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/cc/cc_messages.mes
 	touch $@
 
-BUILT_SOURCES = session_config.h cc_messages.cc cc_messages.h proto_defs.h
-
-# This rule is here, but we added proto_defs.h to the git repo,
-# so the script is no longer needed.
-#proto_defs.h: $(top_srcdir)/src/lib/util/python/const2hdr.py proto_defs.cc
-#	$(PYTHON) $(top_srcdir)/src/lib/util/python/const2hdr.py $(srcdir)/proto_defs.cc $@
+BUILT_SOURCES = session_config.h cc_messages.cc cc_messages.h
 
 EXTRA_DIST = cc_messages.mes

+ 12 - 92
src/lib/cc/cc_messages.mes

@@ -14,99 +14,19 @@
 
 $NAMESPACE isc::cc
 
-% CC_ASYNC_READ_FAILED asynchronous read failed (error code = %1)
-This marks a low level error, we tried to read data from the message queue
-daemon asynchronously, but the ASIO library returned an error.
+% CC_RECEIVE Received a message over control channel: %1
+Debug message, noting that a message was received over control channel.
 
-% CC_CONN_ERROR error connecting to message queue (%1)
-It is impossible to reach the message queue daemon for the reason given. It
-is unlikely there'll be reason for whatever program this currently is to
-continue running, as the communication with the rest of Kea is vital
-for the components.
+% CC_SEND Sending message over control channel: '%1'
+Debug message, the code is about to send a message over the control channel.
 
-% CC_DISCONNECT disconnecting from message queue daemon
-The library is disconnecting from the message queue daemon. This debug message
-indicates that the program is trying to shut down gracefully.
+% CC_REGISTER_COMMAND_HANDLER Handler for command '%1' registered
+Command Handler for a given command has been registered. This means that
+the software enabled handling of said command.
 
-% CC_ESTABLISH trying to establish connection with message queue daemon at %1
-This debug message indicates that the command channel library is about to
-connect to the message queue daemon, which should be listening on the UNIX-domain
-socket listed in the output.
+% CC_PROCESS_COMMAND Processing command '%1'
+Debug message, noting that the software is processing received command.
 
-% CC_ESTABLISHED successfully connected to message queue daemon
-This debug message indicates that the connection was successfully made, this
-should follow CC_ESTABLISH.
-
-% CC_GROUP_RECEIVE trying to receive a message with seq %1
-Debug message, noting that a message is expected to come over the command
-channel.
-
-% CC_GROUP_RECEIVED message arrived ('%1', '%2')
-Debug message, noting that we successfully received a message (its envelope and
-payload listed). This follows CC_GROUP_RECEIVE, but might happen some time
-later, depending if we waited for it or just polled.
-
-% CC_GROUP_SEND sending message '%1' to group '%2'
-Debug message, we're about to send a message over the command channel.
-
-% CC_INVALID_LENGTHS invalid length parameters (%1, %2)
-This happens when garbage comes over the command channel or some kind of
-confusion happens in the program. The data received from the socket make no
-sense if we interpret it as lengths of message. The first one is total length
-of the message; the second is the length of the header. The header
-and its length (2 bytes) is counted in the total length.
-
-% CC_LENGTH_NOT_READY length not ready
-There should be data representing the length of message on the socket, but it
-is not there.
-
-% CC_LNAME_RECEIVED received local name: %1
-Debug message: the local module received its unique identifier (name)
-from msgq on completion of establishing the session with msgq.
-
-% CC_NO_MESSAGE no message ready to be received yet
-The program polled for incoming messages, but there was no message waiting.
-This is a debug message which may happen only after CC_GROUP_RECEIVE.
-
-% CC_NO_MSGQ unable to connect to message queue (%1)
-It isn't possible to connect to the message queue daemon, for reason listed.
-It is unlikely any program will be able continue without the communication.
-
-% CC_READ_ERROR error reading data from command channel (%1)
-A low level error happened when the library tried to read data from the
-command channel socket. The reason is listed.
-
-% CC_READ_EXCEPTION error reading data from command channel (%1)
-We received an exception while trying to read data from the command
-channel socket. The reason is listed.
-
-% CC_REPLY replying to message from '%1' with '%2'
-Debug message, noting we're sending a response to the original message
-with the given envelope.
-
-% CC_SET_TIMEOUT setting timeout to %1ms
-Debug message. A timeout for which the program is willing to wait for a reply
-is being set.
-
-% CC_START_READ starting asynchronous read
-Debug message. From now on, when a message (or command) comes, it'll wake the
-program and the library will automatically pass it over to correct place.
-
-% CC_SUBSCRIBE subscribing to communication group %1
-Debug message. The program wants to receive messages addressed to this group.
-
-% CC_TIMEOUT timeout reading data from command channel
-The program waited too long for data from the command channel (usually when it
-sent a query to different program and it didn't answer for whatever reason).
-
-% CC_UNSUBSCRIBE unsubscribing from communication group %1
-Debug message. The program no longer wants to receive messages addressed to
-this group.
-
-% CC_WRITE_ERROR error writing data to command channel (%1)
-A low level error happened when the library tried to write data to the command
-channel socket.
-
-% CC_ZERO_LENGTH invalid message length (0)
-The library received a message length being zero, which makes no sense, since
-all messages must contain at least the envelope.
+% CC_READ_ERROR Received truncated or malformed command (%1)
+A read error indicates that either the communication was interrupted (e.g.
+truncated packet received) or the entity had sent malformed command.

+ 146 - 0
src/lib/cc/command_interpreter.cc

@@ -0,0 +1,146 @@
+// Copyright (C) 2009,2015  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include <cc/command_interpreter.h>
+#include <string>
+#include <cc/data.h>
+
+using namespace std;
+
+using isc::data::Element;
+using isc::data::ConstElementPtr;
+using isc::data::ElementPtr;
+using isc::data::JSONError;
+
+namespace isc {
+namespace config {
+
+const char *CONTROL_COMMAND = "command";
+const char *CONTROL_RESULT = "result";
+const char *CONTROL_TEXT = "text";
+const char *CONTROL_ARGUMENTS = "arguments";
+
+// Full version, with status, text and arguments
+ConstElementPtr
+createAnswer(const int status_code, const std::string& text,
+             const ConstElementPtr& arg) {
+    if (status_code != 0 && text.empty()) {
+        isc_throw(CtrlChannelError, "Text has to be provided for status_code != 0");
+    }
+
+    ElementPtr answer = Element::createMap();
+    ElementPtr result = Element::create(status_code);
+    answer->set(CONTROL_RESULT, result);
+
+    if (!text.empty()) {
+        answer->set(CONTROL_TEXT, Element::create(text));
+    }
+    if (arg) {
+        answer->set(CONTROL_ARGUMENTS, arg);
+    }
+    return (answer);
+}
+
+ConstElementPtr
+createAnswer() {
+    return (createAnswer(0, string(""), ConstElementPtr()));
+}
+
+ConstElementPtr
+createAnswer(const int status_code, const std::string& text) {
+    return (createAnswer(status_code, text, ElementPtr()));
+}
+
+ConstElementPtr
+createAnswer(const int status_code, const ConstElementPtr& arg) {
+    return (createAnswer(status_code, "", arg));
+}
+
+ConstElementPtr
+parseAnswer(int &rcode, const ConstElementPtr& msg) {
+    if (!msg) {
+        isc_throw(CtrlChannelError, "No answer specified");
+    }
+    if (msg->getType() != Element::map) {
+        isc_throw(CtrlChannelError,
+                  "Invalid answer Element specified, expected map");
+    }
+    if (!msg->contains(CONTROL_RESULT)) {
+        isc_throw(CtrlChannelError,
+                  "Invalid answer specified, does not contain mandatory 'result'");
+    }
+
+    ConstElementPtr result = msg->get(CONTROL_RESULT);
+    if (result->getType() != Element::integer) {
+            isc_throw(CtrlChannelError,
+                      "Result element in answer message is not a string");
+    }
+
+    rcode = result->intValue();
+
+    // If there are arguments, return them.
+    ConstElementPtr args = msg->get(CONTROL_ARGUMENTS);
+    if (args) {
+        return (args);
+    }
+
+    // There are no arguments, let's try to return just the text status
+    return (msg->get(CONTROL_TEXT));
+}
+
+ConstElementPtr
+createCommand(const std::string& command) {
+    return (createCommand(command, ElementPtr()));
+}
+
+ConstElementPtr
+createCommand(const std::string& command, ConstElementPtr arg) {
+    ElementPtr query = Element::createMap();
+    ElementPtr cmd = Element::create(command);
+    query->set(CONTROL_COMMAND, cmd);
+    if (arg) {
+        query->set(CONTROL_ARGUMENTS, arg);
+    }
+    return (query);
+}
+
+std::string
+parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
+    if (!command) {
+        isc_throw(CtrlChannelError, "No command specified");
+    }
+    if (command->getType() != Element::map) {
+        isc_throw(CtrlChannelError, "Invalid command Element specified, expected map");
+    }
+    if (!command->contains(CONTROL_COMMAND)) {
+        isc_throw(CtrlChannelError,
+                  "Invalid answer specified, does not contain mandatory 'command'");
+    }
+
+    ConstElementPtr cmd = command->get(CONTROL_COMMAND);
+    if (cmd->getType() != Element::string) {
+        isc_throw(CtrlChannelError,
+                  "'command' element in command message is not a string");
+    }
+
+    arg = command->get(CONTROL_ARGUMENTS);
+
+    return (cmd->stringValue());
+}
+
+}
+}

+ 134 - 0
src/lib/cc/command_interpreter.h

@@ -0,0 +1,134 @@
+// Copyright (C) 2009,2015  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef COMMAND_INTERPRETER_H
+#define COMMAND_INTERPRETER_H
+
+#include <cc/data.h>
+#include <string>
+
+/// @file command_interpreter.h
+///
+/// This file contains several functions and constants that are used for
+/// handling commands and responses sent over control channel. The design
+/// is described here: http://kea.isc.org/wiki/StatsDesign, but also
+/// in @ref ctrlSocket section in the Developer's Guide.
+
+namespace isc {
+namespace config {
+
+/// @brief String used for commands ("command")
+extern const char *CONTROL_COMMAND;
+
+/// @brief String used for result, i.e. integer status ("result")
+extern const char *CONTROL_RESULT;
+
+/// @brief String used for storing textual description ("text")
+extern const char *CONTROL_TEXT;
+
+/// @brief String used for arguments map ("arguments")
+extern const char *CONTROL_ARGUMENTS;
+
+/// @brief Status code indicating a successful operation
+const int CONTROL_RESULT_SUCCESS = 0;
+
+/// @brief Status code indicating a general failure
+const int CONTROL_RESULT_ERROR = 1;
+
+/// @brief A standard control channel exception that is thrown if a function
+/// is there is a problem with one of the messages
+class CtrlChannelError : public isc::Exception {
+public:
+    CtrlChannelError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// @brief Creates a standard config/command level success answer message
+///        (i.e. of the form { "result": 0 }
+/// @return Standard command/config success answer message
+isc::data::ConstElementPtr createAnswer();
+
+/// @brief Creates a standard config/command level answer message
+/// (i.e. of the form { "result": 1, "text": "Invalid command received" }
+///
+/// @param status_code The return code (0 for success)
+/// @param status_text A string to put into the "text" argument
+/// @return Standard command/config answer message
+isc::data::ConstElementPtr createAnswer(const int status_code,
+                                        const std::string& status_text);
+
+/// @brief Creates a standard config/command level answer message
+/// (i.e. of the form { "result": status_code, "arguments": arg }
+///
+/// @param status_code The return code (0 for success)
+/// @param arg The optional argument for the answer. This can be of
+///        any Element type. May be NULL.
+/// @return Standard command/config answer message
+isc::data::ConstElementPtr createAnswer(const int status_code,
+                                        const isc::data::ConstElementPtr& arg);
+
+/// @brief Creates a standard config/command level answer message
+///
+/// @param status_code The return code (0 for success)
+/// @param status textual represenation of the status (used mostly for errors)
+/// @param arg The optional argument for the answer. This can be of
+///        any Element type. May be NULL.
+/// @return Standard command/config answer message
+isc::data::ConstElementPtr createAnswer(const int status_code,
+                                        const std::string& status,
+                                        const isc::data::ConstElementPtr& arg);
+
+/// @brief Parses a standard config/command level answer message.
+///
+/// @param status_code This value will be set to the return code contained in
+///              the message
+/// @param msg The message to parse
+/// @return The optional argument in the message.
+isc::data::ConstElementPtr parseAnswer(int &status_code,
+                                       const isc::data::ConstElementPtr& msg);
+
+/// @brief Creates a standard config/command command message with no
+/// argument (of the form { "command": "my_command" })
+///
+/// @param command The command string
+/// @return The created message
+isc::data::ConstElementPtr createCommand(const std::string& command);
+
+/// @brief Creates a standard config/command command message with the
+/// given argument (of the form { "command": "my_command", "arguments": arg }
+///
+/// @param command The command string
+/// @param arg The optional argument for the command. This can be of
+///        any Element type. May be NULL.
+/// @return The created message
+isc::data::ConstElementPtr createCommand(const std::string& command,
+                                         isc::data::ConstElementPtr arg);
+
+/// @brief Parses the given command into a string containing the actual
+///        command and an ElementPtr containing the optional argument.
+///
+/// @throw Raises a CtrlChannelError if this is not a well-formed command
+///
+/// @param arg This value will be set to the ElementPtr pointing to
+///        the argument, or to an empty Map (ElementPtr) if there was none.
+/// @param command The command message containing the command (as made
+///        by createCommand()
+/// @return The command name
+std::string parseCommand(isc::data::ConstElementPtr& arg,
+                         isc::data::ConstElementPtr command);
+
+}; // end of namespace isc::config
+}; // end of namespace isc
+
+#endif // COMMAND_INTERPRETER_H

+ 0 - 58
src/lib/cc/proto_defs.cc

@@ -1,58 +0,0 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <cc/proto_defs.h>
-
-namespace isc {
-namespace cc {
-
-// Aside from defining the values for the C++ library, this file is also
-// used as direct input of the generator of the python counterpart. Please,
-// keep the syntax here simple and check the generated file
-// (lib/python/isc/cc/proto_defs.py) is correct and sane.
-
-// The constants used in the CC protocol
-// First the header names
-const char* const CC_HEADER_TYPE = "type";
-const char* const CC_HEADER_FROM = "from";
-const char* const CC_HEADER_TO = "to";
-const char* const CC_HEADER_GROUP = "group";
-const char* const CC_HEADER_INSTANCE = "instance";
-const char* const CC_HEADER_SEQ = "seq";
-const char* const CC_HEADER_WANT_ANSWER = "want_answer";
-const char* const CC_HEADER_REPLY = "reply";
-// The commands in the "type" header
-const char* const CC_COMMAND_SEND = "send";
-const char* const CC_COMMAND_SUBSCRIBE = "subscribe";
-const char* const CC_COMMAND_UNSUBSCRIBE = "unsubscribe";
-const char* const CC_COMMAND_GET_LNAME = "getlname";
-const char* const CC_COMMAND_PING = "ping";
-const char* const CC_COMMAND_PONG = "pong";
-const char* const CC_COMMAND_STOP = "stop";
-// The wildcards of some headers
-const char* const CC_TO_WILDCARD = "*";
-const char* const CC_INSTANCE_WILDCARD = "*";
-// Prefixes for groups
-const char* const CC_GROUP_NOTIFICATION_PREFIX = "notifications/";
-// Reply codes
-const int CC_REPLY_NO_RECPT = -1;
-const int CC_REPLY_SUCCESS = 0;
-// Payload in the message
-const char *const CC_PAYLOAD_LNAME = "lname";
-const char *const CC_PAYLOAD_RESULT = "result";
-const char *const CC_PAYLOAD_COMMAND = "command";
-const char *const CC_PAYLOAD_NOTIFICATION = "notification";
-
-}
-}

+ 0 - 73
src/lib/cc/proto_defs.h

@@ -1,73 +0,0 @@
-// This file is generated from ./proto_defs.cc
-// by the const2hdr.py script.
-// Do not edit, all changes will be lost.
-
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef KEA_COMMON_DEFS_H
-#define KEA_COMMON_DEFS_H
-
-// \file proto_defs.h
-// \brief Common shared constants
-
-// This file contains common definitions of constasts used across the sources.
-// It includes, but is not limited to the definitions of messages sent from
-// one process to another. Since the names should be self-explanatory and
-// the variables here are used mostly to synchronize the same values across
-// multiple programs, separate documentation for each variable is not provided.
-
-namespace isc {
-namespace cc {
-
-// Aside from defining the values for the C++ library, this file is also
-// used as direct input of the generator of the python counterpart. Please,
-// keep the syntax here simple and check the generated file
-// (lib/python/isc/cc/proto_defs.py) is correct and sane.
-
-// The constants used in the CC protocol
-// First the header names
-extern const char* const CC_HEADER_TYPE;
-extern const char* const CC_HEADER_FROM;
-extern const char* const CC_HEADER_TO;
-extern const char* const CC_HEADER_GROUP;
-extern const char* const CC_HEADER_INSTANCE;
-extern const char* const CC_HEADER_SEQ;
-extern const char* const CC_HEADER_WANT_ANSWER;
-extern const char* const CC_HEADER_REPLY;
-// The commands in the "type" header
-extern const char* const CC_COMMAND_SEND;
-extern const char* const CC_COMMAND_SUBSCRIBE;
-extern const char* const CC_COMMAND_UNSUBSCRIBE;
-extern const char* const CC_COMMAND_GET_LNAME;
-extern const char* const CC_COMMAND_PING;
-extern const char* const CC_COMMAND_PONG;
-extern const char* const CC_COMMAND_STOP;
-// The wildcards of some headers
-extern const char* const CC_TO_WILDCARD;
-extern const char* const CC_INSTANCE_WILDCARD;
-// Prefixes for groups
-extern const char* const CC_GROUP_NOTIFICATION_PREFIX;
-// Reply codes
-extern const int CC_REPLY_NO_RECPT;
-extern const int CC_REPLY_SUCCESS;
-// Payload in the message
-extern const char *const CC_PAYLOAD_LNAME;
-extern const char *const CC_PAYLOAD_RESULT;
-extern const char *const CC_PAYLOAD_COMMAND;
-extern const char *const CC_PAYLOAD_NOTIFICATION;
-
-}
-}
-#endif

+ 0 - 552
src/lib/cc/session.cc

@@ -1,552 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <cc/session_config.h>
-#include <cc/logger.h>
-
-#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/deadline_timer.hpp>
-#include <asio/system_error.hpp>
-
-#include <cc/data.h>
-#include <cc/session.h>
-
-#include <cstdio>
-#include <vector>
-#include <iostream>
-#include <sstream>
-
-#include <sys/un.h>
-
-#include <boost/bind.hpp>
-#include <boost/optional.hpp>
-#include <boost/function.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <exceptions/exceptions.h>
-
-using namespace std;
-using namespace isc::cc;
-using namespace isc::data;
-
-// some of the asio names conflict with socket API system calls
-// (e.g. write(2)) so we don't import the entire asio namespace.
-using asio::io_service;
-
-namespace {
-/// \brief Sets the given Optional 'result' to the given error code
-/// Used as a callback for emulating sync reads with async calls
-/// \param result Pointer to the optional to set
-/// \param err The error code to set it to
-void
-setResult(boost::optional<asio::error_code>* result,
-          const asio::error_code& err)
-{
-    result->reset(err);
-}
-}
-
-namespace isc {
-namespace cc {
-
-class SessionImpl {
-public:
-    SessionImpl(io_service& io_service) :
-        sequence_(-1), queue_(Element::createList()),
-        io_service_(io_service), socket_(io_service_), data_length_(0),
-        timeout_(MSGQ_DEFAULT_TIMEOUT)
-    {}
-    void establish(const char& socket_file);
-    void disconnect();
-    void writeData(const void* data, size_t datalen);
-    size_t readDataLength();
-    // Blocking read. Will throw a SessionTimeout if the timeout value
-    // (in seconds) is thrown. If timeout is 0 it will block forever
-    void readData(void* data, size_t datalen);
-    void startRead(boost::function<void()> user_handler);
-    void setTimeout(size_t seconds) { timeout_ = seconds; };
-    size_t getTimeout() const { return timeout_; };
-    int getSocketDesc();
-
-    long int sequence_; // the next sequence number to use
-    std::string lname_;
-    ElementPtr queue_;
-
-private:
-    void internalRead(const asio::error_code& error,
-                      size_t bytes_transferred);
-
-private:
-    io_service& io_service_;
-    asio::local::stream_protocol::socket socket_;
-    uint32_t data_length_;
-    boost::function<void()> user_handler_;
-    asio::error_code error_;
-    size_t timeout_;
-
-    // By default, unless changed or disabled, blocking reads on
-    // the msgq channel will time out after 4 seconds in this
-    // implementation.
-    // This number is chosen to be low enough so that whatever
-    // component is blocking does not seem to be hanging, but
-    // still gives enough time for other modules to respond if they
-    // are busy. If this choice turns out to be a bad one, we can
-    // change it later.
-    static const size_t MSGQ_DEFAULT_TIMEOUT = 4000;
-};
-
-void
-SessionImpl::establish(const char& socket_file) {
-    try {
-        LOG_DEBUG(logger, DBG_TRACE_BASIC, CC_ESTABLISH).arg(&socket_file);
-        socket_.connect(asio::local::stream_protocol::endpoint(&socket_file),
-                        error_);
-        LOG_DEBUG(logger, DBG_TRACE_BASIC, CC_ESTABLISHED);
-    } catch(const asio::system_error& se) {
-        LOG_FATAL(logger, CC_CONN_ERROR).arg(se.what());
-        isc_throw(SessionError, se.what());
-    }
-    if (error_) {
-        LOG_FATAL(logger, CC_NO_MSGQ).arg(error_.message());
-        isc_throw(SessionError, "Unable to connect to message queue: " <<
-                  error_.message());
-    }
-}
-
-void
-SessionImpl::disconnect() {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, CC_DISCONNECT);
-    socket_.close();
-    data_length_ = 0;
-}
-
-void
-SessionImpl::writeData(const void* data, size_t datalen) {
-    try {
-        asio::write(socket_, asio::buffer(data, datalen));
-    } catch (const asio::system_error& asio_ex) {
-        LOG_FATAL(logger, CC_WRITE_ERROR).arg(asio_ex.what());
-        isc_throw(SessionError, "ASIO write failed: " << asio_ex.what());
-    }
-}
-
-size_t
-SessionImpl::readDataLength() {
-    size_t ret_len = data_length_;
-    
-    if (ret_len == 0) {
-        readData(&data_length_, sizeof(data_length_));
-        if (data_length_ == 0) {
-            LOG_ERROR(logger, CC_LENGTH_NOT_READY);
-            isc_throw(SessionError, "ASIO read: data length is not ready");
-        }
-        ret_len = ntohl(data_length_);
-    }
-
-    data_length_ = 0;
-    return (ret_len);
-}
-
-void
-SessionImpl::readData(void* data, size_t datalen) {
-    boost::optional<asio::error_code> read_result;
-    boost::optional<asio::error_code> timer_result;
-
-    try {
-        asio::async_read(socket_, asio::buffer(data, datalen),
-                         boost::bind(&setResult, &read_result, _1));
-        asio::deadline_timer timer(socket_.io_service());
-
-        if (getTimeout() != 0) {
-            timer.expires_from_now(boost::posix_time::milliseconds(getTimeout()));
-            timer.async_wait(boost::bind(&setResult, &timer_result, _1));
-        }
-
-        // wait until either we have read the data we want, the
-        // timer expires, or one of the two is triggered with an error.
-        // When one of them has a result, cancel the other, and wait
-        // until the cancel is processed before we continue
-        while (!read_result && !timer_result) {
-            socket_.io_service().run_one();
-
-            // Don't cancel the timer if we haven't set it
-            if (read_result && getTimeout() != 0) {
-                timer.cancel();
-                while (!timer_result) {
-                    socket_.io_service().run_one();
-                }
-            } else if (timer_result) {
-                socket_.cancel();
-                while (!read_result) {
-                    socket_.io_service().run_one();
-                }
-            }
-        }
-
-        // asio::error_code evaluates to false if there was no error
-        if (*read_result) {
-            if (*read_result == asio::error::operation_aborted) {
-                LOG_ERROR(logger, CC_TIMEOUT);
-                isc_throw(SessionTimeout,
-                          "Timeout while reading data from cc session");
-            } else {
-                LOG_ERROR(logger, CC_READ_ERROR).arg(read_result->message());
-                isc_throw(SessionError,
-                          "Error while reading data from cc session: " <<
-                          read_result->message());
-            }
-        }
-    } catch (const asio::system_error& asio_ex) {
-        // to hide ASIO specific exceptions, we catch them explicitly
-        // and convert it to SessionError.
-        LOG_FATAL(logger, CC_READ_EXCEPTION).arg(asio_ex.what());
-        isc_throw(SessionError, "ASIO read failed: " << asio_ex.what());
-    }
-}
-
-void
-SessionImpl::startRead(boost::function<void()> user_handler) {
-    data_length_ = 0;
-    user_handler_ = user_handler;
-    asio::async_read(socket_, asio::buffer(&data_length_,
-                                           sizeof(data_length_)),
-                     boost::bind(&SessionImpl::internalRead, this,
-                                 asio::placeholders::error,
-                                 asio::placeholders::bytes_transferred));
-}
-
-void
-SessionImpl::internalRead(const asio::error_code& error,
-                          size_t bytes_transferred)
-{
-    if (!error) {
-        assert(bytes_transferred == sizeof(data_length_));
-        data_length_ = ntohl(data_length_);
-        if (data_length_ == 0) {
-            LOG_ERROR(logger, CC_ZERO_LENGTH);
-            isc_throw(SessionError, "Invalid message length (0)");
-        }
-        user_handler_();
-    } else {
-        LOG_ERROR(logger, CC_ASYNC_READ_FAILED).arg(error.value());
-        isc_throw(SessionError, "asynchronous read failed");
-    }
-}
-
-int
-SessionImpl::getSocketDesc() {
-    /// @todo boost 1.42 uses native() method, but it is deprecated
-    /// in 1.49 and native_handle() is recommended instead
-    if (!socket_.is_open()) {
-        isc_throw(InvalidOperation, "Can't return socket descriptor: no socket opened.");
-    }
-    return socket_.native();
-}
-
-Session::Session(asio::io_service& io_service) :
-    impl_(new SessionImpl(io_service))
-{}
-
-Session::~Session() {
-    delete impl_;
-}
-
-void
-Session::disconnect() {
-    impl_->disconnect();
-}
-
-void
-Session::startRead(boost::function<void()> read_callback) {
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_START_READ);
-    impl_->startRead(read_callback);
-}
-
-int
-Session::getSocketDesc() const {
-    return impl_->getSocketDesc();
-}
-
-namespace {                     // maybe unnecessary.
-// This is a helper class to make the establish() method (below) exception-safe
-// with the RAII approach.
-class SessionHolder {
-public:
-    SessionHolder(SessionImpl* obj) : impl_obj_(obj) {}
-    ~SessionHolder()
-    {
-        if (impl_obj_ != NULL) {
-            impl_obj_->disconnect();
-        }
-    }
-    void clear() { impl_obj_ = NULL; }
-    SessionImpl* impl_obj_;
-};
-}
-
-void
-Session::establish(const char* socket_file) {
-    if (socket_file == NULL) {
-        socket_file = getenv("BUNDY_MSGQ_SOCKET_FILE");
-    }
-    if (socket_file == NULL) {
-        socket_file = BUNDY_MSGQ_SOCKET_FILE;
-    }
-
-    impl_->establish(*socket_file);
-
-    // once established, encapsulate the implementation object so that we
-    // can safely release the internal resource when exception happens
-    // below.
-    SessionHolder session_holder(impl_);
-
-    //
-    // send a request for our local name, and wait for a response
-    //
-    ElementPtr get_lname_msg(Element::createMap());
-    get_lname_msg->set(CC_HEADER_TYPE, Element::create(CC_COMMAND_GET_LNAME));
-    sendmsg(get_lname_msg);
-
-    ConstElementPtr routing, msg;
-    recvmsg(routing, msg, false);
-
-    impl_->lname_ = msg->get(CC_PAYLOAD_LNAME)->stringValue();
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_LNAME_RECEIVED).arg(impl_->lname_);
-
-    // At this point there's no risk of resource leak.
-    session_holder.clear();
-}
-
-//
-// Convert to wire format and send this via the stream socket with its length
-// prefix.
-//
-void
-Session::sendmsg(ConstElementPtr header) {
-    std::string header_wire = header->toWire();
-    unsigned int length = 2 + header_wire.length();
-    unsigned int length_net = htonl(length);
-    unsigned short header_length = header_wire.length();
-    unsigned short header_length_net = htons(header_length);
-
-    impl_->writeData(&length_net, sizeof(length_net));
-    impl_->writeData(&header_length_net, sizeof(header_length_net));
-    impl_->writeData(header_wire.data(), header_length);
-}
-
-void
-Session::sendmsg(ConstElementPtr header, ConstElementPtr payload) {
-    std::string header_wire = header->toWire();
-    std::string body_wire = payload->toWire();
-    unsigned int length = 2 + header_wire.length() + body_wire.length();
-    unsigned int length_net = htonl(length);
-    unsigned short header_length = header_wire.length();
-    unsigned short header_length_net = htons(header_length);
-
-    impl_->writeData(&length_net, sizeof(length_net));
-    impl_->writeData(&header_length_net, sizeof(header_length_net));
-    impl_->writeData(header_wire.data(), header_length);
-    impl_->writeData(body_wire.data(), body_wire.length());
-}
-
-bool
-Session::recvmsg(ConstElementPtr& msg, bool nonblock, int seq) {
-    ConstElementPtr l_env;
-    return (recvmsg(l_env, msg, nonblock, seq));
-}
-
-bool
-Session::recvmsg(ConstElementPtr& env, ConstElementPtr& msg,
-                 bool nonblock, int seq)
-{
-    size_t length = impl_->readDataLength();
-    if (hasQueuedMsgs()) {
-        ConstElementPtr q_el;
-        for (size_t i = 0; i < impl_->queue_->size(); i++) {
-            q_el = impl_->queue_->get(i);
-            if (( seq == -1 &&
-                  !q_el->get(0)->contains(CC_HEADER_REPLY)
-                ) || (
-                  q_el->get(0)->contains(CC_HEADER_REPLY) &&
-                  q_el->get(0)->get(CC_HEADER_REPLY)->intValue() == seq
-                )
-               ) {
-                   env = q_el->get(0);
-                   msg = q_el->get(1);
-                   impl_->queue_->remove(i);
-                   return (true);
-            }
-        }
-    }
-    
-    unsigned short header_length_net;
-    impl_->readData(&header_length_net, sizeof(header_length_net));
-
-    unsigned short header_length = ntohs(header_length_net);
-    if (header_length > length || length < 2) {
-        LOG_ERROR(logger, CC_INVALID_LENGTHS).arg(length).arg(header_length);
-        isc_throw(SessionError, "Length parameters invalid: total=" << length
-                  << ", header=" << header_length);
-    }
-
-    // remove the header-length bytes from the total length
-    length -= 2;
-    std::vector<char> buffer(length);
-    impl_->readData(&buffer[0], length);
-
-    std::string header_wire = std::string(&buffer[0], header_length);
-    std::string body_wire = std::string(&buffer[0] + header_length,
-                                        length - header_length);
-    std::stringstream header_wire_stream;
-    header_wire_stream << header_wire;
-    ConstElementPtr l_env =
-        Element::fromWire(header_wire_stream, header_length);
-    
-    std::stringstream body_wire_stream;
-    body_wire_stream << body_wire;
-    ConstElementPtr l_msg =
-        Element::fromWire(body_wire_stream, length - header_length);
-    if ((seq == -1 &&
-         !l_env->contains(CC_HEADER_REPLY)
-        ) || (
-         l_env->contains(CC_HEADER_REPLY) &&
-         l_env->get(CC_HEADER_REPLY)->intValue() == seq
-        )
-       ) {
-        env = l_env;
-        msg = l_msg;
-        return (true);
-    } else {
-        ElementPtr q_el = Element::createList();
-        q_el->add(l_env);
-        q_el->add(l_msg);
-        impl_->queue_->add(q_el);
-        return (recvmsg(env, msg, nonblock, seq));
-    }
-    // XXXMLG handle non-block here, and return false for short reads
-}
-
-void
-Session::subscribe(std::string group, std::string instance) {
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_SUBSCRIBE).arg(group);
-    ElementPtr env = Element::createMap();
-
-    env->set(CC_HEADER_TYPE, Element::create(CC_COMMAND_SUBSCRIBE));
-    env->set(CC_HEADER_GROUP, Element::create(group));
-    env->set(CC_HEADER_INSTANCE, Element::create(instance));
-
-    sendmsg(env);
-}
-
-void
-Session::unsubscribe(std::string group, std::string instance) {
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_UNSUBSCRIBE).arg(group);
-    ElementPtr env = Element::createMap();
-
-    env->set(CC_HEADER_TYPE, Element::create(CC_COMMAND_UNSUBSCRIBE));
-    env->set(CC_HEADER_GROUP, Element::create(group));
-    env->set(CC_HEADER_INSTANCE, Element::create(instance));
-
-    sendmsg(env);
-}
-
-int
-Session::group_sendmsg(ConstElementPtr msg, std::string group,
-                       std::string instance, std::string to, bool want_answer)
-{
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_GROUP_SEND).arg(msg->str()).
-        arg(group);
-    ElementPtr env = Element::createMap();
-    const long int nseq = ++impl_->sequence_;
-
-    env->set(CC_HEADER_TYPE,
-             Element::create(CC_COMMAND_SEND));
-    env->set(CC_HEADER_FROM, Element::create(impl_->lname_));
-    env->set(CC_HEADER_TO, Element::create(to));
-    env->set(CC_HEADER_GROUP, Element::create(group));
-    env->set(CC_HEADER_INSTANCE, Element::create(instance));
-    env->set(CC_HEADER_SEQ, Element::create(nseq));
-    env->set(CC_HEADER_WANT_ANSWER, Element::create(want_answer));
-
-    sendmsg(env, msg);
-    return (nseq);
-}
-
-bool
-Session::group_recvmsg(ConstElementPtr& envelope, ConstElementPtr& msg,
-                       bool nonblock, int seq)
-{
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_GROUP_RECEIVE).arg(seq);
-    bool result(recvmsg(envelope, msg, nonblock, seq));
-    if (result) {
-        LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_GROUP_RECEIVED).
-            arg(envelope->str()).arg(msg->str());
-    } else {
-        LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_NO_MESSAGE);
-    }
-    return (result);
-}
-
-int
-Session::reply(ConstElementPtr envelope, ConstElementPtr newmsg) {
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_REPLY).arg(envelope->str()).
-        arg(newmsg->str());
-    ElementPtr env = Element::createMap();
-    long int nseq = ++impl_->sequence_;
-
-    env->set(CC_HEADER_TYPE, Element::create(CC_COMMAND_SEND));
-    env->set(CC_HEADER_FROM, Element::create(impl_->lname_));
-    env->set(CC_HEADER_TO,
-             Element::create(envelope->get(CC_HEADER_FROM)->stringValue()));
-    env->set(CC_HEADER_GROUP,
-             Element::create(envelope->get(CC_HEADER_GROUP)->stringValue()));
-    env->set(CC_HEADER_INSTANCE,
-             Element::create(envelope->get(CC_HEADER_INSTANCE)->stringValue()));
-    env->set(CC_HEADER_SEQ, Element::create(nseq));
-    env->set(CC_HEADER_REPLY,
-             Element::create(envelope->get(CC_HEADER_SEQ)->intValue()));
-
-    sendmsg(env, newmsg);
-
-    return (nseq);
-}
-
-bool
-Session::hasQueuedMsgs() const {
-    return (!impl_->queue_->empty());
-}
-
-void
-Session::setTimeout(size_t milliseconds) {
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_SET_TIMEOUT).arg(milliseconds);
-    impl_->setTimeout(milliseconds);
-}
-
-size_t
-Session::getTimeout() const {
-    return (impl_->getTimeout());
-}
-}
-}

+ 0 - 192
src/lib/cc/session.h

@@ -1,192 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef ISC_SESSION_H
-#define ISC_SESSION_H 1
-
-#include <cc/data.h>
-#include <cc/session_config.h>
-#include <cc/proto_defs.h>
-
-#include <exceptions/exceptions.h>
-
-#include <string>
-
-#include <boost/function.hpp>
-
-namespace asio {
-class io_service;
-}
-
-namespace isc {
-    namespace cc {
-        class SessionImpl;
-
-        class SessionError : public isc::Exception {
-        public:
-            SessionError(const char* file, size_t line, const char* what) :
-                isc::Exception(file, line, what) {}
-        };
-
-        /// \brief A standard Exception class that is thrown when a
-        /// blocking readData call does not read the given number of
-        /// bytes before the timeout expires
-        class SessionTimeout : public isc::Exception {
-        public:
-            SessionTimeout(const char* file, size_t line, const char* what) :
-                isc::Exception(file, line, what) {}
-        };
-
-        /// \brief The AbstractSession class is an abstract base class that
-        /// defines the interfaces of Session.
-        /// The intended primary usage of abstraction is to allow tests for the
-        /// user class of Session without requiring actual communication
-        /// channels.
-        /// For simplicity we only define the methods that are necessary for
-        /// existing test cases that use this base class.  Eventually we'll
-        /// probably have to extend them.
-        class AbstractSession {
-            ///
-            /// \name Constructors, Assignment Operator and Destructor.
-            ///
-            /// Note: The copy constructor and the assignment operator are
-            /// intentionally defined as private to make it explicit that
-            /// this is a pure base class.
-            //@{
-        private:
-            AbstractSession(const AbstractSession& source);
-            AbstractSession& operator=(const AbstractSession& source);
-        protected:
-            /// \brief The default constructor.
-            ///
-            /// This is intentionally defined as \c protected as this base
-            /// class should never be instantiated (except as part of a
-            /// derived class).
-            AbstractSession() {}
-        public:
-            /// \brief The destructor.
-            virtual ~AbstractSession() {}
-            //@}
-            virtual void establish(const char* socket_file) = 0;
-            virtual void disconnect() = 0;
-            virtual int group_sendmsg(isc::data::ConstElementPtr msg,
-                                      std::string group,
-                                      std::string instance =
-                                          CC_INSTANCE_WILDCARD,
-                                      std::string to = CC_TO_WILDCARD,
-                                      bool want_answer = false) = 0;
-            virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
-                                       isc::data::ConstElementPtr& msg,
-                                       bool nonblock = true,
-                                       int seq = -1) = 0;
-            virtual void subscribe(std::string group,
-                                   std::string instance = "*") = 0;
-            virtual void unsubscribe(std::string group,
-                             std::string instance = "*") = 0;
-            virtual void startRead(boost::function<void()> read_callback) = 0;
-            virtual int reply(isc::data::ConstElementPtr envelope,
-                               isc::data::ConstElementPtr newmsg) = 0;
-            virtual bool hasQueuedMsgs() const = 0;
-
-            /// \brief Sets the default timeout for blocking reads
-            ///        in this session to the given number of milliseconds
-            /// \param milliseconds the timeout for blocking reads in
-            ///        milliseconds; if this is set to 0, reads will block
-            ///        forever.
-            virtual void setTimeout(size_t milliseconds) = 0;
-
-            /// \brief Returns the current timeout for blocking reads
-            /// \return The timeout (in milliseconds)
-            virtual size_t getTimeout() const = 0;
-        };
-
-    class Session : public AbstractSession {
-        private:
-            SessionImpl* impl_;
-
-        private:
-            Session(const Session& source);
-            Session& operator=(const Session& source);
-
-        public:
-            Session(asio::io_service& ioservice);
-            virtual ~Session();
-
-            virtual void startRead(boost::function<void()> read_callback);
-
-            virtual void establish(const char* socket_file = NULL);
-            virtual void disconnect();
-            virtual void subscribe(std::string group,
-                                   std::string instance = "*");
-            virtual void unsubscribe(std::string group,
-                             std::string instance = "*");
-
-            /// \brief Send a message to a group.
-            ///
-            /// \todo Can someone explain how the group, instance and to work?
-            ///     What is the desired semantics here?
-            /// \param msg The message to send.
-            /// \param group Part of addressing.
-            /// \param instance Part of addressing.
-            /// \param to Part of addressing.
-            /// \param want_answer Require an answer? If it is true and there's
-            ///     no recipient, the message queue answers by an error
-            ///     instead.
-            /// \return The squence number of the message sent. It can be used
-            ///     to wait for an answer by group_recvmsg.
-            virtual int group_sendmsg(isc::data::ConstElementPtr msg,
-                                      std::string group,
-                                      std::string instance = "*",
-                                      std::string to = "*",
-                                      bool want_answer = false);
-
-            virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
-                                       isc::data::ConstElementPtr& msg,
-                                       bool nonblock = true,
-                                       int seq = -1);
-            virtual int reply(isc::data::ConstElementPtr envelope,
-                              isc::data::ConstElementPtr newmsg);
-            virtual bool hasQueuedMsgs() const;
-            virtual void setTimeout(size_t milliseconds);
-            virtual size_t getTimeout() const;
-
-            /// @brief returns socket descriptor from underlying socket connection
-            ///
-            /// @return socket descriptor used for session connection
-            virtual int getSocketDesc() const;
-    private:
-            // The following two methods are virtual to allow tests steal and
-            // replace them. It is not expected to be specialized by a derived
-            // class. Actually, it is not expected to inherit from this class
-            // to begin with.
-            virtual void sendmsg(isc::data::ConstElementPtr header);
-            virtual void sendmsg(isc::data::ConstElementPtr header,
-                                 isc::data::ConstElementPtr payload);
-
-            bool recvmsg(isc::data::ConstElementPtr& msg,
-                         bool nonblock = true,
-                         int seq = -1);
-            bool recvmsg(isc::data::ConstElementPtr& env,
-                         isc::data::ConstElementPtr& msg,
-                         bool nonblock = true,
-                         int seq = -1);
-        };
-    } // namespace cc
-} // namespace isc
-
-#endif // ISC_SESSION_H
-
-// Local Variables:
-// mode: c++
-// End:

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

@@ -20,8 +20,8 @@ TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
 # (TODO: these need to be completed and moved to tests/)
-run_unittests_SOURCES = data_unittests.cc session_unittests.cc run_unittests.cc
-run_unittests_SOURCES += data_file_unittests.cc
+run_unittests_SOURCES = command_interpreter_unittests.cc data_unittests.cc
+run_unittests_SOURCES += data_file_unittests.cc run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 

+ 155 - 0
src/lib/cc/tests/command_interpreter_unittests.cc

@@ -0,0 +1,155 @@
+// Copyright (C) 2009,2015  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+#include <cc/command_interpreter.h>
+#include <config/tests/data_def_unittests_config.h>
+#include <log/logger_name.h>
+#include <boost/scoped_ptr.hpp>
+#include <boost/bind.hpp>
+#include <fstream>
+
+using namespace isc::data;
+using namespace isc::config;
+using namespace std;
+
+namespace {
+
+
+/// @brief Convenience method for creating elements from JSON string
+///
+/// @param str string to be converted
+/// @return Element structure
+ElementPtr
+el(const std::string& str) {
+    return (Element::fromJSON(str));
+}
+
+// This test verifies that that createAnswer method is able to generate
+// various answers.
+TEST(CommandInterpreterTest, createAnswer) {
+    ConstElementPtr answer;
+
+    // By default the answer is a successful one.
+    answer = createAnswer();
+    EXPECT_EQ("{ \"result\": 0 }", answer->str());
+
+    // Let's check if we can generate an error.
+    answer = createAnswer(1, "error");
+    EXPECT_EQ("{ \"result\": 1, \"text\": \"error\" }", answer->str());
+
+    // This is expected to throw. When status code is non-zero (indicating error),
+    // textual explanation is mandatory.
+    EXPECT_THROW(createAnswer(1, ElementPtr()), CtrlChannelError);
+    EXPECT_THROW(createAnswer(1, Element::create(1)), CtrlChannelError);
+
+    // Let's check if answer can be generate with some data in it.
+    ConstElementPtr arg = el("[ \"just\", \"some\", \"data\" ]");
+    answer = createAnswer(0, arg);
+    EXPECT_EQ("{ \"arguments\": [ \"just\", \"some\", \"data\" ], \"result\": 0 }",
+              answer->str());
+}
+
+// This test checks whether parseAnswer is able to handle good and malformed
+// answers.
+TEST(CommandInterpreterTest, parseAnswer) {
+    ConstElementPtr answer;
+    ConstElementPtr arg;
+    int rcode;
+
+    EXPECT_THROW(parseAnswer(rcode, ElementPtr()), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("1")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("[]")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{  }")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{ \"something\": 1 }")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 0 ] }")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1 ] }")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1, 1 ] }")), CtrlChannelError);
+    
+    answer = el("{ \"result\": 0 }");
+    arg = parseAnswer(rcode, answer);
+    EXPECT_EQ(0, rcode);
+    EXPECT_TRUE(isNull(arg));
+
+    answer = el("{ \"result\": 1, \"text\": \"error\" }");
+    arg = parseAnswer(rcode, answer);
+    EXPECT_EQ(1, rcode);
+    EXPECT_EQ("error", arg->stringValue());
+
+    answer = el("{ \"result\": 0, \"arguments\": [ \"just\", \"some\", \"data\" ] }");
+    arg = parseAnswer(rcode, answer);
+    EXPECT_EQ(0, rcode);
+    EXPECT_EQ("[ \"just\", \"some\", \"data\" ]", arg->str());
+}
+
+// This test checks whether createCommand function is able to create commands
+// with and without parameters.
+TEST(CommandInterpreterTest, createCommand) {
+    ConstElementPtr command;
+    ConstElementPtr arg;
+
+    command = createCommand("my_command");
+    ASSERT_EQ("{ \"command\": \"my_command\" }", command->str());
+
+    arg = el("1");
+    command = createCommand("my_command", arg);
+    ASSERT_EQ("{ \"arguments\": 1, \"command\": \"my_command\" }",
+              command->str());
+
+    arg = el("[ \"a\", \"b\" ]");
+    command = createCommand("my_cmd", arg);
+    ASSERT_EQ("{ \"arguments\": [ \"a\", \"b\" ], \"command\": \"my_cmd\" }",
+              command->str());
+
+    arg = el("{ \"a\": \"map\" }");
+    command = createCommand("foo", arg);
+    ASSERT_EQ("{ \"arguments\": { \"a\": \"map\" }, \"command\": \"foo\" }",
+              command->str());
+}
+
+// This test checks whether parseCommand function is able to parse various valid
+// and malformed commands.
+TEST(CommandInterpreterTest, parseCommand) {
+    ConstElementPtr arg;
+    std::string cmd;
+
+    // should throw
+    EXPECT_THROW(parseCommand(arg, ElementPtr()), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("1")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{  }")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{ \"not a command\": 1 }")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{ \"command\": 1 }")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{ \"command\": [] }")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{ \"command\": [ 1 ] }")), CtrlChannelError);
+
+    cmd = parseCommand(arg, el("{ \"command\": \"my_command\" }"));
+    EXPECT_EQ("my_command", cmd);
+    EXPECT_FALSE(arg);
+
+    cmd = parseCommand(arg, el("{ \"command\": \"my_command\", \"arguments\": 1 }"));
+    ASSERT_TRUE(arg);
+    EXPECT_EQ("my_command", cmd);
+    EXPECT_EQ("1", arg->str());
+
+    parseCommand(arg, el("{ \"command\": \"my_command\", \"arguments\": "
+                         "[ \"some\", \"argument\", \"list\" ] }"));
+    EXPECT_EQ("my_command", cmd);
+    ASSERT_TRUE(arg);
+    EXPECT_EQ("[ \"some\", \"argument\", \"list\" ]", arg->str());
+
+}
+
+}

+ 0 - 364
src/lib/cc/tests/session_unittests.cc

@@ -1,364 +0,0 @@
-// Copyright (C) 2009,2015  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-
-// for some IPC/network system calls in asio/detail/pipe_select_interrupter.hpp 
-#include <unistd.h>
-// XXX: the ASIO header must be included before others.  See session.cc.
-#include <asio.hpp>
-
-#include <cc/session.h>
-#include <cc/data.h>
-#include <cc/tests/session_unittests_config.h>
-
-#include <gtest/gtest.h>
-#include <boost/bind.hpp>
-
-#include <exceptions/exceptions.h>
-
-#include <utility>
-#include <list>
-#include <string>
-#include <iostream>
-
-using namespace isc::cc;
-using std::pair;
-using std::list;
-using std::string;
-using isc::data::ConstElementPtr;
-using isc::data::Element;
-
-namespace {
-
-TEST(AsioSession, establish) {
-    asio::io_service io_service_;
-    Session sess(io_service_);
-
-    // can't return socket descriptor before session is established
-    EXPECT_THROW(sess.getSocketDesc(), isc::InvalidOperation);
-
-    EXPECT_THROW(
-        sess.establish("/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                       "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                       "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                       "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                       "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                       "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                       "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                       "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                       "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                       "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
-                  ), isc::cc::SessionError
-    );
-}
-
-// This class sets up a domain socket for the session to connect to
-// it will impersonate the msgq a tiny bit (if setSendLname() has
-// been called, it will send an 'answer' to the lname query that is
-// sent in the initialization of Session objects)
-class TestDomainSocket {
-
-public:
-    TestDomainSocket(asio::io_service& io_service, const char* file) :
-        io_service_(io_service),
-        ep_(file),
-        acceptor_(io_service_, ep_),
-        socket_(io_service_),
-        data_buf_(1024)
-    {
-        acceptor_.async_accept(socket_, boost::bind(&TestDomainSocket::acceptHandler,
-                                                    _1));
-    }
-
-    ~TestDomainSocket() {
-        socket_.close();
-        unlink(BUNDY_TEST_SOCKET_FILE);
-    }
-
-    static void acceptHandler(const asio::error_code&) {
-    }
-
-    void sendmsg(isc::data::ElementPtr& env, isc::data::ElementPtr& msg) {
-        const std::string header_wire = env->toWire();
-        const std::string body_wire = msg->toWire();
-        const unsigned int length = 2 + header_wire.length() +
-            body_wire.length();
-        const unsigned int length_net = htonl(length);
-        const unsigned short header_length = header_wire.length();
-        const unsigned short header_length_net = htons(header_length);
-
-        socket_.send(asio::buffer(&length_net, sizeof(length_net)));
-        socket_.send(asio::buffer(&header_length_net,
-                                  sizeof(header_length_net)));
-        socket_.send(asio::buffer(header_wire.data(), header_length));
-        socket_.send(asio::buffer(body_wire.data(), body_wire.length()));
-    }
-
-    void sendLname() {
-        isc::data::ElementPtr lname_answer1 =
-            isc::data::Element::fromJSON("{ \"type\": \"lname\" }");
-        isc::data::ElementPtr lname_answer2 =
-            isc::data::Element::fromJSON("{ \"lname\": \"foobar\" }");
-        sendmsg(lname_answer1, lname_answer2);
-    }
-
-    void setSendLname() {
-        // ignore whatever data we get, send back an lname
-        asio::async_read(socket_,  asio::buffer(&data_buf_[0], 0),
-                         boost::bind(&TestDomainSocket::sendLname, this));
-    }
-
-private:
-    asio::io_service& io_service_;
-    asio::local::stream_protocol::endpoint ep_;
-    asio::local::stream_protocol::acceptor acceptor_;
-    asio::local::stream_protocol::socket socket_;
-    std::vector<char> data_buf_;
-};
-
-/// \brief Pair holding header and data of a message sent over the connection.
-typedef pair<ConstElementPtr, ConstElementPtr> SentMessage;
-
-// We specialize the tested class a little. We replace some low-level
-// methods so we can examine the rest without relying on real network IO
-class TestSession : public Session {
-public:
-    TestSession(asio::io_service& ioservice) :
-        Session(ioservice)
-    {}
-    // Get first message previously sent by sendmsg and remove it from the
-    // buffer. Expects there's at leas one message in the buffer.
-    SentMessage getSentMessage() {
-        assert(!sent_messages_.empty());
-        const SentMessage result(sent_messages_.front());
-        sent_messages_.pop_front();
-        return (result);
-    }
-private:
-    // Override the sendmsg. They are not sent over the real connection, but
-    // stored locally and can be extracted by getSentMessage()
-    virtual void sendmsg(ConstElementPtr header) {
-        sendmsg(header, ConstElementPtr(new isc::data::NullElement));
-    }
-    virtual void sendmsg(ConstElementPtr header, ConstElementPtr payload) {
-        sent_messages_.push_back(SentMessage(header, payload));
-    }
-
-    // The sendmsg stores data here.
-    list<SentMessage> sent_messages_;
-};
-
-class SessionTest : public ::testing::Test {
-protected:
-    SessionTest() : sess(my_io_service), work(my_io_service) {
-        // The TestDomainSocket is held as a 'new'-ed pointer,
-        // so we can call unlink() first.
-        unlink(BUNDY_TEST_SOCKET_FILE);
-        tds = new TestDomainSocket(my_io_service, BUNDY_TEST_SOCKET_FILE);
-    }
-
-    ~SessionTest() {
-        delete tds;
-    }
-
-    // Check the session sent a message with the given header. The
-    // message is hardcoded.
-    void checkSentMessage(const string& expected_hdr, const char* description)
-    {
-        SCOPED_TRACE(description);
-        const SentMessage& msg(sess.getSentMessage());
-        elementsEqual(expected_hdr, msg.first);
-        elementsEqual("{\"test\": 42}", msg.second);
-    }
-
-private:
-    // Check two elements are equal
-    void elementsEqual(const string& expected,
-                       const ConstElementPtr& actual) const
-    {
-        EXPECT_TRUE(Element::fromJSON(expected)->equals(*actual)) <<
-            "Elements differ, expected: " << expected <<
-            ", got: " << actual->toWire();
-    }
-
-public:
-    // used in the handler test
-    // This handler first reads (and ignores) whatever message caused
-    // it to be invoked. Then it calls group_recv for a second message.
-    // If this message is { "command": "stop" } it'll tell the
-    // io_service it is done. Otherwise it'll re-register this handler
-    void someHandler() {
-        isc::data::ConstElementPtr env, msg;
-        sess.group_recvmsg(env, msg, false, -1);
-
-        sess.group_recvmsg(env, msg, false, -1);
-        if (msg && msg->contains("command") &&
-            msg->get("command")->stringValue() == "stop") {
-            my_io_service.stop();
-        } else {
-            sess.startRead(boost::bind(&SessionTest::someHandler, this));
-        }
-    }
-
-protected:
-    asio::io_service my_io_service;
-    TestDomainSocket* tds;
-    TestSession sess;
-    // Keep run() from stopping right away by informing it it has work to do
-    asio::io_service::work work;
-};
-
-TEST_F(SessionTest, timeout_on_connect) {
-    // set to a short timeout so the test doesn't take too long
-    EXPECT_EQ(4000, sess.getTimeout());
-    sess.setTimeout(100);
-    EXPECT_EQ(100, sess.getTimeout());
-    // no answer, should timeout
-    EXPECT_THROW(sess.establish(BUNDY_TEST_SOCKET_FILE), SessionTimeout);
-}
-
-TEST_F(SessionTest, connect_ok) {
-    tds->setSendLname();
-    sess.establish(BUNDY_TEST_SOCKET_FILE);
-}
-
-TEST_F(SessionTest, connect_ok_no_timeout) {
-    tds->setSendLname();
-
-    sess.setTimeout(0);
-    sess.establish(BUNDY_TEST_SOCKET_FILE);
-}
-
-TEST_F(SessionTest, connect_ok_connection_reset) {
-    tds->setSendLname();
-
-    sess.establish(BUNDY_TEST_SOCKET_FILE);
-    // Close the session again, so the next recv() should throw
-    sess.disconnect();
-
-    isc::data::ConstElementPtr env, msg;
-    EXPECT_THROW(sess.group_recvmsg(env, msg, false, -1), SessionError);
-}
-
-TEST_F(SessionTest, run_with_handler) {
-    tds->setSendLname();
-
-    sess.establish(BUNDY_TEST_SOCKET_FILE);
-    sess.startRead(boost::bind(&SessionTest::someHandler, this));
-
-    isc::data::ElementPtr env = isc::data::Element::fromJSON("{ \"to\": \"me\" }");
-    isc::data::ElementPtr msg = isc::data::Element::fromJSON("{ \"some\": \"message\" }");
-    tds->sendmsg(env, msg);
-
-    msg = isc::data::Element::fromJSON("{ \"another\": \"message\" }");
-    tds->sendmsg(env, msg);
-
-    msg = isc::data::Element::fromJSON("{ \"a third\": \"message\" }");
-    tds->sendmsg(env, msg);
-
-    msg = isc::data::Element::fromJSON("{ \"command\": \"stop\" }");
-    tds->sendmsg(env, msg);
-
-
-    size_t count = my_io_service.run();
-    ASSERT_EQ(2, count);
-}
-
-TEST_F(SessionTest, run_with_handler_timeout) {
-    tds->setSendLname();
-
-    sess.establish(BUNDY_TEST_SOCKET_FILE);
-    sess.startRead(boost::bind(&SessionTest::someHandler, this));
-    sess.setTimeout(100);
-
-    isc::data::ElementPtr env = isc::data::Element::fromJSON("{ \"to\": \"me\" }");
-    isc::data::ElementPtr msg = isc::data::Element::fromJSON("{ \"some\": \"message\" }");
-    tds->sendmsg(env, msg);
-
-    msg = isc::data::Element::fromJSON("{ \"another\": \"message\" }");
-    tds->sendmsg(env, msg);
-
-    msg = isc::data::Element::fromJSON("{ \"a third\": \"message\" }");
-    tds->sendmsg(env, msg);
-
-    // No follow-up message, should time out.
-    ASSERT_THROW(my_io_service.run(), SessionTimeout);
-}
-
-TEST_F(SessionTest, get_socket_descr) {
-    tds->setSendLname();
-    sess.establish(BUNDY_TEST_SOCKET_FILE);
-
-    int socket = 0;
-    // session is established, so getSocketDesc() should work
-    EXPECT_NO_THROW(socket = sess.getSocketDesc());
-
-    // expect actual socket handle to be returned, not 0
-    EXPECT_LT(0, socket);
-}
-
-// Test the group_sendmsg sends the correct data.
-TEST_F(SessionTest, group_sendmsg) {
-    // Connect (to set the lname, so we can see it sets the from)
-    tds->setSendLname();
-    sess.establish(BUNDY_TEST_SOCKET_FILE);
-    // Eat the "get_lname" message, so it doesn't confuse the
-    // test below.
-    sess.getSentMessage();
-
-    const ConstElementPtr msg(Element::fromJSON("{\"test\": 42}"));
-    sess.group_sendmsg(msg, "group");
-    checkSentMessage("{"
-                     "   \"from\": \"foobar\","
-                     "   \"group\": \"group\","
-                     "   \"instance\": \"*\","
-                     "   \"seq\": 0,"
-                     "   \"to\": \"*\","
-                     "   \"type\": \"send\","
-                     "   \"want_answer\": False"
-                     "}", "No instance");
-    sess.group_sendmsg(msg, "group", "instance", "recipient");
-    checkSentMessage("{"
-                     "   \"from\": \"foobar\","
-                     "   \"group\": \"group\","
-                     "   \"instance\": \"instance\","
-                     "   \"seq\": 1,"
-                     "   \"to\": \"recipient\","
-                     "   \"type\": \"send\","
-                     "   \"want_answer\": False"
-                     "}", "With instance");
-    sess.group_sendmsg(msg, "group", "*", "*", true);
-    checkSentMessage("{"
-                     "   \"from\": \"foobar\","
-                     "   \"group\": \"group\","
-                     "   \"instance\": \"*\","
-                     "   \"seq\": 2,"
-                     "   \"to\": \"*\","
-                     "   \"type\": \"send\","
-                     "   \"want_answer\": True"
-                     "}", "Want answer");
-    sess.group_sendmsg(msg, "group", "*", "*", false);
-    checkSentMessage("{"
-                     "   \"from\": \"foobar\","
-                     "   \"group\": \"group\","
-                     "   \"instance\": \"*\","
-                     "   \"seq\": 3,"
-                     "   \"to\": \"*\","
-                     "   \"type\": \"send\","
-                     "   \"want_answer\": False"
-                     "}", "Doesn't want answer");
-}
-
-}

+ 0 - 1
src/lib/config/Makefile.am

@@ -17,7 +17,6 @@ BUILT_SOURCES = config_messages.h config_messages.cc
 lib_LTLIBRARIES = libkea-cfgclient.la
 libkea_cfgclient_la_SOURCES = config_data.h config_data.cc
 libkea_cfgclient_la_SOURCES += module_spec.h module_spec.cc
-libkea_cfgclient_la_SOURCES += ccsession.cc ccsession.h
 libkea_cfgclient_la_SOURCES += config_log.h config_log.cc
 
 libkea_cfgclient_la_LIBADD = $(top_builddir)/src/lib/cc/libkea-cc.la

+ 0 - 994
src/lib/config/ccsession.cc

@@ -1,994 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-
-#include <stdexcept>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <ctype.h>
-
-#include <algorithm>
-#include <cerrno>
-#include <fstream>
-#include <iostream>
-#include <set>
-#include <sstream>
-#include <string>
-
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-
-#include <cc/data.h>
-#include <config/module_spec.h>
-#include <cc/session.h>
-#include <exceptions/exceptions.h>
-
-#include <config/config_log.h>
-#include <config/ccsession.h>
-
-#include <log/logger_support.h>
-#include <log/logger_specification.h>
-#include <log/logger_manager.h>
-#include <log/logger_name.h>
-
-using namespace std;
-
-using isc::data::Element;
-using isc::data::ConstElementPtr;
-using isc::data::ElementPtr;
-using isc::data::JSONError;
-
-namespace isc {
-namespace config {
-
-/// Creates a standard config/command protocol answer message
-ConstElementPtr
-createAnswer() {
-    ElementPtr answer = Element::createMap();
-    ElementPtr answer_content = Element::createList();
-    answer_content->add(Element::create(isc::cc::CC_REPLY_SUCCESS));
-    answer->set(isc::cc::CC_PAYLOAD_RESULT, answer_content);
-
-    return (answer);
-}
-
-ConstElementPtr
-createAnswer(const int rcode, ConstElementPtr arg) {
-    if (rcode != 0 && (!arg || arg->getType() != Element::string)) {
-        isc_throw(CCSessionError, "Bad or no argument for rcode != 0");
-    }
-    ElementPtr answer = Element::createMap();
-    ElementPtr answer_content = Element::createList();
-    answer_content->add(Element::create(rcode));
-    answer_content->add(arg);
-    answer->set(isc::cc::CC_PAYLOAD_RESULT, answer_content);
-
-    return (answer);
-}
-
-ConstElementPtr
-createAnswer(const int rcode, const std::string& arg) {
-    ElementPtr answer = Element::createMap();
-    ElementPtr answer_content = Element::createList();
-    answer_content->add(Element::create(rcode));
-    answer_content->add(Element::create(arg));
-    answer->set(isc::cc::CC_PAYLOAD_RESULT, answer_content);
-
-    return (answer);
-}
-
-ConstElementPtr
-parseAnswer(int &rcode, ConstElementPtr msg) {
-    if (msg &&
-        msg->getType() == Element::map &&
-        msg->contains(isc::cc::CC_PAYLOAD_RESULT)) {
-        ConstElementPtr result = msg->get(isc::cc::CC_PAYLOAD_RESULT);
-        if (result->getType() != Element::list) {
-            isc_throw(CCSessionError, "Result element in answer message is not a list");
-        } else if (result->get(0)->getType() != Element::integer) {
-            isc_throw(CCSessionError, "First element of result is not an rcode in answer message");
-        }
-        rcode = result->get(0)->intValue();
-        if (result->size() > 1) {
-            if (rcode == 0 || result->get(1)->getType() == Element::string) {
-                return (result->get(1));
-            } else {
-                isc_throw(CCSessionError, "Error description in result with rcode != 0 is not a string");
-            }
-        } else {
-            if (rcode == 0) {
-                return (ElementPtr());
-            } else {
-                isc_throw(CCSessionError, "Result with rcode != 0 does not have an error description");
-            }
-        }
-    } else {
-        isc_throw(CCSessionError, "No result part in answer message");
-    }
-}
-
-ConstElementPtr
-createCommand(const std::string& command) {
-    return (createCommand(command, ElementPtr()));
-}
-
-ConstElementPtr
-createCommand(const std::string& command, ConstElementPtr arg) {
-    ElementPtr cmd = Element::createMap();
-    ElementPtr cmd_parts = Element::createList();
-    cmd_parts->add(Element::create(command));
-    if (arg) {
-        cmd_parts->add(arg);
-    }
-    cmd->set(isc::cc::CC_PAYLOAD_COMMAND, cmd_parts);
-    return (cmd);
-}
-
-std::string
-parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
-    if (command &&
-        command->getType() == Element::map &&
-        command->contains(isc::cc::CC_PAYLOAD_COMMAND)) {
-        ConstElementPtr cmd = command->get(isc::cc::CC_PAYLOAD_COMMAND);
-        if (cmd->getType() == Element::list &&
-            !cmd->empty() &&
-            cmd->get(0)->getType() == Element::string) {
-            if (cmd->size() > 1) {
-                arg = cmd->get(1);
-            } else {
-                arg = Element::createMap();
-            }
-            return (cmd->get(0)->stringValue());
-        } else {
-            isc_throw(CCSessionError, "Command part in command message missing, empty, or not a list");
-        }
-    } else {
-        isc_throw(CCSessionError, "Command Element empty or not a map with \"command\"");
-    }
-}
-
-namespace {
-// Temporary workaround functions for missing functionality in
-// getValue() (main problem described in ticket #993)
-// This returns either the value set for the given relative id,
-// or its default value
-// (intentionally defined here so this interface does not get
-// included in ConfigData as it is)
-ConstElementPtr getValueOrDefault(ConstElementPtr config_part,
-                                  const std::string& relative_id,
-                                  const ConfigData& config_data,
-                                  const std::string& full_id) {
-    if (config_part->contains(relative_id)) {
-        return config_part->get(relative_id);
-    } else {
-        return config_data.getDefaultValue(full_id);
-    }
-}
-
-/// @brief Prefix name with "kea-".
-///
-/// In BIND 10, modules had names taken from the .spec file, which are typically
-/// names starting with a capital letter (e.g. "Resolver", "Auth" etc.).  The
-/// names of the associated binaries are derived from the module names, being
-/// prefixed "b10-" and having the first letter of the module name lower-cased
-/// (e.g. "b10-resolver", "b10-auth").  (It is a required convention that there
-/// be this relationship between the names.)
-///
-/// In Kea we're not using module names, but we do still keep some capability to
-/// run Kea servers in Bundy framework. For that reason the whole discussion here
-/// applies only to case when Kea is compiled with Bundy configuration backend.
-///
-/// Within the binaries the root loggers are named after the binaries themselves.
-/// (The reason for this is that the name of the logger is included in the
-/// message logged, so making it clear which message comes from which Kea
-/// process.) As logging is configured using module names, the configuration code
-/// has to match these with the corresponding logger names. This function
-/// converts a module name to a root logger name by lowercasing the first letter
-/// of the module name and prepending "kea-".
-///
-/// \param instring String to convert.  (This may be empty, in which case
-///        "kea-" will be returned.)
-///
-/// \return Converted string.
-std::string
-keaPrefix(const std::string& instring) {
-    std::string result = instring;
-    if (!result.empty()) {
-        result[0] = tolower(result[0]);
-    }
-    return (std::string("kea-") + result);
-}
-
-// Reads a output_option subelement of a logger configuration,
-// and sets the values thereing to the given OutputOption struct,
-// or defaults values if they are not provided (from config_data).
-void
-readOutputOptionConf(isc::log::OutputOption& output_option,
-                     ConstElementPtr output_option_el,
-                     const ConfigData& config_data)
-{
-    ConstElementPtr destination_el = getValueOrDefault(output_option_el,
-                                    "destination", config_data,
-                                    "loggers/output_options/destination");
-    output_option.destination = isc::log::getDestination(destination_el->stringValue());
-    ConstElementPtr output_el = getValueOrDefault(output_option_el,
-                                    "output", config_data,
-                                    "loggers/output_options/output");
-    if (output_option.destination == isc::log::OutputOption::DEST_CONSOLE) {
-        output_option.stream = isc::log::getStream(output_el->stringValue());
-    } else if (output_option.destination == isc::log::OutputOption::DEST_FILE) {
-        output_option.filename = output_el->stringValue();
-    } else if (output_option.destination == isc::log::OutputOption::DEST_SYSLOG) {
-        output_option.facility = output_el->stringValue();
-    }
-    output_option.flush = getValueOrDefault(output_option_el,
-                              "flush", config_data,
-                              "loggers/output_options/flush")->boolValue();
-    output_option.maxsize = getValueOrDefault(output_option_el,
-                                "maxsize", config_data,
-                                "loggers/output_options/maxsize")->intValue();
-    output_option.maxver = getValueOrDefault(output_option_el,
-                               "maxver", config_data,
-                               "loggers/output_options/maxver")->intValue();
-}
-
-// Reads a full 'loggers' configuration, and adds the loggers therein
-// to the given vector, fills in blanks with defaults from config_data
-void
-readLoggersConf(std::vector<isc::log::LoggerSpecification>& specs,
-                ConstElementPtr logger,
-                const ConfigData& config_data)
-{
-    // Read name, adding prefix as required.
-    std::string lname = logger->get("name")->stringValue();
-
-    ConstElementPtr severity_el = getValueOrDefault(logger,
-                                      "severity", config_data,
-                                      "loggers/severity");
-    isc::log::Severity severity = isc::log::getSeverity(
-                                      severity_el->stringValue());
-    int dbg_level = getValueOrDefault(logger, "debuglevel",
-                                      config_data,
-                                      "loggers/debuglevel")->intValue();
-    bool additive = getValueOrDefault(logger, "additive", config_data,
-                                      "loggers/additive")->boolValue();
-
-    isc::log::LoggerSpecification logger_spec(
-        lname, severity, dbg_level, additive
-    );
-
-    if (logger->contains("output_options")) {
-        BOOST_FOREACH(ConstElementPtr output_option_el,
-                      logger->get("output_options")->listValue()) {
-            // create outputoptions
-            isc::log::OutputOption output_option;
-            readOutputOptionConf(output_option,
-                                 output_option_el,
-                                 config_data);
-            logger_spec.addOutputOption(output_option);
-        }
-    }
-
-    specs.push_back(logger_spec);
-}
-
-// Copies the map for a logger, changing the name of the logger in the process.
-// This is used because the map being copied is "const", so in order to
-// change the name we need to create a new one.
-//
-// \param cur_logger Logger being copied.
-// \param new_name New value of the "name" element at the top level.
-//
-// \return Pointer to the map with the updated element.
-ConstElementPtr
-copyLogger(ConstElementPtr& cur_logger, const std::string& new_name) {
-
-    // Since we'll only be updating one first-level element and subsequent
-    // use won't change the contents of the map, a shallow map copy is enough.
-    ElementPtr new_logger(Element::createMap());
-    new_logger->setValue(cur_logger->mapValue());
-    new_logger->set("name", Element::create(new_name));
-
-    return (new_logger);
-}
-
-
-} // end anonymous namespace
-
-
-ConstElementPtr
-getRelatedLoggers(ConstElementPtr loggers) {
-    // Keep a list of names for easier lookup later
-    std::set<std::string> our_names;
-    const std::string& root_name = isc::log::getRootLoggerName();
-
-    ElementPtr result = isc::data::Element::createList();
-
-    BOOST_FOREACH(ConstElementPtr cur_logger, loggers->listValue()) {
-        // Need to add the kea- prefix to names ready from the spec file.
-        const std::string cur_name = cur_logger->get("name")->stringValue();
-        const std::string mod_name = keaPrefix(cur_name);
-        if (mod_name == root_name || mod_name.find(root_name + ".") == 0) {
-
-            // Note this name so that we don't add a wildcard that matches it.
-            our_names.insert(mod_name);
-
-            // We want to store the logger with the modified name (i.e. with
-            // the kea- prefix).  As we are dealing with const loggers, we
-            // store a modified copy of the data.
-            result->add(copyLogger(cur_logger, mod_name));
-            LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS, CONFIG_LOG_EXPLICIT)
-                      .arg(cur_name);
-
-        } else if (!cur_name.empty() && (cur_name[0] != '*')) {
-            // Not a wildcard logger and we are ignoring it.
-            LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS,
-                      CONFIG_LOG_IGNORE_EXPLICIT).arg(cur_name);
-        }
-    }
-
-    // Now find the wildcard names (the one that start with "*").
-    BOOST_FOREACH(ConstElementPtr cur_logger, loggers->listValue()) {
-        const std::string cur_name = cur_logger->get("name")->stringValue();
-        // If name is '*', or starts with '*.', replace * with root
-        // logger name.
-        if (cur_name == "*" || (cur_name.length() > 1 &&
-            cur_name[0] == '*' && cur_name[1] == '.')) {
-
-            // Substitute the "*" with the root name
-            std::string mod_name = cur_name;
-            mod_name.replace(0, 1, root_name);
-
-            // Now add it to the result list, but only if a logger with
-            // that name was not configured explicitly.
-            if (our_names.find(mod_name) == our_names.end()) {
-
-                // We substitute the name here, but as we are dealing with
-                // consts, we need to copy the data.
-                result->add(copyLogger(cur_logger, mod_name));
-                LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS,
-                          CONFIG_LOG_WILD_MATCH).arg(cur_name);
-
-            } else if (!cur_name.empty() && (cur_name[0] == '*')) {
-                // Is a wildcard and we are ignoring it (because the wildcard
-                // expands to a specification that we already encountered when
-                // processing explicit names).
-                LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS,
-                          CONFIG_LOG_IGNORE_WILD).arg(cur_name);
-            }
-        }
-    }
-    return (result);
-}
-
-void
-default_logconfig_handler(const std::string& module_name,
-                          ConstElementPtr new_config,
-                          const ConfigData& config_data) {
-    config_data.getModuleSpec().validateConfig(new_config, true);
-
-    std::vector<isc::log::LoggerSpecification> specs;
-
-    if (new_config->contains("loggers")) {
-        ConstElementPtr loggers = getRelatedLoggers(new_config->get("loggers"));
-        BOOST_FOREACH(ConstElementPtr logger,
-                      loggers->listValue()) {
-            readLoggersConf(specs, logger, config_data);
-        }
-    }
-
-    isc::log::LoggerManager logger_manager;
-    logger_manager.process(specs.begin(), specs.end());
-}
-
-
-ModuleSpec
-ModuleCCSession::readModuleSpecification(const std::string& filename) {
-    std::ifstream file;
-    ModuleSpec module_spec;
-
-    // this file should be declared in a @something@ directive
-    file.open(filename.c_str());
-    if (!file) {
-        LOG_ERROR(config_logger, CONFIG_OPEN_FAIL).arg(filename).arg(strerror(errno));
-        isc_throw(CCSessionInitError, strerror(errno));
-    }
-
-    try {
-        module_spec = moduleSpecFromFile(file, true);
-    } catch (const JSONError& pe) {
-        LOG_ERROR(config_logger, CONFIG_JSON_PARSE).arg(filename).arg(pe.what());
-        isc_throw(CCSessionInitError, pe.what());
-    } catch (const ModuleSpecError& dde) {
-        LOG_ERROR(config_logger, CONFIG_MOD_SPEC_FORMAT).arg(filename).arg(dde.what());
-        isc_throw(CCSessionInitError, dde.what());
-    }
-    file.close();
-    return (module_spec);
-}
-
-void
-ModuleCCSession::startCheck() {
-    // data available on the command channel.  process it in the synchronous
-    // mode.
-    checkCommand();
-
-    // start asynchronous read again.
-    session_.startRead(boost::bind(&ModuleCCSession::startCheck, this));
-}
-
-ModuleCCSession::ModuleCCSession(
-    const std::string& spec_file_name,
-    isc::cc::AbstractSession& session,
-    isc::data::ConstElementPtr(*config_handler)(
-        isc::data::ConstElementPtr new_config),
-    isc::data::ConstElementPtr(*command_handler)(
-        const std::string& command, isc::data::ConstElementPtr args),
-    bool start_immediately,
-    bool handle_logging
-    ) :
-    started_(false),
-    session_(session)
-{
-    module_specification_ = readModuleSpecification(spec_file_name);
-    setModuleSpec(module_specification_);
-
-    module_name_ = module_specification_.getFullSpec()->get("module_name")->stringValue();
-    config_handler_ = config_handler;
-    command_handler_ = command_handler;
-
-    session_.establish(NULL);
-    session_.subscribe(module_name_, "*");
-
-    // send the data specification
-    ConstElementPtr spec_msg = createCommand("module_spec",
-                                             module_specification_.getFullSpec());
-    unsigned int seq = session_.group_sendmsg(spec_msg, "ConfigManager");
-
-    ConstElementPtr answer, env;
-    session_.group_recvmsg(env, answer, false, seq);
-    int rcode = -1;
-    ConstElementPtr err = parseAnswer(rcode, answer);
-    if (rcode != 0) {
-        LOG_ERROR(config_logger, CONFIG_MOD_SPEC_REJECT).arg(answer->str());
-        isc_throw(CCSessionInitError, answer->str());
-    }
-
-    setLocalConfig(Element::createMap());
-    // get any stored configuration from the manager
-    if (config_handler_) {
-        ConstElementPtr cmd =
-            createCommand("get_config",
-                          Element::fromJSON("{\"module_name\":\"" +
-                                            module_name_ + "\"}"));
-        seq = session_.group_sendmsg(cmd, "ConfigManager");
-        session_.group_recvmsg(env, answer, false, seq);
-        ConstElementPtr new_config = parseAnswer(rcode, answer);
-        if (rcode == 0) {
-            handleConfigUpdate(new_config);
-        } else {
-            LOG_ERROR(config_logger, CONFIG_GET_FAIL).arg(new_config->str());
-            isc_throw(CCSessionInitError, answer->str());
-        }
-    }
-
-    // Keep track of logging settings automatically
-    if (handle_logging) {
-        addRemoteConfig("Logging", default_logconfig_handler, false);
-    }
-
-    if (start_immediately) {
-        start();
-    }
-
-}
-
-ModuleCCSession::~ModuleCCSession() {
-    try {
-        sendStopping();
-    } catch (const std::exception& exc) {
-        LOG_ERROR(config_logger,
-                  CONFIG_CCSESSION_STOPPING).arg(exc.what());
-    } catch (...) {
-        LOG_ERROR(config_logger,
-                  CONFIG_CCSESSION_STOPPING_UNKNOWN);
-    }
-};
-
-void
-ModuleCCSession::start() {
-    if (started_) {
-        isc_throw(CCSessionError, "Module CC session already started");
-    }
-
-    // register callback for asynchronous read
-    session_.startRead(boost::bind(&ModuleCCSession::startCheck, this));
-
-    started_ = true;
-}
-
-/// Validates the new config values, if they are correct,
-/// call the config handler with the values that have changed
-/// If that results in success, store the new config
-ConstElementPtr
-ModuleCCSession::handleConfigUpdate(ConstElementPtr new_config) {
-    ConstElementPtr answer;
-    ElementPtr errors = Element::createList();
-    if (!config_handler_) {
-        answer = createAnswer(1, module_name_ + " does not have a config handler");
-    } else if (!module_specification_.validateConfig(new_config, false,
-                                                      errors)) {
-        std::stringstream ss;
-        ss << "Error in config validation: ";
-        BOOST_FOREACH(ConstElementPtr error, errors->listValue()) {
-            ss << error->stringValue();
-        }
-        answer = createAnswer(2, ss.str());
-    } else {
-        // remove the values that have not changed
-        ConstElementPtr diff = removeIdentical(new_config, getLocalConfig());
-        // handle config update
-        answer = config_handler_(diff);
-        int rcode = -1;
-        parseAnswer(rcode, answer);
-        if (rcode == 0) {
-            ElementPtr local_config = getLocalConfig();
-            isc::data::merge(local_config, diff);
-            setLocalConfig(local_config);
-        }
-    }
-    return (answer);
-}
-
-bool
-ModuleCCSession::hasQueuedMsgs() const {
-    return (session_.hasQueuedMsgs());
-}
-
-ConstElementPtr
-ModuleCCSession::checkConfigUpdateCommand(const std::string& target_module,
-                                          ConstElementPtr arg)
-{
-    if (target_module == module_name_) {
-        return (handleConfigUpdate(arg));
-    } else {
-        // ok this update is not for us, if we have this module
-        // in our remote config list, update that
-        updateRemoteConfig(target_module, arg);
-        // we're not supposed to answer to this, so return
-        return (ElementPtr());
-    }
-}
-
-ConstElementPtr
-ModuleCCSession::checkModuleCommand(const std::string& cmd_str,
-                                    const std::string& target_module,
-                                    ConstElementPtr arg) const
-{
-    if (target_module == module_name_) {
-        if (command_handler_) {
-            ElementPtr errors = Element::createList();
-            if (module_specification_.validateCommand(cmd_str,
-                                                       arg,
-                                                       errors)) {
-                return (command_handler_(cmd_str, arg));
-            } else {
-                std::stringstream ss;
-                ss << "Error in command validation: ";
-                BOOST_FOREACH(ConstElementPtr error,
-                              errors->listValue()) {
-                    ss << error->stringValue();
-                }
-                return (createAnswer(3, ss.str()));
-            }
-        } else {
-            return (createAnswer(1,
-                                 "Command given but no "
-                                 "command handler for module"));
-        }
-    } else if (unhandled_callback_) {
-        unhandled_callback_(cmd_str, target_module, arg);
-    }
-    return (ElementPtr());
-}
-
-int
-ModuleCCSession::checkCommand() {
-    ConstElementPtr cmd, routing, data;
-    if (session_.group_recvmsg(routing, data, true)) {
-
-        // In case the message is wanted asynchronously, it gets used.
-        if (checkAsyncRecv(routing, data)) {
-            return (0);
-        }
-
-        // In case it is notification, eat it.
-        if (checkNotification(routing, data)) {
-            return (0);
-        }
-
-        /* ignore result messages (in case we're out of sync, to prevent
-         * pingpongs */
-        if (data->getType() != Element::map ||
-            data->contains(isc::cc::CC_PAYLOAD_RESULT)) {
-            return (0);
-        }
-        ConstElementPtr arg;
-        ConstElementPtr answer;
-        try {
-            std::string cmd_str = parseCommand(arg, data);
-            std::string target_module =
-                routing->get(isc::cc::CC_HEADER_GROUP)->stringValue();
-            if (cmd_str == "config_update") {
-                answer = checkConfigUpdateCommand(target_module, arg);
-            } else {
-                answer = checkModuleCommand(cmd_str, target_module, arg);
-            }
-        } catch (const CCSessionError& re) {
-            LOG_ERROR(config_logger, CONFIG_CCSESSION_MSG).arg(re.what());
-        } catch (const std::exception& stde) {
-            // No matter what unexpected error happens, we do not want
-            // to crash because of an incoming event, so we log the
-            // exception and continue to run
-            LOG_ERROR(config_logger, CONFIG_CCSESSION_MSG_INTERNAL).arg(stde.what());
-        }
-        if (!isNull(answer)) {
-            session_.reply(routing, answer);
-        }
-    }
-
-    return (0);
-}
-
-ModuleSpec
-ModuleCCSession::fetchRemoteSpec(const std::string& module, bool is_filename) {
-    if (is_filename) {
-        // It is a filename, simply load it.
-        return (readModuleSpecification(module));
-    } else {
-        // It's module name, request it from config manager
-
-        // Send the command
-        ConstElementPtr cmd(createCommand("get_module_spec",
-                            Element::fromJSON("{\"module_name\": \"" + module +
-                                              "\"}")));
-        unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
-        ConstElementPtr env, answer;
-        session_.group_recvmsg(env, answer, false, seq);
-        int rcode = -1;
-        ConstElementPtr spec_data = parseAnswer(rcode, answer);
-        if (rcode == 0 && spec_data) {
-            // received OK, construct the spec out of it
-            ModuleSpec spec = ModuleSpec(spec_data);
-            if (module != spec.getModuleName()) {
-                // It's a different module!
-                isc_throw(CCSessionError, "Module name mismatch");
-            }
-            return (spec);
-        } else {
-            isc_throw(CCSessionError, "Error getting config for " +
-                      module + ": " + answer->str());
-        }
-    }
-}
-
-std::string
-ModuleCCSession::addRemoteConfig(const std::string& spec_name,
-                                 RemoteHandler handler,
-                                 bool spec_is_filename)
-{
-    // First get the module name, specification and default config
-    const ModuleSpec rmod_spec(fetchRemoteSpec(spec_name, spec_is_filename));
-    const std::string module_name(rmod_spec.getModuleName());
-    ConfigData rmod_config(rmod_spec);
-
-    // Get the current configuration values from config manager
-    ConstElementPtr cmd(createCommand("get_config",
-                        Element::fromJSON("{\"module_name\": \"" +
-                                          module_name + "\"}")));
-    const unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
-
-    ConstElementPtr env, answer;
-    session_.group_recvmsg(env, answer, false, seq);
-    int rcode = -1;
-    ConstElementPtr new_config = parseAnswer(rcode, answer);
-    ElementPtr local_config;
-    if (rcode == 0 && new_config) {
-        // Merge the received config into existing local config
-        local_config = rmod_config.getLocalConfig();
-        isc::data::merge(local_config, new_config);
-        rmod_config.setLocalConfig(local_config);
-    } else {
-        isc_throw(CCSessionError, "Error getting config for " + module_name + ": " + answer->str());
-    }
-
-    // all ok, add it
-    remote_module_configs_[module_name] = rmod_config;
-    if (handler) {
-        remote_module_handlers_[module_name] = handler;
-        handler(module_name, local_config, rmod_config);
-    }
-
-    // Make sure we get updates in future
-    session_.subscribe(module_name);
-    return (module_name);
-}
-
-void
-ModuleCCSession::removeRemoteConfig(const std::string& module_name) {
-    std::map<std::string, ConfigData>::iterator it;
-
-    it = remote_module_configs_.find(module_name);
-    if (it != remote_module_configs_.end()) {
-        remote_module_configs_.erase(it);
-        remote_module_handlers_.erase(module_name);
-        session_.unsubscribe(module_name);
-    }
-}
-
-ConstElementPtr
-ModuleCCSession::getRemoteConfigValue(const std::string& module_name,
-                                      const std::string& identifier) const
-{
-    std::map<std::string, ConfigData>::const_iterator it =
-        remote_module_configs_.find(module_name);
-
-    if (it != remote_module_configs_.end()) {
-        return ((*it).second.getValue(identifier));
-    } else {
-        isc_throw(CCSessionError,
-                  "Remote module " + module_name + " not found.");
-    }
-}
-
-void
-ModuleCCSession::updateRemoteConfig(const std::string& module_name,
-                                    ConstElementPtr new_config)
-{
-    std::map<std::string, ConfigData>::iterator it;
-
-    it = remote_module_configs_.find(module_name);
-    if (it != remote_module_configs_.end()) {
-        ElementPtr rconf = (*it).second.getLocalConfig();
-        isc::data::merge(rconf, new_config);
-        std::map<std::string, RemoteHandler>::iterator hit =
-            remote_module_handlers_.find(module_name);
-        if (hit != remote_module_handlers_.end()) {
-            hit->second(module_name, new_config, it->second);
-        }
-    }
-}
-
-void
-ModuleCCSession::sendStopping() {
-    // Inform the configuration manager that this module is stopping
-    ConstElementPtr cmd(createCommand("stopping",
-                                      Element::fromJSON(
-                                          "{\"module_name\": \"" +
-                                          module_name_ + "\"}")));
-    // It's just an FYI, configmanager is not expected to respond.
-    session_.group_sendmsg(cmd, "ConfigManager");
-}
-
-class ModuleCCSession::AsyncRecvRequest {
-public: // Everything is public here, as the definition is hidden anyway
-    AsyncRecvRequest(const AsyncRecvCallback& cb, const string& rcp, int sq,
-                     bool reply) :
-        callback(cb),
-        recipient(rcp),
-        seq(sq),
-        is_reply(reply)
-    {}
-    const AsyncRecvCallback callback;
-    const string recipient;
-    const int seq;
-    const bool is_reply;
-};
-
-ModuleCCSession::AsyncRecvRequestID
-ModuleCCSession::groupRecvMsgAsync(const AsyncRecvCallback& callback,
-                                   bool is_reply, int seq,
-                                   const string& recipient) {
-    // This just stores the request, the handling is done in checkCommand()
-
-    // push_back would be simpler, but it does not return the iterator we need
-    return (async_recv_requests_.insert(async_recv_requests_.end(),
-                                        AsyncRecvRequest(callback, recipient,
-                                                         seq, is_reply)));
-}
-
-bool
-ModuleCCSession::checkAsyncRecv(const ConstElementPtr& envelope,
-                                const ConstElementPtr& msg)
-{
-    for (AsyncRecvRequestID request(async_recv_requests_.begin());
-         request != async_recv_requests_.end(); ++request) {
-        // Just go through all the requests and look for a matching one
-        if (requestMatch(*request, envelope)) {
-            // We want the request to be still alive at the time we
-            // call the callback. But we need to remove it on an exception
-            // too, so we use the class. If just C++ had the finally keyword.
-            class RequestDeleter {
-            public:
-                RequestDeleter(AsyncRecvRequests& requests,
-                               AsyncRecvRequestID& request) :
-                    requests_(requests),
-                    request_(request)
-                { }
-                ~RequestDeleter() {
-                    requests_.erase(request_);
-                }
-            private:
-                AsyncRecvRequests& requests_;
-                AsyncRecvRequestID& request_;
-            };
-            RequestDeleter deleter(async_recv_requests_, request);
-            // Call the callback
-            request->callback(envelope, msg, request);
-            return (true);
-        }
-    }
-    return (false);
-}
-
-bool
-ModuleCCSession::requestMatch(const AsyncRecvRequest& request,
-                              const ConstElementPtr& envelope) const
-{
-    if (request.is_reply != envelope->contains(isc::cc::CC_HEADER_REPLY)) {
-        // Wrong type of message
-        return (false);
-    }
-    if (request.is_reply &&
-        (request.seq == -1 ||
-         request.seq == envelope->get(isc::cc::CC_HEADER_REPLY)->intValue())) {
-        // This is the correct reply
-        return (true);
-    }
-    if (!request.is_reply &&
-        (request.recipient.empty() || request.recipient ==
-         envelope->get(isc::cc::CC_HEADER_GROUP)->stringValue())) {
-        // This is the correct command
-        return (true);
-    }
-    // If nothing from the above, we don't want it
-    return (false);
-}
-
-void
-ModuleCCSession::cancelAsyncRecv(const AsyncRecvRequestID& id) {
-    async_recv_requests_.erase(id);
-}
-
-ConstElementPtr
-ModuleCCSession::rpcCall(const std::string &command, const std::string &group,
-                         const std::string &instance, const std::string &to,
-                         const ConstElementPtr &params)
-{
-    ConstElementPtr command_el(createCommand(command, params));
-    const int seq = groupSendMsg(command_el, group, instance, to, true);
-    ConstElementPtr env, answer;
-    LOG_DEBUG(config_logger, DBGLVL_TRACE_DETAIL, CONFIG_RPC_SEQ).arg(command).
-        arg(group).arg(seq);
-    groupRecvMsg(env, answer, true, seq);
-    int rcode;
-    const ConstElementPtr result(parseAnswer(rcode, answer));
-    if (rcode == isc::cc::CC_REPLY_NO_RECPT) {
-        isc_throw(RPCRecipientMissing, result);
-    } else if (rcode != isc::cc::CC_REPLY_SUCCESS) {
-        isc_throw_1(RPCError, result, rcode);
-    } else {
-        return (result);
-    }
-}
-
-void
-ModuleCCSession::notify(const std::string& group, const std::string& name,
-                        const ConstElementPtr& params)
-{
-    const ElementPtr message(Element::createMap());
-    const ElementPtr notification(Element::createList());
-    notification->add(Element::create(name));
-    if (params) {
-        notification->add(params);
-    }
-    message->set(isc::cc::CC_PAYLOAD_NOTIFICATION, notification);
-    groupSendMsg(message, isc::cc::CC_GROUP_NOTIFICATION_PREFIX + group,
-                 isc::cc::CC_INSTANCE_WILDCARD,
-                 isc::cc::CC_TO_WILDCARD, false);
-}
-
-ModuleCCSession::NotificationID
-ModuleCCSession::subscribeNotification(const std::string& notification_group,
-                                       const NotificationCallback& callback)
-{
-    // Either insert a new empty list of callbacks or get an existing one.
-    // Either way, get the iterator for its position.
-    const std::pair<SubscribedNotifications::iterator, bool>& inserted =
-        notifications_.insert(
-            std::pair<std::string, NotificationCallbacks>(notification_group,
-                NotificationCallbacks()));
-    if (inserted.second) {
-        // It was newly inserted. In that case, we need to subscribe to the
-        // group.
-        session_.subscribe(isc::cc::CC_GROUP_NOTIFICATION_PREFIX +
-                           notification_group);
-    }
-    // Insert the callback to the chain
-    NotificationCallbacks& callbacks = inserted.first->second;
-    const NotificationCallbacks::iterator& callback_id =
-        callbacks.insert(callbacks.end(), callback);
-    // Just pack the iterators to form the ID
-    return (NotificationID(inserted.first, callback_id));
-}
-
-void
-ModuleCCSession::unsubscribeNotification(const NotificationID& notification) {
-    NotificationCallbacks& callbacks = notification.first->second;
-    // Remove the callback
-    callbacks.erase(notification.second);
-    // If it became empty, remove it from the map and unsubscribe
-    if (callbacks.empty()) {
-        session_.unsubscribe(isc::cc::CC_GROUP_NOTIFICATION_PREFIX +
-                             notification.first->first);
-        notifications_.erase(notification.first);
-    }
-}
-
-bool
-ModuleCCSession::checkNotification(const data::ConstElementPtr& envelope,
-                                   const data::ConstElementPtr& msg)
-{
-    if (msg->getType() != data::Element::map) {
-        // If it's not a map, then it's not a notification
-        return (false);
-    }
-    if (msg->contains(isc::cc::CC_PAYLOAD_NOTIFICATION)) {
-        // There's a notification inside. Extract its parameters.
-        const std::string& group =
-            envelope->get(isc::cc::CC_HEADER_GROUP)->stringValue();
-        const std::string& notification_group =
-            group.substr(std::string(isc::cc::CC_GROUP_NOTIFICATION_PREFIX).
-                         size());
-        const data::ConstElementPtr& notification =
-            msg->get(isc::cc::CC_PAYLOAD_NOTIFICATION);
-        // The first one is the event that happened
-        const std::string& event = notification->get(0)->stringValue();
-        // Any other params are second. But they may be missing
-        const data::ConstElementPtr params =
-            notification->size() == 1 ? data::ConstElementPtr() :
-            notification->get(1);
-        // Find the chain of notification callbacks
-        const SubscribedNotifications::iterator& chain_iter =
-            notifications_.find(notification_group);
-        if (chain_iter == notifications_.end()) {
-            // This means we no longer have any notifications for this group.
-            // This can happen legally as a race condition - if msgq sends
-            // us a notification, but we unsubscribe before we get to it
-            // in the input stream.
-            return (false);
-        }
-        BOOST_FOREACH(const NotificationCallback& callback,
-                      chain_iter->second) {
-            callback(event, params);
-        }
-        return (true);
-    }
-    return (false); // Not a notification
-}
-
-}
-}

+ 0 - 788
src/lib/config/ccsession.h

@@ -1,788 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef CCSESSION_H
-#define CCSESSION_H 1
-
-#include <config/config_data.h>
-#include <config/module_spec.h>
-
-#include <cc/session.h>
-#include <cc/data.h>
-#include <cc/proto_defs.h>
-
-#include <string>
-#include <list>
-#include <boost/function.hpp>
-
-namespace isc {
-namespace config {
-
-///
-/// \brief Creates a standard config/command level success answer message
-///        (i.e. of the form { "result": [ 0 ] }
-/// \return Standard command/config success answer message
-isc::data::ConstElementPtr createAnswer();
-
-///
-/// \brief Creates a standard config/command level answer message
-///        (i.e. of the form { "result": [ rcode, arg ] }
-/// If rcode != 0, arg must be a StringElement
-///
-/// \param rcode The return code (0 for success)
-/// \param arg For rcode == 0, this is an optional argument of any
-///            Element type. For rcode == 1, this argument is mandatory,
-///            and must be a StringElement containing an error description
-/// \return Standard command/config answer message
-isc::data::ConstElementPtr createAnswer(const int rcode,
-                                        isc::data::ConstElementPtr arg);
-
-///
-/// \brief Creates a standard config/command level answer message
-/// (i.e. of the form { "result": [ rcode, arg ] }
-///
-/// \param rcode The return code (0 for success)
-/// \param arg A string to put into the StringElement argument
-/// \return Standard command/config answer message
-isc::data::ConstElementPtr createAnswer(const int rcode,
-                                        const std::string& arg);
-
-///
-/// Parses a standard config/command level answer message
-/// 
-/// \param rcode This value will be set to the return code contained in
-///              the message
-/// \param msg The message to parse
-/// \return The optional argument in the message, or an empty ElementPtr
-///         if there was no argument. If rcode != 0, this contains a
-///         StringElement with the error description.
-isc::data::ConstElementPtr parseAnswer(int &rcode,
-                                       isc::data::ConstElementPtr msg);
-
-///
-/// \brief Creates a standard config/command command message with no
-/// argument (of the form { "command": [ "my_command" ] }
-/// 
-/// \param command The command string
-/// \return The created message
-isc::data::ConstElementPtr createCommand(const std::string& command);
-
-///
-/// \brief Creates a standard config/command command message with the
-/// given argument (of the form { "command": [ "my_command", arg ] }
-/// 
-/// \param command The command string
-/// \param arg The optional argument for the command. This can be of 
-///        any Element type, but it should conform to the .spec file.
-/// \return The created message
-isc::data::ConstElementPtr createCommand(const std::string& command,
-                                         isc::data::ConstElementPtr arg);
-
-///
-/// \brief Parses the given command into a string containing the actual
-///        command and an ElementPtr containing the optional argument.
-///
-/// Raises a CCSessionError if this is not a well-formed command
-///
-/// Example code: (command_message is a ConstElementPtr that is
-/// passed here)
-/// \code
-/// ElementPtr command_message = Element::fromJSON("{ \"command\": [\"foo\", { \"bar\": 123 } ] }");
-/// try {
-///     ConstElementPtr args;
-///     std::string command_str = parseCommand(args, command_message);
-///     if (command_str == "foo") {
-///         std::cout << "The command 'foo' was given" << std::endl;
-///         if (args->contains("bar")) {
-///             std::cout << "It had argument name 'bar' set, which has"
-///                       << "value " 
-///                       << args->get("bar")->intValue();
-///         }
-///     } else {
-///         std::cout << "Unknown command '" << command_str << std::endl;
-///     }
-/// } catch (CCSessionError cse) {
-///     std::cerr << "Bad command in CC Session: "
-///     << cse.what() << std::endl;
-/// }
-/// \endcode
-/// 
-/// \param arg This value will be set to the ElementPtr pointing to
-///        the argument, or to an empty Map (ElementPtr) if there was none.
-/// \param command The command message containing the command (as made
-///        by createCommand()
-/// \return The command name
-std::string parseCommand(isc::data::ConstElementPtr& arg,
-                         isc::data::ConstElementPtr command);
-
-
-///
-/// \brief A standard cc session exception that is thrown if a function
-/// is there is a problem with one of the messages
-///
-// todo: include types and called function in the exception
-class CCSessionError : public isc::Exception {
-public:
-    CCSessionError(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-///
-/// \brief This exception is thrown if the constructor fails
-///
-class CCSessionInitError : public isc::Exception {
-public:
-    CCSessionInitError(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-/// \brief Exception thrown when there's a problem with the remote call.
-///
-/// This usually means either the command couldn't be called or the remote
-/// side sent an error as a response.
-class RPCError: public CCSessionError {
-public:
-    RPCError(const char* file, size_t line, const char* what, int rcode) :
-        CCSessionError(file, line, what),
-        rcode_(rcode)
-    {}
-
-    /// \brief The error code for the error.
-    int rcode() const {
-        return (rcode_);
-    }
-private:
-    const int rcode_;
-};
-
-/// \brief Specific version of RPCError for the case the recipient of command
-///     doesn't exist.
-class RPCRecipientMissing: public RPCError {
-public:
-    RPCRecipientMissing(const char* file, size_t line, const char* what) :
-        RPCError(file, line, what, isc::cc::CC_REPLY_NO_RECPT)
-    {}
-};
-
-///
-/// \brief This module keeps a connection to the command channel,
-/// holds configuration information, and handles messages from
-/// the command channel
-///
-class ModuleCCSession : public ConfigData {
-public:
-    /**
-     * Initialize a config/command session
-     *
-     * @param spec_file_name The name of the file containing the
-     *                        module specification.
-     * @param session A Session object over which configuration and command
-     * data are exchanged.
-     * @param config_handler A callback function pointer to be called when
-     * configuration of the local module needs to be updated.
-     * This must refer to a valid object of a concrete derived class of
-     * AbstractSession without establishing the session.
-     *
-     * Note: the design decision on who is responsible for establishing the
-     * session is in flux, and may change in near future.
-     *
-     * \exception CCSessionInitError when the initialization fails,
-     *            either because the file cannot be read or there is
-     *            a communication problem with the config manager.
-     *
-     * @param command_handler A callback function pointer to be called when
-     * a control command from a remote agent needs to be performed on the
-     * local module.
-     * @param start_immediately If true (default), start listening to new commands
-     * and configuration changes asynchronously at the end of the constructor;
-     * if false, it will be delayed until the start() method is explicitly
-     * called. (This is a short term workaround for an initialization trouble.
-     * We'll need to develop a cleaner solution, and then remove this knob)
-     * @param handle_logging If true, the ModuleCCSession will automatically
-     * take care of logging configuration through the virtual Logging config
-     * module. Defaults to true.
-     */
-    ModuleCCSession(const std::string& spec_file_name,
-                    isc::cc::AbstractSession& session,
-                    isc::data::ConstElementPtr(*config_handler)(
-                        isc::data::ConstElementPtr new_config) = NULL,
-                    isc::data::ConstElementPtr(*command_handler)(
-                        const std::string& command,
-                        isc::data::ConstElementPtr args) = NULL,
-                    bool start_immediately = true,
-                    bool handle_logging = true
-                    );
-
-    ///
-    /// Destructor
-    ///
-    /// The destructor automatically calls sendStopping(), which sends
-    /// a message to the ConfigManager that this module is stopping
-    ///
-    virtual ~ModuleCCSession();
-
-    /// Start receiving new commands and configuration changes asynchronously.
-    ///
-    /// This method must be called only once, and only when the ModuleCCSession
-    /// was constructed with start_immediately being false.  Otherwise
-    /// CCSessionError will be thrown.
-    ///
-    /// As noted in the constructor, this method should be considered a short
-    /// term workaround and will be removed in future.
-    void start();
-
-    /**
-     * Optional optimization for checkCommand loop; returns true
-     * if there are unhandled queued messages in the cc session.
-     * (if either this is true or there is data on the socket found
-     * by the select() call on getSocket(), run checkCommand())
-     * 
-     * @return true if there are unhandled queued messages
-     */
-    bool hasQueuedMsgs() const;
-
-    /**
-     * Check if there is a command or config change on the command
-     * session. If so, the appropriate handler is called if set.
-     * If not set, a default answer is returned.
-     * This is a non-blocking read; if there is nothing this function
-     * will return 0.
-     */
-    int checkCommand();
-
-    /**
-     * The config handler function should expect an ElementPtr containing
-     * the full configuration where non-default values have been set.
-     * Later we might want to think about more granular control
-     * (i.e. this does not scale to for instance lists containing
-     * 100000 zones, where the whole list is passed every time a single
-     * thing changes)
-     */
-    void setConfigHandler(isc::data::ConstElementPtr(*config_handler)(
-                              isc::data::ConstElementPtr new_config))
-    {
-        config_handler_ = config_handler;
-    }
-
-    /**
-     * Set a command handler; the function that is passed takes an
-     * ElementPtr, pointing to a list element, containing
-     * [ module_name, command_name, arg1, arg2, ... ]
-     * The returned ElementPtr should look like
-     * { "result": [ return_value, result_value ] }
-     * result value here is optional and depends on the command
-     *
-     * This protocol is very likely to change.
-     */
-    void setCommandHandler(isc::data::ConstElementPtr(*command_handler)(
-                               const std::string& command,
-                               isc::data::ConstElementPtr args))
-    {
-        command_handler_ = command_handler;
-    }
-
-    /**
-     * Gives access to the configuration values of a different module
-     * Once this function has been called with the name of the specification
-     * file or the module you want the configuration of, you can use
-     * \c getRemoteConfigValue() to get a specific setting.
-     * Changes are automatically updated, and you can specify handlers
-     * for those changes. This function will subscribe to the relevant module
-     * channel.
-     *
-     * This method must be called before calling the \c start() method on the
-     * ModuleCCSession (it also implies the ModuleCCSession must have been
-     * constructed with start_immediately being false).
-     *
-     * \param spec_name This specifies the module to add. It is either a
-     *                  filename of the spec file to use or a name of module
-     *                  (in case it's a module name, the spec data is
-     *                  downloaded from the configuration manager, therefore
-     *                  the configuration manager must know it). If
-     *                  spec_is_filename is true (the default), then a
-     *                  filename is assumed, otherwise a module name.
-     * \param handler The handler functor called whenever there's a change.
-     *                Called once initially from this function. May be NULL
-     *                if you don't want any handler to be called and you're
-     *                fine with requesting the data through
-     *                getRemoteConfigValue() each time.
-     *
-     *                The handler should not throw, or it'll fall through and
-     *                the exception will get into strange places, probably
-     *                aborting the application.
-     * \param spec_is_filename Says if spec_name is filename or module name.
-     * \return The name of the module specified in the given specification
-     *         file
-     */
-    typedef boost::function<void(const std::string&,
-                                 isc::data::ConstElementPtr,
-                                 const ConfigData&)> RemoteHandler;
-    std::string addRemoteConfig(const std::string& spec_name,
-                                RemoteHandler handler = RemoteHandler(),
-                                bool spec_is_filename = true);
-
-    /**
-     * Removes the module with the given name from the remote config
-     * settings. If the module was not added with \c addRemoteConfig(),
-     * nothing happens. If there was a handler for this config, it is
-     * removed as well.
-     */
-    void removeRemoteConfig(const std::string& module_name);
-
-    /**
-     * Returns the current configuration value for the given module
-     * name at the given identifier. See \c ConfigData::getValue() for
-     * more details.
-     * Raises a ModuleCCSessionError if the module name is unknown
-     * Raises a DataNotFoundError if the identifier does not exist
-     * in the specification.
-     *
-     * \param module_name The name of the module to get a config value for
-     * \param identifier The identifier of the config value
-     * \return The configuration setting at the given identifier
-     */
-    isc::data::ConstElementPtr getRemoteConfigValue(
-        const std::string& module_name,
-        const std::string& identifier) const;
-
-    /**
-     * Send a message to the underlying CC session.
-     * This has the same interface as isc::cc::Session::group_sendmsg()
-     *
-     * \param msg see isc::cc::Session::group_sendmsg()
-     * \param group see isc::cc::Session::group_sendmsg()
-     * \param instance see isc::cc::Session::group_sendmsg()
-     * \param to see isc::cc::Session::group_sendmsg()
-     * \param want_answer see isc::cc::Session::group_sendmsg()
-     * \return see isc::cc::Session::group_sendmsg()
-     */
-    int groupSendMsg(isc::data::ConstElementPtr msg,
-                     std::string group,
-                     std::string instance = isc::cc::CC_INSTANCE_WILDCARD,
-                     std::string to = isc::cc::CC_TO_WILDCARD,
-                     bool want_answer = false) {
-        return (session_.group_sendmsg(msg, group, instance, to, want_answer));
-    };
-
-    /// \brief Receive a message from the underlying CC session.
-    /// This has the same interface as isc::cc::Session::group_recvmsg()
-    ///
-    /// NOTE: until #2804 is resolved this method wouldn't work except in
-    /// very limited cases; don't try to use it until then.
-    ///
-    /// \param envelope see isc::cc::Session::group_recvmsg()
-    /// \param msg see isc::cc::Session::group_recvmsg()
-    /// \param nonblock see isc::cc::Session::group_recvmsg()
-    /// \param seq see isc::cc::Session::group_recvmsg()
-    /// \return see isc::cc::Session::group_recvmsg()
-    bool groupRecvMsg(isc::data::ConstElementPtr& envelope,
-                      isc::data::ConstElementPtr& msg,
-                      bool nonblock = true,
-                      int seq = -1) {
-        return (session_.group_recvmsg(envelope, msg, nonblock, seq));
-    }
-
-    /// \brief Send a command message and wait for the answer.
-    ///
-    /// NOTE: until #2804 is resolved this method wouldn't work except in
-    /// very limited cases; don't try to use it until then.
-    ///
-    /// This is mostly a convenience wrapper around groupSendMsg
-    /// and groupRecvMsg, with some error handling.
-    ///
-    /// \param command Name of the command to call.
-    /// \param group Name of the remote module to call the command on.
-    /// \param instance Instance part of recipient address.
-    /// \param to The lname to send it to. Can be used to override the
-    ///     addressing and use a direct recipient.
-    /// \param params Parameters for the command. Can be left NULL if
-    ///     no parameters are needed.
-    /// \return Return value of the successfull remote call. It can be
-    ///     NULL if the remote command is void function (returns nothing).
-    /// \throw RPCError if the call fails (for example when the other
-    ///     side responds with error code).
-    /// \throw RPCRecipientMissing if the recipient doesn't exist.
-    /// \throw CCSessionError if some lower-level error happens (eg.
-    ///     the response was malformed).
-    isc::data::ConstElementPtr rpcCall(const std::string& command,
-                                       const std::string& group,
-                                       const std::string& instance =
-                                           isc::cc::CC_INSTANCE_WILDCARD,
-                                       const std::string& to =
-                                           isc::cc::CC_TO_WILDCARD,
-                                       const isc::data::ConstElementPtr&
-                                           params =
-                                           isc::data::ConstElementPtr());
-
-    /// \brief Send a notification to subscribed users
-    ///
-    /// Send a notification message to all users subscribed to the given
-    /// notification group.
-    ///
-    /// This method does not not block.
-    ///
-    /// See docs/design/ipc-high.txt for details about notifications and
-    /// the format of messages sent.
-    ///
-    /// \throw CCSessionError for low-level communication errors.
-    /// \param notification_group This parameter (indirectly) signifies what
-    ///     users should receive the notification. Only the users that
-    ///     subscribed to notifications on the same group receive it.
-    /// \param name The name of the event to notify about (for example
-    ///     `new_group_member`).
-    /// \param params Other parameters that describe the event. This might
-    ///     be, for example, the ID of the new member and the name of the
-    ///     group. This can be any data element, but it is common for it to be
-    ///     map.
-    void notify(const std::string& notification_group,
-                const std::string& name,
-                const isc::data::ConstElementPtr& params =
-                    isc::data::ConstElementPtr());
-
-    /// \brief Convenience version of rpcCall
-    ///
-    /// This is exactly the same as the previous version of rpcCall, except
-    /// that the instance and to parameters are at their default. This
-    /// allows to sending a command with parameters to a named module
-    /// without long typing of the parameters.
-    isc::data::ConstElementPtr rpcCall(const std::string& command,
-                                       const std::string& group,
-                                       const isc::data::ConstElementPtr&
-                                           params)
-    {
-        return rpcCall(command, group, isc::cc::CC_INSTANCE_WILDCARD,
-                       isc::cc::CC_TO_WILDCARD, params);
-    }
-
-    /// \brief Forward declaration of internal data structure.
-    ///
-    /// This holds information about one asynchronous request to receive
-    /// a message. It is declared as public to allow declaring other derived
-    /// types, but without showing the internal representation.
-    class AsyncRecvRequest;
-
-    /// \brief List of all requests for asynchronous reads.
-    typedef std::list<AsyncRecvRequest> AsyncRecvRequests;
-
-    /// \brief Identifier of single request for asynchronous read.
-    typedef AsyncRecvRequests::iterator AsyncRecvRequestID;
-
-    /// \brief Callback which is called when an asynchronous receive finishes.
-    ///
-    /// This is the callback used by groupRecvMsgAsync() function. It is called
-    /// when a matching message arrives. It receives following parameters when
-    /// called:
-    /// - The envelope of the message
-    /// - The message itself
-    /// - The ID of the request, as returned by corresponding groupRecvMsgAsync
-    ///   call.
-    ///
-    /// It is possible to throw exceptions from the callback, but they will not
-    /// be caught and they will get propagated out through the checkCommand()
-    /// call. This, if not handled on higher level, will likely terminate the
-    /// application. However, the ModuleCCSession internals will be in
-    /// well-defined state after the call (both the callback and the message
-    /// will be removed from the queues as already called).
-    typedef boost::function3<void, const isc::data::ConstElementPtr&,
-                             const isc::data::ConstElementPtr&,
-                             const AsyncRecvRequestID&>
-        AsyncRecvCallback;
-
-    /// \brief Receive a message from the CC session asynchronously.
-    ///
-    /// This registers a callback which is called when a matching message
-    /// is received. This message returns immediately.
-    ///
-    /// Once a matching message arrives, the callback is called with the
-    /// envelope of the message, the message itself and the result of this
-    /// function call (which might be useful for identifying which of many
-    /// events the recipient is waiting for this is). This makes the callback
-    /// used and is not called again even if a message that would match
-    /// arrives later (this is a single-shot callback).
-    ///
-    /// The callback is never called from within this function. Even if there
-    /// are queued messages, the callback would be called once checkCommand()
-    /// is invoked (possibly from start() or the constructor).
-    ///
-    /// The matching is as follows. If is_reply is true, only replies are
-    /// considered. In that case, if seq is -1, any reply is accepted. If
-    /// it is something else than -1, only the reply with matching seq is
-    /// taken. This may be used to receive replies to commands
-    /// asynchronously.
-    ///
-    /// In case the is_reply is false, the function looks for command messages.
-    /// The seq parameter is ignored, but the recipient one is considered. If
-    /// it is an empty string, any command is taken. If it is non-empty, only
-    /// commands addressed to the recipient channel (eg. group - instance is
-    /// ignored for now) are taken. This can be used to receive foreign commands
-    /// or notifications. In such case, it might be desirable to call the
-    /// groupRecvMsgAsync again from within the callback, to receive any future
-    /// commands or events of the same type.
-    ///
-    /// The interaction with other receiving functions is slightly complicated.
-    /// The groupRecvMsg call takes precedence. If the message matches its
-    /// parameters, it steals the message and no callback matching it as well
-    /// is called. Then, all the queued asynchronous receives are considered,
-    /// with the oldest active ones taking precedence (they work as FIFO).
-    /// If none of them matches, generic command and config handling takes
-    /// place. If it is not handled by that, the message is dropped. However,
-    /// it is better if there's just one place that wants to receive each given
-    /// message.
-    ///
-    /// \exception std::bad_alloc if there isn't enough memory to store the
-    ///     callback.
-    /// \param callback is the function to be called when a matching message
-    ///     arrives.
-    /// \param is_reply specifies if the desired message should be a reply or
-    ///     a command.
-    /// \param seq specifies the reply sequence number in case a reply is
-    ///     desired. The default -1 means any reply is OK.
-    /// \param recipient is the CC channel to which the command should be
-    ///     addressed to match (in case is_reply is false). Empty means any
-    ///     command is good one.
-    /// \return An identifier of the request. This will be passed to the
-    ///     callback or can be used to cancel the request by cancelAsyncRecv.
-    /// \todo Decide what to do with instance and what was it meant for anyway.
-    AsyncRecvRequestID groupRecvMsgAsync(const AsyncRecvCallback& callback,
-                                         bool is_reply, int seq = -1,
-                                         const std::string& recipient =
-                                         std::string());
-
-    /// \brief Removes yet unused request for asynchronous receive.
-    ///
-    /// This function cancels a request previously queued by
-    /// groupRecvMsgAsync(). You may use it only before the callback was
-    /// already triggered. If you call it with an ID of callback that
-    /// already happened or was already canceled, the behaviour is undefined
-    /// (but something like a crash is very likely, as the function removes
-    /// an item from a list and this would be removing it from a list that
-    /// does not contain the item).
-    ///
-    /// It is important to cancel requests that are no longer going to happen
-    /// for some reason, as the request would occupy memory forever.
-    ///
-    /// \param id The id of request as returned by groupRecvMsgAsync.
-    void cancelAsyncRecv(const AsyncRecvRequestID& id);
-
-    /// \brief Called when a notification comes
-    ///
-    /// The callback should be exception-free. If it raises an exception,
-    /// it'll leak through the event loop up and probably terminate the
-    /// application.
-    ///
-    /// \param event_name The identification of event type.
-    /// \param params The parameters of the event. This may be NULL
-    ///     pointer in case no parameters were sent with the event.
-    typedef boost::function<void (const std::string& event_name,
-                                  const data::ConstElementPtr& params)>
-        NotificationCallback;
-
-    /// \brief Multiple notification callbacks for the same notification
-    typedef std::list<NotificationCallback> NotificationCallbacks;
-
-    /// \brief Mapping from groups to callbacks
-    typedef std::map<std::string, NotificationCallbacks>
-        SubscribedNotifications;
-
-    /// \brief Identification of single callback
-    typedef std::pair<SubscribedNotifications::iterator,
-                      NotificationCallbacks::iterator>
-        NotificationID;
-
-    /// \brief Subscribe to a notification group
-    ///
-    /// From now on, every notification that is sent to the given group
-    /// triggers the passed callback.
-    ///
-    /// There may be multiple (independent) callbacks for the same channel.
-    /// This one adds a new one, to the end of the chain (the callbacks
-    /// are called in the same order as they were registered).
-    ///
-    /// \param notification_group The channel of notifications.
-    /// \param callback The callback to be added.
-    /// \return ID of the notification callback. It is an opaque ID and can
-    ///     be used to remove this callback.
-    NotificationID subscribeNotification(const std::string& notification_group,
-                                         const NotificationCallback& callback);
-
-    /// \brief Unsubscribe the callback from its notification group.
-    ///
-    /// Express that the desire for this callback to be executed is no longer
-    /// relevant. All the other callbacks (even for the same notification
-    /// group) are left intact.
-    ///
-    /// \param notification The ID of notification callback returned by
-    ///     subscribeNotification.
-    void unsubscribeNotification(const NotificationID& notification);
-
-    /// \brief Subscribe to a group
-    ///
-    /// Wrapper around the CCSession::subscribe.
-    void subscribe(const std::string& group) {
-        session_.subscribe(group, isc::cc::CC_INSTANCE_WILDCARD);
-    }
-
-    /// \brief Unsubscribe from a group.
-    ///
-    /// Wrapper around the CCSession::unsubscribe.
-    void unsubscribe(const std::string& group) {
-        session_.unsubscribe(group, isc::cc::CC_INSTANCE_WILDCARD);
-    }
-
-    /// \brief Callback type for unhandled commands
-    ///
-    /// The type of functions that are not handled by the ModuleCCSession
-    /// because they are not aimed at the module.
-    ///
-    /// The parameters are:
-    /// - Name of the command.
-    /// - The module it was aimed for (may be empty).
-    /// - The parameters of the command.
-    typedef boost::function<void (const std::string&, const std::string&,
-                                  const isc::data::ConstElementPtr&)>
-        UnhandledCallback;
-
-    /// \brief Register a callback for messages sent to foreign modules.
-    ///
-    /// Usually, a command aimed at foreign module (or sent directly)
-    /// is discarded. By registering a callback here, these can be
-    /// examined.
-    ///
-    /// \note A callback overwrites the previous one set.
-    /// \todo This is a temporary, unclean, solution. A more generic
-    ///     one needs to be designed. Also, a solution that is able
-    ///     to send an answer would be great.
-    ///
-    /// \param callback The new callback to use. It may be an empty
-    ///     function.
-    void setUnhandledCallback(const UnhandledCallback& callback) {
-        unhandled_callback_ = callback;
-    }
-
-private:
-    ModuleSpec readModuleSpecification(const std::string& filename);
-    void startCheck();
-    void sendStopping();
-    /// \brief Check if the message is wanted by asynchronous read
-    ///
-    /// It checks if any of the previously queued requests match
-    /// the message. If so, the callback is dispatched and removed.
-    ///
-    /// \param envelope The envelope of the message.
-    /// \param msg The actual message data.
-    /// \return True if the message was used for a callback, false
-    ///     otherwise.
-    bool checkAsyncRecv(const data::ConstElementPtr& envelope,
-                        const data::ConstElementPtr& msg);
-    bool checkNotification(const data::ConstElementPtr& envelope,
-                           const data::ConstElementPtr& msg);
-    /// \brief Checks if a message with this envelope matches the request
-    bool requestMatch(const AsyncRecvRequest& request,
-                      const data::ConstElementPtr& envelope) const;
-
-    bool started_;
-    std::string module_name_;
-    isc::cc::AbstractSession& session_;
-    ModuleSpec module_specification_;
-    AsyncRecvRequests async_recv_requests_;
-    SubscribedNotifications notifications_;
-
-    isc::data::ConstElementPtr handleConfigUpdate(
-        isc::data::ConstElementPtr new_config);
-
-    isc::data::ConstElementPtr checkConfigUpdateCommand(
-        const std::string& target_module,
-        isc::data::ConstElementPtr arg);
-
-    isc::data::ConstElementPtr checkModuleCommand(
-        const std::string& cmd_str,
-        const std::string& target_module,
-        isc::data::ConstElementPtr arg) const;
-
-    isc::data::ConstElementPtr(*config_handler_)(
-        isc::data::ConstElementPtr new_config);
-    isc::data::ConstElementPtr(*command_handler_)(
-        const std::string& command,
-        isc::data::ConstElementPtr args);
-
-    std::map<std::string, ConfigData> remote_module_configs_;
-    std::map<std::string, RemoteHandler> remote_module_handlers_;
-
-    void updateRemoteConfig(const std::string& module_name,
-                            isc::data::ConstElementPtr new_config);
-
-    ModuleSpec fetchRemoteSpec(const std::string& module, bool is_filename);
-
-    UnhandledCallback unhandled_callback_;
-};
-
-/// \brief Default handler for logging config updates
-///
-/// When CCSession is initialized with handle_logging set to true,
-/// this callback will be used to update the logger when a configuration
-/// change comes in.
-///
-/// This function updates the (global) loggers by initializing a
-/// LoggerManager and passing the settings as specified in the given
-/// configuration update.
-///
-/// \param module_name The name of the module
-/// \param new_config The modified configuration values
-/// \param config_data The full config data for the (remote) logging
-///                    module.
-void
-default_logconfig_handler(const std::string& module_name,
-                          isc::data::ConstElementPtr new_config,
-                          const ConfigData& config_data);
-
-
-/// \brief Returns the loggers related to this module
-///
-/// This function does two things;
-/// - it drops the configuration parts for loggers for other modules.
-/// - it replaces the '*' in the name of the loggers by the name of
-///   this module, but *only* if the expanded name is not configured
-///   explicitly.
-///
-/// Examples: if this is the module b10-resolver,
-/// For the config names ['*', 'b10-auth']
-/// The '*' is replaced with 'b10-resolver', and this logger is used.
-/// 'b10-auth' is ignored (of course, it will not be in the b10-auth
-/// module).
-///
-/// For ['*', 'b10-resolver']
-/// The '*' is ignored, and only 'b10-resolver' is used.
-///
-/// For ['*.reslib', 'b10-resolver']
-/// Or ['b10-resolver.reslib', '*']
-/// Both are used, where the * will be expanded to b10-resolver
-///
-/// \note This is a public function at this time, but mostly for
-/// the purposes of testing. Once we can directly test what loggers
-/// are running, this function may be moved to the unnamed namespace
-///
-/// \param loggers the original 'loggers' config list
-/// \return ListElement containing only loggers relevant for this
-///         module, where * is replaced by the root logger name
-isc::data::ConstElementPtr
-getRelatedLoggers(isc::data::ConstElementPtr loggers);
-
-} // namespace config
-
-} // namespace isc
-#endif // CCSESSION_H
-
-// Local Variables:
-// mode: c++
-// End:

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

@@ -11,21 +11,18 @@ endif
 
 CLEANFILES = *.gcno *.gcda
 
-noinst_LTLIBRARIES = libfake_session.la
-libfake_session_la_SOURCES = fake_session.h fake_session.cc
-
 TESTS_ENVIRONMENT = \
 	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
-run_unittests_SOURCES = ccsession_unittests.cc module_spec_unittests.cc config_data_unittests.cc run_unittests.cc
+run_unittests_SOURCES = module_spec_unittests.cc
+run_unittests_SOURCES += config_data_unittests.cc 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 += libfake_session.la
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1219
src/lib/config/tests/ccsession_unittests.cc


+ 0 - 274
src/lib/config/tests/fake_session.cc

@@ -1,274 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-
-#include <stdint.h>
-
-#include <cstdio>
-#include <vector>
-#include <iostream>
-#include <sstream>
-
-#include <boost/foreach.hpp>
-
-#include <exceptions/exceptions.h>
-
-#include <cc/data.h>
-#include <config/tests/fake_session.h>
-
-using namespace std;
-using namespace isc::cc;
-using namespace isc::data;
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-// ok i want these in cc/data 
-bool
-listContains(ConstElementPtr list, ConstElementPtr el) {
-    if (!list) {
-        return (false);
-    }
-    BOOST_FOREACH(ConstElementPtr l_el, list->listValue()) {
-        if (*l_el == *el) {
-            return (true);
-        }
-    }
-    return (false);
-}
-
-void
-listRemove(ElementPtr list, ConstElementPtr el) {
-    int i = 0;
-    BOOST_FOREACH(ConstElementPtr s_el, list->listValue()) {
-        if (*el == *s_el) {
-            list->remove(i);
-            return;
-        }
-        i++;
-    }
-}
-// endwant
-
-namespace isc {
-namespace cc {
-
-FakeSession::FakeSession(isc::data::ElementPtr initial_messages,
-                         isc::data::ElementPtr subscriptions,
-                         isc::data::ElementPtr msg_queue) :
-    messages_(initial_messages),
-    subscriptions_(subscriptions),
-    msg_queue_(msg_queue),
-    started_(false),
-    throw_on_send_(false)
-{
-}
-
-FakeSession::~FakeSession() {
-}
-
-void
-FakeSession::disconnect() {
-}
-
-void
-FakeSession::startRead(boost::function<void()>) {
-    started_ = true;
-}
-
-void
-FakeSession::establish(const char*) {
-}
-
-bool
-FakeSession::recvmsg(ConstElementPtr& msg, bool nonblock, int) {
-    if (started_ && !nonblock) {
-        // This would schedule another read for length, leading to
-        // corrupted data
-        isc_throw(DoubleRead, "Second read scheduled from recvmsg");
-    }
-
-    //cout << "[XX] client asks for message " << endl;
-    if (messages_ &&
-        messages_->getType() == Element::list &&
-        !messages_->empty()) {
-        msg = messages_->get(0);
-        messages_->remove(0);
-    } else {
-        msg = ElementPtr();
-    }
-    return (true);
-}
-
-bool
-FakeSession::recvmsg(ConstElementPtr& env, ConstElementPtr& msg, bool nonblock,
-                     int)
-{
-    if (started_ && !nonblock) {
-        // This would schedule another read for length, leading to
-        // corrupted data
-        isc_throw(DoubleRead, "Second read scheduled from recvmsg");
-    }
-
-    //cout << "[XX] client asks for message and env" << endl;
-    env = ElementPtr();
-    if (messages_ &&
-        messages_->getType() == Element::list &&
-        !messages_->empty()) {
-        // do we need initial message to have env[group] and [to] too?
-        msg = messages_->get(0);
-        messages_->remove(0);
-        return (true);
-    } else if (msg_queue_) {
-        BOOST_FOREACH(ConstElementPtr c_m, msg_queue_->listValue()) {
-            ConstElementPtr to_remove = ElementPtr();
-            if (haveSubscription(c_m->get(0), c_m->get(1))) {
-                ElementPtr new_env = Element::createMap();
-                new_env->set("group", c_m->get(0));
-                new_env->set("to", c_m->get(1));
-                if (c_m->get(3)->intValue() != -1) {
-                    new_env->set("reply", c_m->get(3));
-                }
-                env = new_env;
-                msg = c_m->get(2);
-                to_remove = c_m;
-            }
-            if (to_remove) {
-                listRemove(msg_queue_, to_remove);
-                return (true);
-            }
-        }
-    }
-    msg = ElementPtr();
-    env = ElementPtr();
-    return (false);
-}
-
-void
-FakeSession::subscribe(std::string group, std::string instance) {
-    //cout << "[XX] client subscribes to " << group << " . " << instance << endl;
-    ElementPtr s_el = Element::createList();
-    s_el->add(Element::create(group));
-    s_el->add(Element::create(instance));
-    if (!subscriptions_) {
-        subscriptions_ = Element::createList();
-    }
-    subscriptions_->add(s_el);
-}
-
-void
-FakeSession::unsubscribe(std::string group, std::string instance) {
-    //cout << "[XX] client unsubscribes from " << group << " . " << instance << endl;
-    ElementPtr s_el = Element::createList();
-    s_el->add(Element::create(group));
-    s_el->add(Element::create(instance));
-    if (!subscriptions_) {
-        return;
-    }
-    listRemove(subscriptions_, s_el);
-}
-
-int
-FakeSession::group_sendmsg(ConstElementPtr msg, std::string group,
-                           std::string to, std::string, bool want_answer)
-{
-    if (throw_on_send_) {
-        isc_throw(Exception, "Throw on send is set in FakeSession");
-    }
-    addMessage(msg, group, to, -1, want_answer);
-    return (1);
-}
-
-bool
-FakeSession::group_recvmsg(ConstElementPtr& envelope, ConstElementPtr& msg,
-                           bool nonblock, int seq)
-{
-    return (recvmsg(envelope, msg, nonblock, seq));
-}
-
-int
-FakeSession::reply(ConstElementPtr envelope, ConstElementPtr newmsg) {
-    //cout << "[XX] client sends reply: " << newmsg << endl;
-    //cout << "[XX] env: " << envelope << endl;
-    addMessage(newmsg, envelope->get("group")->stringValue(),
-               envelope->get("to")->stringValue());
-    return (1);
-}
-
-bool
-FakeSession::hasQueuedMsgs() const {
-    return (msg_queue_ && !msg_queue_->empty());
-}
-
-ConstElementPtr
-FakeSession::getFirstMessage(std::string& group, std::string& to) const {
-    ConstElementPtr el;
-    if (msg_queue_ && !msg_queue_->empty()) {
-        el = msg_queue_->get(0);
-        msg_queue_->remove(0);
-        group = el->get(0)->stringValue();
-        to = el->get(1)->stringValue();
-        return (el->get(2));
-    } else {
-        group = "";
-        to = "";
-        return (ElementPtr());
-    }
-}
-
-void
-FakeSession::addMessage(ConstElementPtr msg, const std::string& group,
-                        const std::string& to, int seq, bool want_answer)
-{
-    ElementPtr m_el = Element::createList();
-    m_el->add(Element::create(group));
-    m_el->add(Element::create(to));
-    m_el->add(msg);
-    m_el->add(Element::create(seq));
-    if (want_answer) {
-        m_el->add(Element::create(want_answer));
-    }
-    if (!msg_queue_) {
-        msg_queue_ = Element::createList();
-    }
-    msg_queue_->add(m_el);
-}
-
-bool
-FakeSession::haveSubscription(const std::string& group,
-                              const std::string& instance)
-{
-    if (!subscriptions_) {
-        return (false);
-    }
-    ElementPtr s1 = Element::createList();
-    ElementPtr s2 = Element::createList();
-    s1->add(Element::create(group));
-    s1->add(Element::create(instance));
-    s2->add(Element::create(group));
-    s2->add(Element::create("*"));
-    bool result = (listContains(subscriptions_, s1) ||
-                   listContains(subscriptions_, s2));
-    return (result);
-}
-
-bool
-FakeSession::haveSubscription(ConstElementPtr group, ConstElementPtr instance)
-{
-    return (haveSubscription(group->stringValue(), instance->stringValue()));
-}
-}
-}

+ 0 - 120
src/lib/config/tests/fake_session.h

@@ -1,120 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef ISC_FAKESESSION_H
-#define ISC_FAKESESSION_H 1
-
-#include <string>
-
-#include <boost/function.hpp>
-
-#include <exceptions/exceptions.h>
-
-#include <cc/data.h>
-#include <cc/session.h>
-
-namespace isc {
-namespace cc {
-class FakeSession : public AbstractSession {
-private:
-    FakeSession(const Session& source);
-    FakeSession& operator=(const Session& source);
-
-public:
-    // if initial_messages contains a list of messages,
-    // these are sent when recv_msg or group_recvmsg is called
-    // instead of whatever is in the msg queue.
-    // The test can also add data to a copy of the message later to tweak
-    // the group_recvmsg() behavior.  See getMessages() below.
-    FakeSession(isc::data::ElementPtr initial_messages,
-                isc::data::ElementPtr subscriptions,
-                isc::data::ElementPtr msg_queue);
-    virtual ~FakeSession();
-
-    // This is thrown if two reads for length at once are scheduled at once.
-    // Such thing does bad things currently (see discussion in ticket #931).
-    class DoubleRead : public Exception {
-    public:
-        DoubleRead(const char* file, size_t line, const char* what) :
-            Exception(file, line, what) {}
-    };
-
-    virtual void startRead(boost::function<void()> read_callback);
-
-    virtual void establish(const char* socket_file = NULL);
-    virtual void disconnect();
-    virtual void subscribe(std::string group,
-                           std::string instance = "*");
-    virtual void unsubscribe(std::string group,
-                             std::string instance = "*");
-    virtual int group_sendmsg(isc::data::ConstElementPtr msg,
-                              std::string group,
-                              std::string instance = "*",
-                              std::string to = "*",
-                              bool want_answer = false);
-    virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
-                               isc::data::ConstElementPtr& msg,
-                               bool nonblock = true,
-                               int seq = -1);
-    virtual int reply(isc::data::ConstElementPtr envelope,
-                      isc::data::ConstElementPtr newmsg);
-    virtual bool hasQueuedMsgs() const;
-    virtual void setTimeout(size_t) {}
-    virtual size_t getTimeout() const { return (0); }
-    isc::data::ConstElementPtr getFirstMessage(std::string& group,
-                                               std::string& to) const;
-    void addMessage(isc::data::ConstElementPtr, const std::string& group,
-                    const std::string& to, int seq = -1,
-                    bool want_answer = false);
-    bool haveSubscription(const std::string& group,
-                          const std::string& instance);
-    bool haveSubscription(const isc::data::ConstElementPtr group,
-                          const isc::data::ConstElementPtr instance);
-
-    // For the convenience of tests, we share these internal members
-    // with the tester.  The test code may insert update and check,
-    // before (via the constructor parameters), during and after the actual
-    // session object was created/destroyed.
-    isc::data::ElementPtr getMessages() { return (messages_); }
-    isc::data::ElementPtr getMsgQueue() { return (msg_queue_); }
-
-    /// Throw exception on sendmsg()
-    ///
-    /// When set to true, and sendmsg() is later called, this
-    /// will throw isc::Exception
-    ///
-    /// \param value If true, enable throw. If false, disable it
-    void setThrowOnSend(bool value) { throw_on_send_ = value; }
-
-private:
-    bool recvmsg(isc::data::ConstElementPtr& msg,
-                 bool nonblock = true, int seq = -1);
-    bool recvmsg(isc::data::ConstElementPtr& env,
-                 isc::data::ConstElementPtr& msg,
-                 bool nonblock = true, int seq = -1);
-
-    const isc::data::ElementPtr messages_;
-    isc::data::ElementPtr subscriptions_;
-    isc::data::ElementPtr msg_queue_;
-    bool started_;
-    bool throw_on_send_;
-};
-} // namespace cc
-} // namespace isc
-
-#endif // ISC_FAKESESSION_H
-
-// Local Variables:
-// mode: c++
-// End:

+ 1 - 1
src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc

@@ -14,7 +14,7 @@
 
 #include <config.h>
 
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/parsers/dbaccess_parser.h>
 #include <log/logger_support.h>

+ 1 - 1
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc

@@ -13,7 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <config.h>
-#include <config/ccsession.h>
+#include <cc/command_interpreter.h>
 #include <cc/data.h>
 #include <dhcp/option.h>
 #include <dhcp/option_custom.h>

+ 7 - 6
src/lib/dhcpsrv/testutils/config_result_check.cc

@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <cc/proto_defs.h>
+#include <cc/command_interpreter.h>
 #include <dhcpsrv/testutils/config_result_check.h>
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/constants.hpp>
@@ -28,15 +28,16 @@ using namespace isc::data;
 
 bool errorContainsPosition(ConstElementPtr error_element,
                            const std::string& file_name) {
-    if (error_element->contains(isc::cc::CC_PAYLOAD_RESULT)) {
-        ConstElementPtr result = error_element->get(isc::cc::CC_PAYLOAD_RESULT);
-        if ((result->getType() != Element::list) || (result->size() < 2) ||
-            (result->get(1)->getType() != Element::string)) {
+    if (error_element->contains(isc::config::CONTROL_RESULT)) {
+        ConstElementPtr result = error_element->get(isc::config::CONTROL_RESULT);
+        ConstElementPtr text = error_element->get(isc::config::CONTROL_TEXT);
+        if (!result || (result->getType() != Element::integer) || !text
+            || (text->getType() != Element::string)) {
             return (false);
         }
 
         // Get the error message in the textual format.
-        std::string error_string = result->get(1)->stringValue();
+        std::string error_string = text->stringValue();
 
         // The position of the data element causing an error has the following
         // format: <filename>:<linenum>:<pos>. The <filename> has been specified

+ 0 - 82
src/lib/testutils/mockups.h

@@ -18,9 +18,6 @@
 #include <exceptions/exceptions.h>
 
 #include <cc/data.h>
-#include <cc/session.h>
-
-//#include <xfr/xfrout_client.h>
 
 #include <asiodns/asiodns.h>
 
@@ -30,85 +27,6 @@
 namespace isc {
 namespace testutils {
 
-// A minimal mock configuration session.  Most the methods are
-// stubbed out, except for a very basic group_sendmsg() and
-// group_recvmsg().  hasQueuedMessages() always returns false.
-class MockSession : public isc::cc::AbstractSession {
-public:
-    MockSession() :
-        // by default we return a simple "success" message.
-        msg_(isc::data::Element::fromJSON("{\"result\": [0, \"SUCCESS\"]}")),
-        send_ok_(true), receive_ok_(true), answer_wanted_(false)
-    {}
-
-
-    virtual void establish(const char*) {}
-    virtual void disconnect() {}
-
-    virtual int group_sendmsg(isc::data::ConstElementPtr msg,
-                              std::string group,
-                              std::string, std::string, bool want_answer)
-    {
-        if (!send_ok_) {
-            isc_throw(isc::cc::SessionError,
-                      "mock session send is disabled for test");
-        }
-
-        sent_msg_ = msg;
-        msg_dest_ = group;
-        answer_wanted_ = want_answer;
-        return (0);
-    }
-
-    virtual bool group_recvmsg(isc::data::ConstElementPtr&,
-                               isc::data::ConstElementPtr& msg, bool, int)
-    {
-        if (!receive_ok_) {
-            isc_throw(isc::cc::SessionError,
-                      "mock session receive is disabled for test");
-        }
-
-        msg = msg_;
-        return (true);
-    }
-
-    virtual void subscribe(std::string, std::string) {}
-    virtual void unsubscribe(std::string, std::string) {}
-
-    virtual void startRead(boost::function<void()>) {}
-
-    virtual int reply(isc::data::ConstElementPtr, isc::data::ConstElementPtr) {
-        return (-1);
-    }
-
-    virtual bool hasQueuedMsgs() const {
-        return (false);
-    }
-
-    virtual void setTimeout(size_t) {};
-    virtual size_t getTimeout() const { return 0; };
-
-    // The following methods extent AbstractSession to allow testing:
-    void setMessage(isc::data::ConstElementPtr msg) { msg_ = msg; }
-    void disableSend() { send_ok_ = false; }
-    void disableReceive() { receive_ok_ = false; }
-
-    isc::data::ConstElementPtr getSentMessage() const { return (sent_msg_); }
-    std::string getMessageDest() const { return (msg_dest_); }
-
-    /// \brief Return the value of want_answer parameter of the previous call
-    /// to group_sendmsg().
-    bool wasAnswerWanted() const { return (answer_wanted_); }
-
-private:
-    isc::data::ConstElementPtr sent_msg_;
-    std::string msg_dest_;
-    isc::data::ConstElementPtr msg_;
-    bool send_ok_;
-    bool receive_ok_;
-    bool answer_wanted_;
-};
-
 // This mock object does nothing except for recording passed parameters
 // to addServerXXX methods so the test code subsequently checks the parameters.
 class MockDNSService : public isc::asiodns::DNSServiceBase {

+ 0 - 1
src/lib/testutils/srv_test.h

@@ -93,7 +93,6 @@ protected:
                              const char* const address = DEFAULT_REMOTE_ADDRESS,
                              uint16_t port = DEFAULT_REMOTE_PORT);
 
-    MockSession notify_session;
     MockServer dnsserv;
     isc::dns::Message request_message;
     isc::dns::MessagePtr parse_message;