Browse Source

[2956] Changes to address review comments. Note that the module name is
now b10-dhcp-ddns.

Thomas Markwalder 12 years ago
parent
commit
21f3ea9067

+ 19 - 19
src/bin/d2/Makefile.am

@@ -18,15 +18,15 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
 
 CLEANFILES  = *.gcno *.gcda spec_config.h d2_messages.h d2_messages.cc
 
-man_MANS = b10-d2.8
+man_MANS = b10-dhcp-ddns.8
 DISTCLEANFILES = $(man_MANS)
-EXTRA_DIST = $(man_MANS) b10-d2.xml d2.spec
+EXTRA_DIST = $(man_MANS) b10-dhcp-ddns.xml dhcp-ddns.spec
 
 if GENERATE_DOCS
-b10-d2.8: b10-d2.xml
+b10-dhcp-ddns.8: b10-dhcp-ddns.xml
 	@XSLTPROC@ --novalid --xinclude --nonet -o $@ \
         http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \
-	$(srcdir)/b10-d2.xml
+	$(srcdir)/b10-dchdp-ddns.xml
 
 else
 
@@ -44,23 +44,23 @@ d2_messages.h d2_messages.cc: d2_messages.mes
 
 BUILT_SOURCES = spec_config.h d2_messages.h d2_messages.cc
 
-pkglibexec_PROGRAMS = b10-d2
+pkglibexec_PROGRAMS = b10-dhcp-ddns
 
-b10_d2_SOURCES  = main.cc
-b10_d2_SOURCES += d2_log.cc d2_log.h
-b10_d2_SOURCES += d_process.h
-b10_d2_SOURCES += d2_process.cc d2_process.h
-b10_d2_SOURCES += d_controller.cc d_controller.h
-b10_d2_SOURCES += d2_controller.cc d2_controller.h
+b10_dhcp_ddns_SOURCES  = main.cc
+b10_dhcp_ddns_SOURCES += d2_log.cc d2_log.h
+b10_dhcp_ddns_SOURCES += d_process.h
+b10_dhcp_ddns_SOURCES += d2_process.cc d2_process.h
+b10_dhcp_ddns_SOURCES += d_controller.cc d_controller.h
+b10_dhcp_ddns_SOURCES += d2_controller.cc d2_controller.h
 
-nodist_b10_d2_SOURCES = d2_messages.h d2_messages.cc
+nodist_b10_dhcp_ddns_SOURCES = d2_messages.h d2_messages.cc
 EXTRA_DIST += d2_messages.mes
 
-b10_d2_LDADD = $(top_builddir)/src/lib/log/libb10-log.la
-b10_d2_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
-b10_d2_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
-b10_d2_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
-b10_d2_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+b10_dhcp_ddns_LDADD = $(top_builddir)/src/lib/log/libb10-log.la
+b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
 
-b10_d2dir = $(pkgdatadir)
-b10_d2_DATA = d2.spec
+b10_dhcp_ddnsdir = $(pkgdatadir)
+b10_dhcp_ddns_DATA = dhcp-ddns.spec

+ 7 - 7
src/bin/d2/b10-d2.xml

@@ -24,13 +24,13 @@
   </refentryinfo>
 
   <refmeta>
-    <refentrytitle>b10-d2</refentrytitle>
+    <refentrytitle>b10-dhcp-ddns</refentrytitle>
     <manvolnum>8</manvolnum>
     <refmiscinfo>BIND10</refmiscinfo>
   </refmeta>
 
   <refnamediv>
-    <refname>b10-d2</refname>
+    <refname>b10-dhcp-ddns</refname>
     <refpurpose>D2 process in BIND 10 architecture</refpurpose>
   </refnamediv>
 
@@ -43,14 +43,14 @@
 
   <refsynopsisdiv>
     <cmdsynopsis>
-      <command>b10-d2</command>
+      <command>b10-dhcp-ddns</command>
       <arg><option>-v</option></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
   <refsynopsisdiv>
     <cmdsynopsis>
-      <command>b10-d2</command>
+      <command>b10-dhcp-ddns</command>
       <arg><option>-s</option></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
@@ -59,7 +59,7 @@
   <refsect1>
     <title>DESCRIPTION</title>
     <para>
-      The <command>b10-d2</command> daemon processes requests to
+      The <command>b10-dhcp-ddns</command> daemon processes requests to
       to update DNS mapping based on DHCP lease change events.
     </para>
 
@@ -95,7 +95,7 @@
     <title>SEE ALSO</title>
     <para>
       <citerefentry>
-        <refentrytitle>b10-d2</refentrytitle><manvolnum>8</manvolnum>
+        <refentrytitle>b10-dhcp-ddns</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
@@ -106,7 +106,7 @@
   <refsect1>
     <title>HISTORY</title>
     <para>
-      The <command>b10-d2</command> process was first coded in
+      The <command>b10-dhcp-ddns</command> process was first coded in
       May 2013 by the ISC Kea/Dhcp team.
     </para>
   </refsect1>

+ 4 - 3
src/bin/d2/d2_controller.cc

@@ -23,10 +23,11 @@ DControllerBasePtr&
 D2Controller::instance() {
     // If the instance hasn't been created yet, create it.  Note this method
     // must use the base class singleton instance methods.  The base class
-    // must own the singleton in order to use it within BIND10 static function
-    // callbacks.
+    // must have access to the singleton in order to use it within BIND10 
+    // static function callbacks.
     if (!getController()) {
-        setController(new D2Controller());
+        DControllerBasePtr controller_ptr(new D2Controller());
+        setController(controller_ptr);
     }
 
     return (getController());

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

@@ -21,7 +21,7 @@ namespace d2 {
 
 /// @brief Defines the service name which is used in the controller constructor
 /// and ultimately defines the BIND10 module name.
-const char* const D2_MODULE_NAME = "b10-d2";
+const char* const D2_MODULE_NAME = "b10-dhpc-ddns";
 
 /// @brief Defines the logger used within D2.
 isc::log::Logger d2_logger(D2_MODULE_NAME);

+ 7 - 5
src/bin/d2/d2_messages.mes

@@ -27,11 +27,11 @@ This is a debug message issued when the service process has been instructed
 to shut down by the controller.
 
 % D2PRC_PROCESS_INIT DHCP-DDNS application init invoked
-This is a debug message issued when the D2 process enters it's
+This is a debug message issued when the D2 process enters its
 init method. 
 
 % D2PRC_RUN_ENTER process has entered the event loop 
-This is a debug message issued when the D2 process enters it's
+This is a debug message issued when the D2 process enters its
 run method. 
 
 % D2PRC_RUN_EXIT process is exiting the event loop
@@ -52,15 +52,17 @@ has been invoked.
 
 % D2CTL_INIT_PROCESS initializing application proces 
 This debug message is issued just before the controller attempts
-to create and initialize it's process instance.
+to create and initialize its process instance.
 
 % D2CTL_SESSION_FAIL failed to establish BIND 10 session: %1
 The controller has failed to establish communication with the rest of BIND
 10 and will exit. 
 
 % D2CTL_DISCONNECT_FAIL failed to disconnect from BIND 10 session: %1
-The controller has failed to terminate communication with the rest of BIND
-10. 
+This message indicates that while shutting down, the DHCP-DDNS controller 
+encountered an error terminating communication with the BIND10. The service 
+will still exit.  While theoretically possible, this situation is rather 
+unlikely. 
 
 % D2CTL_STANDALONE skipping message queue, running standalone
 This is a debug message indicating that the controller is running in the

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

@@ -45,7 +45,7 @@ D2Process::run() {
         } catch (const std::exception& ex) {
             LOG_FATAL(d2_logger, D2PRC_FAILED).arg(ex.what());
             isc_throw (DProcessBaseError,
-                std::string("Process run method failed:") + ex.what());
+                       "Process run method failed:" << ex.what());
         }
     }
 

+ 27 - 44
src/bin/d2/d_controller.cc

@@ -32,7 +32,7 @@ DControllerBase::DControllerBase(const char* name)
 }
 
 void
-DControllerBase::setController(DControllerBase* controller) {
+DControllerBase::setController(const DControllerBasePtr& controller) {
     if (controller_) {
         // This shouldn't happen, but let's make sure it can't be done.
         // It represents a programmatic error.
@@ -40,41 +40,34 @@ DControllerBase::setController(DControllerBase* controller) {
                 "Multiple controller instances attempted.");
     }
 
-    controller_ = DControllerBasePtr(controller);
+    controller_ = controller;
 }
 
-int
+void
 DControllerBase::launch(int argc, char* argv[]) {
-    int ret = d2::NORMAL_EXIT;
-
     // Step 1 is to parse the command line arguments.
     try {
         parseArgs(argc, argv);
     } catch (const InvalidUsage& ex) {
         usage(ex.what());
-        return (d2::INVALID_USAGE);
+        throw; // rethrow it
     }
 
-#if 1
-    //@TODO During initial development default to max log, no buffer
-    isc::log::initLogger(name_, isc::log::DEBUG,
-                         isc::log::MAX_DEBUG_LEVEL, NULL, false);
-#else
     // Now that we know what the mode flags are, we can init logging.
     // If standalone is enabled, do not buffer initial log messages
     isc::log::initLogger(name_,
                          ((verbose_ && stand_alone_)
                           ? isc::log::DEBUG : isc::log::INFO),
                          isc::log::MAX_DEBUG_LEVEL, NULL, !stand_alone_);
-#endif
 
     LOG_DEBUG(d2_logger, DBGLVL_START_SHUT, D2CTL_STARTING).arg(getpid());
     try {
-        // Step 2 is to create and initialize the application process.
+        // Step 2 is to create and initialize the application process object.
         initProcess();
     } catch (const std::exception& ex) {
-        LOG_ERROR(d2_logger, D2CTL_SESSION_FAIL).arg(ex.what());
-        return (PROCESS_INIT_ERROR);
+        LOG_FATAL(d2_logger, D2CTL_INIT_PROCESS).arg(ex.what());
+        isc_throw (ProcessInitError, 
+                   "Application Process initialization failed:" << ex.what());
     }
 
     // Next we connect if we are running integrated.
@@ -84,8 +77,9 @@ DControllerBase::launch(int argc, char* argv[]) {
         try {
             establishSession();
         } catch (const std::exception& ex) {
-            LOG_ERROR(d2_logger, D2CTL_SESSION_FAIL).arg(ex.what());
-            return (d2::SESSION_START_ERROR);
+            LOG_FATAL(d2_logger, D2CTL_SESSION_FAIL).arg(ex.what());
+            isc_throw (SessionStartError, 
+                       "Session start up failed:" << ex.what());
         }
     }
 
@@ -95,24 +89,25 @@ DControllerBase::launch(int argc, char* argv[]) {
         runProcess();
     } catch (const std::exception& ex) {
         LOG_FATAL(d2_logger, D2CTL_FAILED).arg(ex.what());
-        ret = d2::RUN_ERROR;
+        isc_throw (ProcessRunError, 
+                   "Application process event loop failed:" << ex.what());
     }
 
-    // If running integrated, always try to disconnect.
+    // If running integrated, disconnect.
     if (!stand_alone_) {
         try {
             disconnectSession();
         } catch (const std::exception& ex) {
             LOG_ERROR(d2_logger, D2CTL_DISCONNECT_FAIL).arg(ex.what());
-            ret = d2::SESSION_END_ERROR;
+            isc_throw (SessionEndError, "Session end failed:" << ex.what());
         }
     }
 
     // All done, so bail out.
     LOG_INFO(d2_logger, D2CTL_STOPPING);
-    return (ret);
 }
 
+
 void
 DControllerBase::parseArgs(int argc, char* argv[])
 {
@@ -137,11 +132,10 @@ DControllerBase::parseArgs(int argc, char* argv[])
 
         case '?': {
             // We hit an invalid option.
-            std::stringstream tmp;
-            tmp << " unsupported option: [" << (char)optopt << "] "
-                << (!optarg ? "" : optarg);
+            isc_throw(InvalidUsage, "unsupported option: [" 
+                      << static_cast<char>(optopt) << "] "
+                      << (!optarg ? "" : optarg));
 
-            isc_throw(InvalidUsage,tmp.str());
             break;
             }
 
@@ -149,10 +143,9 @@ DControllerBase::parseArgs(int argc, char* argv[])
             // We hit a valid custom option
             if (!customOption(ch, optarg)) {
                 // This would be a programmatic error.
-                std::stringstream tmp;
-                tmp << " Option listed but implemented?: [" <<
-                        (char)ch << "] " << (!optarg ? "" : optarg);
-                isc_throw(InvalidUsage,tmp.str());
+                isc_throw(InvalidUsage, " Option listed but implemented?: [" 
+                          << static_cast<char>(ch) << "] "
+                          << (!optarg ? "" : optarg));
             }
             break;
         }
@@ -160,9 +153,7 @@ DControllerBase::parseArgs(int argc, char* argv[])
 
     // There was too much information on the command line.
     if (argc > optind) {
-        std::stringstream tmp;
-        tmp << "extraneous command line information";
-        isc_throw(InvalidUsage,tmp.str());
+        isc_throw(InvalidUsage, "extraneous command line information");
     }
 }
 
@@ -181,13 +172,13 @@ DControllerBase::initProcess() {
     try {
         process_.reset(createProcess());
     } catch (const std::exception& ex) {
-        isc_throw (DControllerBaseError, std::string("createProcess failed:")
-                    + ex.what());
+        isc_throw(DControllerBaseError, std::string("createProcess failed:")
+                  + ex.what());
     }
 
     // This is pretty unlikely, but will test for it just to be safe..
     if (!process_) {
-        isc_throw (DControllerBaseError, "createProcess returned NULL");
+        isc_throw(DControllerBaseError, "createProcess returned NULL");
     }
 
     // Invoke application's init method (Note this call should throw
@@ -300,7 +291,7 @@ DControllerBase::configHandler(isc::data::ConstElementPtr new_config) {
 // Static callback which invokes non-static handler on singleton
 isc::data::ConstElementPtr
 DControllerBase::commandHandler(const std::string& command,
-                            isc::data::ConstElementPtr args) {
+                                isc::data::ConstElementPtr args) {
 
     LOG_DEBUG(d2_logger, DBGLVL_COMMAND, D2CTL_COMMAND_RECEIVED)
               .arg(command).arg(args->str());
@@ -403,14 +394,6 @@ DControllerBase::customControllerCommand(const std::string& command,
 
 isc::data::ConstElementPtr
 DControllerBase::shutdown() {
-    // @TODO (tmark) - not sure about io_service_->stop here
-    // IF application is using this service for all of its IO, stopping
-    // here would mean, no more work by the application.. UNLESS it resets
-    // it. People have discussed letting the application finish any in-progress
-    // updates before shutting down.  If we don't stop it here, then
-    // application can't use io_service_->run(), it will never "see" the
-    // shutdown.
-    io_service_->stop();
     if (process_) {
         process_->shutdown();
     } else {

+ 68 - 41
src/bin/d2/d_controller.h

@@ -35,19 +35,6 @@ namespace d2 {
 /// normal or otherwise, the Controller's launch method will return one of
 /// these values.
 
-/// @brief Indicates normal shutdown.
-static const int NORMAL_EXIT = 0;
-/// @brief Indicates invalid command line.
-static const int INVALID_USAGE = 1;
-/// @brief Failed to create and initialize application process.
-static const int PROCESS_INIT_ERROR = 2;
-/// @brief Could not connect to BIND10 (integrated mode only).
-static const int SESSION_START_ERROR = 3;
-/// @brief A fatal error occurred in the application process.
-static const int RUN_ERROR = 4;
-/// @brief Error occurred disconnecting from BIND10 (integrated mode only).
-static const int SESSION_END_ERROR = 5;
-
 /// @brief Exception thrown when the command line is invalid.
 class InvalidUsage : public isc::Exception {
 public:
@@ -55,6 +42,36 @@ public:
         isc::Exception(file, line, what) { };
 };
 
+/// @brief Exception thrown when the application process fails.
+class ProcessInitError: public isc::Exception {
+public:
+    ProcessInitError (const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when the session start up fails.
+class SessionStartError: public isc::Exception {
+public:
+    SessionStartError (const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when the application process encounters an 
+/// operation in its event loop (i.e. run method).
+class ProcessRunError: public isc::Exception {
+public:
+    ProcessRunError (const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when the session end fails.
+class SessionEndError: public isc::Exception {
+public:
+    SessionEndError (const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+
 /// @brief Exception thrown when the controller encounters an operational error.
 class DControllerBaseError : public isc::Exception {
 public:
@@ -82,15 +99,24 @@ typedef boost::shared_ptr<isc::config::ModuleCCSession> ModuleCCSessionPtr;
 /// integrated mode as a BIND10 module or stand-alone. It coordinates command
 /// line argument parsing, process instantiation and initialization, and runtime
 /// control through external command and configuration event handling.
-/// It creates the io_service_ instance which is used for runtime control
-/// events and passes the io_service into the application process at process
+/// It creates the IOService instance which is used for runtime control
+/// events and passes the IOService into the application process at process
 /// creation.  In integrated mode it is responsible for establishing BIND10
-/// session(s) and passes this io_service_ into the session creation method(s).
-/// It also provides the callback handlers for command and configuration events.
+/// session(s) and passes this IOService into the session creation method(s).
+/// It also provides the callback handlers for command and configuration events
+/// received from the external framework (aka BIND10).  For example, when 
+/// running in integrated mode and a user alters the configuration with the
+/// bindctl tool, BIND10 will emit a configuration message which is sensed by
+/// the controller's IOService. The IOService in turn invokes the configuration
+/// callback, DControllerBase::configHandler().  If the user issues a command
+/// such as shutdown via bindctl,  BIND10 will emit a command message, which is
+/// sensed by controller's IOService which invokes the command callback, 
+/// DControllerBase::commandHandler().
+///
 /// NOTE: Derivations must supply their own static singleton instance method(s)
 /// for creating and fetching the instance. The base class declares the instance
 /// member in order for it to be available for BIND10 callback functions. This
-/// would not be required if BIND10 supported instance method callbacks.
+/// would not be required if BIND10 supported instance method callbacks.   
 class DControllerBase : public boost::noncopyable {
 public:
     /// @brief Constructor
@@ -119,16 +145,16 @@ public:
     /// @param argc  is the number of command line arguments supplied
     /// @param argv  is the array of string (char *) command line arguments
     ///
-    /// @return returns one of the following integer values:
-    /// d2::NORMAL_EXIT - Indicates normal shutdown.
-    /// d2::INVALID_USAGE - Indicates invalid command line.
-    /// d2::PROCESS_INIT_ERROR  - Failed to create and initialize application
-    /// process
-    /// d2::SESSION_START_ERROR  - Could not connect to BIND10 (integrated mode
+    /// @throw throws one of the following exceptions:
+    /// InvalidUsage - Indicates invalid command line.
+    /// ProcessInitError  - Failed to create and initialize application
+    /// process object.
+    /// SessionStartError  - Could not connect to BIND10 (integrated mode only).
+    /// ProcessRunError - A fatal error occurred while in the application 
+    /// process event loop.
+    /// SessionEndError - Could not disconnect from BIND10 (integrated mode 
     /// only).
-    /// d2::RUN_ERROR - An fatal error occurred in the application process
-    /// d2::SESSION_END_ERROR = 4;
-    int launch(int argc, char* argv[]);
+    void launch(int argc, char* argv[]);
 
     /// @brief A dummy configuration handler that always returns success.
     ///
@@ -240,11 +266,11 @@ protected:
     virtual bool customOption(int option, char *optarg);
 
     /// @brief Abstract method that is responsible for instantiating the
-    /// application process instance. It is invoked by the controller after
+    /// application process object. It is invoked by the controller after
     /// command line argument parsing as part of the process initialization
     /// (see initProcess method).
     ///
-    /// @return returns a pointer to the new process instance (DProcessBase*)
+    /// @return returns a pointer to the new process object (DProcessBase*)
     /// or NULL if the create fails.
     /// Note this value is subsequently wrapped in a smart pointer.
     virtual DProcessBase* createProcess() = 0;
@@ -294,7 +320,7 @@ protected:
     /// invalid usage conditions.
     ///
     /// @return returns the desired text.
-    virtual const std::string getUsageText() {
+    virtual const std::string getUsageText() const {
         return ("");
     }
 
@@ -304,21 +330,21 @@ protected:
     /// line interpretation.
     ///
     /// @return returns a string containing the custom option letters.
-    virtual const std::string getCustomOpts() {
+    virtual const std::string getCustomOpts() const {
         return ("");
     }
 
     /// @brief Supplies the controller name.
     ///
     /// @return returns the controller name string
-    const std::string& getName() {
+    const std::string getName() const {
         return (name_);
     }
 
     /// @brief Supplies whether or not the controller is in stand alone mode.
     ///
     /// @return returns true if in stand alone mode, false otherwise
-    bool isStandAlone() {
+    const bool isStandAlone() const {
         return (stand_alone_);
     }
 
@@ -332,7 +358,7 @@ protected:
     /// @brief Supplies whether or not verbose logging is enabled.
     ///
     /// @return returns true if verbose logging is enabled.
-    bool isVerbose() {
+    const bool isVerbose() const {
         return (verbose_);
     }
 
@@ -354,7 +380,7 @@ protected:
     /// file.
     ///
     /// @return returns the file name string.
-    const std::string& getSpecFileName() {
+    const std::string getSpecFileName() const {
         return (spec_file_name_);
     }
 
@@ -373,13 +399,13 @@ protected:
         return (controller_);
     }
 
-    /// @brief Static setter which returns the singleton instance.
+    /// @brief Static setter which sets the singleton instance.
+    ///
+    /// @param controller is a pointer to the singleton instance.
     ///
-    /// @return returns a pointer reference to the private singleton instance
-    /// member.
     /// @throw throws DControllerBase error if an attempt is made to set the
     /// instance a second time.
-    static void setController(DControllerBase* controller);
+    static void setController(const DControllerBasePtr& controller);
 
 private:
     /// @brief Processes the command line arguments. It is the first step
@@ -452,7 +478,7 @@ private:
     ///
     /// @param text is a string message which will preceded the usage text.
     /// This is intended to be used for specific usage violation messages.
-    void usage(const std::string & text);
+    void usage(const std::string& text);
 
 private:
     /// @brief Text label for the controller. Typically this would be the
@@ -462,9 +488,10 @@ private:
     /// @brief Indicates if the controller stand alone mode is enabled. When
     /// enabled, the controller will not establish connectivity with BIND10.
     bool stand_alone_;
-    /// @brief Indicates if the verbose logging mode is enabled.
 
+    /// @brief Indicates if the verbose logging mode is enabled.
     bool verbose_;
+
     /// @brief The absolute file name of the BIND10 spec file.
     std::string spec_file_name_;
 

+ 18 - 6
src/bin/d2/d_process.h

@@ -72,20 +72,24 @@ public:
     /// to application. It must be invoked prior to invoking run. This would
     /// likely include the creation of additional IO sources and their
     /// integration into the io_service.
-    /// @throw throws a DProcessBaseError if the initialization fails.
+    /// @throw throws DProcessBaseError if the initialization fails.
     virtual void init() = 0;
 
     /// @brief Implements the process's event loop. In its simplest form it
     /// would an invocation io_service_->run().  This method should not exit
     /// until the process itself is exiting due to a request to shutdown or
     /// some anomaly is forcing an exit.
-    /// @throw throws a DProcessBaseError if an operational error is encountered.
+    /// @throw throws DProcessBaseError if an operational error is encountered.
     virtual void run() = 0;
 
     /// @brief Implements the process's shutdown processing. When invoked, it
     /// should ensure that the process gracefully exits the run method.
-    /// @throw throws a DProcessBaseError if an operational error is encountered.
-    virtual void shutdown() = 0;
+    /// The default implementation sets the shutdown flag and stops IOService.
+    /// @throw throws DProcessBaseError if an operational error is encountered.
+    virtual void shutdown() {
+        setShutdownFlag(true);
+        stopIOService();
+    };
 
     /// @brief Processes the given configuration.
     ///
@@ -123,7 +127,7 @@ public:
     /// @brief Checks if the process has been instructed to shut down.
     ///
     /// @return returns true if process shutdown flag is true.
-    bool shouldShutdown() {
+    const bool shouldShutdown() const {
         return (shut_down_flag_);
     }
 
@@ -137,7 +141,7 @@ public:
     /// @brief Fetches the name of the controller.
     ///
     /// @return returns a reference the controller's name string.
-    const std::string& getName() const {
+    const std::string getName() const {
         return (name_);
     }
 
@@ -148,6 +152,14 @@ public:
         return (io_service_);
     }
 
+    /// @brief Convenience method for stopping IOservice processing.
+    /// Invoking this will cause the process to exit any blocking 
+    /// IOService method such as run().  No further IO events will be
+    /// processed.
+    void stopIOService() {
+        io_service_->stop();
+    }
+
 private:
     /// @brief Text label for the process. Generally used in log statements,
     /// but otherwise can be arbitrary.

+ 1 - 1
src/bin/d2/d2.spec

@@ -7,7 +7,7 @@
     "commands": [
       {
         "command_name": "shutdown",
-        "command_description": "Shut down the stats httpd",
+        "command_description": "Shut down the DHCP-DDNS service",
         "command_args": [
           {
             "item_name": "pid",

+ 13 - 13
src/bin/d2/main.cc

@@ -15,6 +15,7 @@
 #include <config.h>
 #include <d2/d2_log.h>
 #include <d2/d2_controller.h>
+#include <exceptions/exceptions.h>
 #include <log/logger_support.h>
 #include <log/logger_manager.h>
 
@@ -26,23 +27,22 @@ using namespace std;
 /// This file contains entry point (main() function) for standard DHCP-DDNS
 /// process, b10-dhcp-ddns, component for BIND10 framework.  It fetches
 /// the D2Controller singleton instance and invokes its launch method.
-/// The exit value of the program will the return value of launch:
-/// d2::NORMAL_EXIT - Indicates normal shutdown.
-/// d2::INVALID_USAGE - Indicates invalid command line.
-/// d2::PROCESS_INIT_ERROR  - Failed to create and initialize application
-/// process
-/// d2::SESSION_START_ERROR  - Could not connect to BIND10 (integrated mode
-/// only).
-/// d2::RUN_ERROR - A fatal error occurred in the application process
-/// d2::SESSION_END_ERROR - Error occurred disconnecting from BIND10 (integrated
-/// mode only).
-int
-main(int argc, char* argv[]) {
+/// The exit value of the program will be EXIT_SUCCESS if there were no
+/// errors, EXIT_FAILURE otherwise.
+int main(int argc, char* argv[]) {
+    int ret = EXIT_SUCCESS;
 
     // Instantiate/fetch the DHCP-DDNS application controller singleton.
     DControllerBasePtr& controller = D2Controller::instance();
 
     // Launch the controller passing in command line arguments.
     // Exit program with the controller's return code.
-    return (controller->launch(argc, argv));
+    try  {
+        controller->launch(argc, argv);
+    } catch (const isc::Exception& ex) {
+        std::cerr << "Service failed:" << ex.what() << std::endl;
+        ret = EXIT_FAILURE;
+    }
+
+    return (ret);
 }

+ 10 - 9
src/bin/d2/tests/d2_controller_unittests.cc

@@ -81,7 +81,9 @@ TEST_F(D2ControllerTest, basicInstanceTesting) {
 /// 1. Standard command line options are supported.
 /// 2. Invalid options are detected.
 TEST_F(D2ControllerTest, commandLineArgs) {
-    char* argv[] = { (char*)"progName", (char*)"-s", (char*)"-v" };
+    char* argv[] = { const_cast<char*>("progName"), 
+                     const_cast<char*>("-s"), 
+                     const_cast<char*>("-v") };
     int argc = 3;
 
     // Verify that both flags are false initially.
@@ -96,9 +98,10 @@ TEST_F(D2ControllerTest, commandLineArgs) {
     EXPECT_TRUE(checkVerbose(true));
 
     // Verify that an unknown option is detected.
-    char* argv2[] = { (char*)"progName", (char*)"-x" };
+    char* argv2[] = { const_cast<char*>("progName"), 
+                      const_cast<char*>("-x") };
     argc = 2;
-    EXPECT_THROW (parseArgs(argc, argv2), InvalidUsage);
+    EXPECT_THROW(parseArgs(argc, argv2), InvalidUsage);
 }
 
 /// @brief Tests application process creation and initialization.
@@ -111,10 +114,11 @@ TEST_F(D2ControllerTest, initProcessTesting) {
 /// @brief Tests launch and normal shutdown (stand alone mode).
 /// This creates an interval timer to generate a normal shutdown and then
 /// launches with a valid, stand-alone command line and no simulated errors.
-/// Launch exit code should be d2::NORMAL_EXIT.
 TEST_F(D2ControllerTest, launchNormalShutdown) {
     // command line to run standalone
-    char* argv[] = { (char*)"progName", (char*)"-s", (char*)"-v" };
+    char* argv[] = { const_cast<char*>("progName"), 
+                     const_cast<char*>("-s"), 
+                     const_cast<char*>("-v") };
     int argc = 3;
 
     // Use an asiolink IntervalTimer and callback to generate the
@@ -124,14 +128,11 @@ TEST_F(D2ControllerTest, launchNormalShutdown) {
 
     // Record start time, and invoke launch().
     ptime start = microsec_clock::universal_time();
-    int rcode = launch(argc, argv);
+    EXPECT_NO_THROW(launch(argc, argv));
 
     // Record stop time.
     ptime stop = microsec_clock::universal_time();
 
-    // Verify normal shutdown status.
-    EXPECT_EQ(d2::NORMAL_EXIT, rcode);
-
     // Verify that duration of the run invocation is the same as the
     // timer duration.  This demonstrates that the shutdown was driven
     // by an io_service event and callback.

+ 2 - 1
src/bin/d2/tests/d2_test.py

@@ -159,7 +159,8 @@ class TestD2Daemon(unittest.TestCase):
         print("Note: Simple test to verify that D2 server can be started.")
         # note that "-s" for stand alone is necessary in order to flush the log output
         # soon enough to catch it.
-        (returncode, output, error) = self.runCommand(["../b10-d2", "-s", "-v"])
+        (returncode, output, error) = self.runCommand(["../b10-dhcp-ddns", 
+                                                       "-s", "-v"])
         output_text = str(output) + str(error)
         self.assertEqual(output_text.count("D2CTL_STARTING"), 1)
 

+ 33 - 40
src/bin/d2/tests/d_controller_unittests.cc

@@ -78,7 +78,9 @@ TEST_F(DStubControllerTest, commandLineArgs) {
     EXPECT_TRUE(checkVerbose(false));
 
     // Verify that standard options can be parsed without error.
-    char* argv[] = { (char*)"progName", (char*)"-s", (char*)"-v" };
+    char* argv[] = { const_cast<char*>("progName"),
+                     const_cast<char*>("-s"),
+                     const_cast<char*>("-v") };
     int argc = 3;
     EXPECT_NO_THROW(parseArgs(argc, argv));
 
@@ -87,23 +89,24 @@ TEST_F(DStubControllerTest, commandLineArgs) {
     EXPECT_TRUE(checkVerbose(true));
 
     // Verify that the custom command line option is parsed without error.
-    char xopt[3]="";
-    sprintf (xopt, "-%c", *DStubController::stub_option_x_);
-    char* argv1[] = { (char*)"progName", xopt};
+    char xopt[3] = "- ";
+    xopt[1] =  *DStubController::stub_option_x_;
+    char* argv1[] = { const_cast<char*>("progName"), xopt};
     argc = 2;
     EXPECT_NO_THROW (parseArgs(argc, argv1));
 
     // Verify that an unknown option is detected.
-    char* argv2[] = { (char*)"progName", (char*)"-bs" };
+    char* argv2[] = { const_cast<char*>("progName"),
+                      const_cast<char*>("-bs") };
     argc = 2;
     EXPECT_THROW (parseArgs(argc, argv2), InvalidUsage);
 
     // Verify that extraneous information is detected.
-    char* argv3[] = { (char*)"progName", (char*)"extra", (char*)"information" };
+    char* argv3[] = { const_cast<char*>("progName"),
+                      const_cast<char*>("extra"),
+                      const_cast<char*>("information") };
     argc = 3;
     EXPECT_THROW (parseArgs(argc, argv3), InvalidUsage);
-
-
 }
 
 /// @brief Tests application process creation and initialization.
@@ -141,44 +144,42 @@ TEST_F(DStubControllerTest, initProcessTesting) {
 }
 
 /// @brief Tests launch handling of invalid command line.
-/// This test launches with an invalid command line which should exit with
-/// an status of d2::INVALID_USAGE.
+/// This test launches with an invalid command line which should throw
+/// an InvalidUsage.
 TEST_F(DStubControllerTest, launchInvalidUsage) {
     // Command line to run integrated
-    char* argv[] = { (char*)"progName",(char*) "-z" };
+    char* argv[] = { const_cast<char*>("progName"),
+                     const_cast<char*>("-z") };
     int argc = 2;
 
     // Launch the controller in integrated mode.
-    int rcode = launch(argc, argv);
-
-    // Verify session failure exit status.
-    EXPECT_EQ(d2::INVALID_USAGE, rcode);
+    EXPECT_THROW(launch(argc, argv), InvalidUsage);
 }
 
 /// @brief Tests launch handling of failure in application process
 /// initialization.  This test launches with a valid command line but with
-/// SimFailure set to fail during process creation.  Launch exit code should
-/// be d2::PROCESS_INIT_ERROR.
+/// SimFailure set to fail during process creation.  Launch should throw
+/// ProcessInitError.
 TEST_F(DStubControllerTest, launchProcessInitError) {
     // Command line to run integrated
-    char* argv[] = { (char*)"progName", (char*)"-s", (char*)"-v" };
+    char* argv[] = { const_cast<char*>("progName"),
+                     const_cast<char*>("-s"),
+                     const_cast<char*>("-v") };
     int argc = 3;
 
     // Launch the controller in stand alone mode.
     SimFailure::set(SimFailure::ftCreateProcessException);
-    int rcode = launch(argc, argv);
-
-    // Verify session failure exit status.
-    EXPECT_EQ(d2::PROCESS_INIT_ERROR, rcode);
+    EXPECT_THROW(launch(argc, argv), ProcessInitError);
 }
 
 /// @brief Tests launch and normal shutdown (stand alone mode).
 /// This creates an interval timer to generate a normal shutdown and then
 /// launches with a valid, stand-alone command line and no simulated errors.
-/// Launch exit code should be d2::NORMAL_EXIT.
 TEST_F(DStubControllerTest, launchNormalShutdown) {
     // command line to run standalone
-    char* argv[] = { (char*)"progName", (char*)"-s", (char*)"-v" };
+    char* argv[] = { const_cast<char*>("progName"),
+                     const_cast<char*>("-s"),
+                     const_cast<char*>("-v") };
     int argc = 3;
 
     // Use an asiolink IntervalTimer and callback to generate the
@@ -188,14 +189,11 @@ TEST_F(DStubControllerTest, launchNormalShutdown) {
 
     // Record start time, and invoke launch().
     ptime start = microsec_clock::universal_time();
-    int rcode = launch(argc, argv);
+    EXPECT_NO_THROW(launch(argc, argv));
 
     // Record stop time.
     ptime stop = microsec_clock::universal_time();
 
-    // Verify normal shutdown status.
-    EXPECT_EQ(d2::NORMAL_EXIT, rcode);
-
     // Verify that duration of the run invocation is the same as the
     // timer duration.  This demonstrates that the shutdown was driven
     // by an io_service event and callback.
@@ -207,10 +205,12 @@ TEST_F(DStubControllerTest, launchNormalShutdown) {
 /// @brief Tests launch with an operational error during application execution.
 /// This test creates an interval timer to generate a runtime exception during
 /// the process event loop. It launches wih a valid, stand-alone command line
-/// and no simulated errors.  Launch exit code should be d2::RUN_ERROR.
+/// and no simulated errors.  Launch should throw ProcessRunError.
 TEST_F(DStubControllerTest, launchRuntimeError) {
     // command line to run standalone
-    char* argv[] = { (char*)"progName", (char*)"-s", (char*)"-v" };
+    char* argv[] = { const_cast<char*>("progName"),
+                     const_cast<char*>("-s"),
+                     const_cast<char*>("-v") };
     int argc = 3;
 
     // Use an asiolink IntervalTimer and callback to generate the
@@ -220,14 +220,11 @@ TEST_F(DStubControllerTest, launchRuntimeError) {
 
     // Record start time, and invoke launch().
     ptime start = microsec_clock::universal_time();
-    int rcode = launch(argc, argv);
+    EXPECT_THROW(launch(argc, argv), ProcessRunError);
 
     // Record stop time.
     ptime stop = microsec_clock::universal_time();
 
-    // Verify abnormal shutdown status.
-    EXPECT_EQ(d2::RUN_ERROR, rcode);
-
     // Verify that duration of the run invocation is the same as the
     // timer duration.  This demonstrates that the shutdown was driven
     // by an io_service event and callback.
@@ -239,18 +236,14 @@ TEST_F(DStubControllerTest, launchRuntimeError) {
 /// @brief Tests launch with a session establishment failure.
 /// This test launches with a valid command line for integrated mode and no.
 /// Attempting to connect to BIND10 should fail, even if BIND10 is running
-/// UNLESS the test is run as root.  Launch exit code should be
-/// d2::SESSION_START_ERROR.
+/// UNLESS the test is run as root.  Launch should throw SessionStartError.
 TEST_F(DStubControllerTest, launchSessionFailure) {
     // Command line to run integrated
     char* argv[] = { (char*)"progName" };
     int argc = 1;
 
     // Launch the controller in integrated mode.
-    int rcode = launch(argc, argv);
-
-    // Verify session failure exit status.
-    EXPECT_EQ(d2::SESSION_START_ERROR, rcode);
+    EXPECT_THROW(launch(argc, argv), SessionStartError);
 }
 
 /// @brief Configuration update event testing.

+ 10 - 6
src/bin/d2/tests/d_test_stubs.cc

@@ -12,6 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <d2/d2_log.h>
 #include <d2/spec_config.h>
 #include <d2/tests/d_test_stubs.h>
 
@@ -24,7 +25,7 @@ namespace d2 {
 SimFailure::FailureType SimFailure::failure_type_ = SimFailure::ftNoFailure;
 
 // Define custom process command supported by DStubProcess.
-const std::string DStubProcess::stub_proc_command_("cool_proc_cmd");
+const char*  DStubProcess::stub_proc_command_("cool_proc_cmd");
 
 DStubProcess::DStubProcess(const char* name, IOServicePtr io_service)
     : DProcessBase(name, io_service) {
@@ -69,7 +70,8 @@ DStubProcess::shutdown() {
         // Simulates a failure during shutdown process.
         isc_throw(DProcessBaseError, "DStubProcess simulated shutdown failure");
     }
-    setShutdownFlag(true);
+
+    DProcessBase::shutdown();
 }
 
 isc::data::ConstElementPtr
@@ -113,7 +115,7 @@ DStubProcess::~DStubProcess() {
 //************************** DStubController *************************
 
 // Define custom controller command supported by DStubController.
-const std::string DStubController::stub_ctl_command_("spiffy");
+const char* DStubController::stub_ctl_command_("spiffy");
 
 // Define custom command line option command supported by DStubController.
 const char* DStubController::stub_option_x_ = "x";
@@ -122,7 +124,9 @@ DControllerBasePtr&
 DStubController::instance() {
     // If the singleton hasn't been created, do it now.
     if (!getController()) {
-        setController(new DStubController());
+        //setController(new DStubController());
+        DControllerBasePtr p(new DStubController());
+        setController(p);
     }
 
     return (getController());
@@ -143,7 +147,7 @@ bool
 DStubController::customOption(int option, char* /* optarg */)
 {
     // Check for the custom option supported by DStubController.
-    if ((char)(option) == *stub_option_x_) {
+    if (static_cast<char>(option) == *stub_option_x_) {
         return (true);
     }
 
@@ -183,7 +187,7 @@ DStubController::customControllerCommand(const std::string& command,
     return (answer);
 }
 
-const std::string DStubController::getCustomOpts(){
+const std::string DStubController::getCustomOpts() const {
     // Return the "list" of custom options supported by DStubController.
     return (std::string(stub_option_x_));
 }

+ 5 - 5
src/bin/d2/tests/d_test_stubs.h

@@ -96,7 +96,7 @@ class DStubProcess : public DProcessBase {
 public:
 
     /// @brief Static constant that defines a custom process command string.
-    static const std::string stub_proc_command_;
+    static const char* stub_proc_command_;
 
     /// @brief Constructor
     ///
@@ -184,7 +184,7 @@ public:
 
     /// @brief Defines a custom controller command string. This is a
     /// custom command supported by DStubController.
-    static const std::string stub_ctl_command_;
+    static const char* stub_ctl_command_;
 
     /// @brief Defines a custom command line option supported by
     /// DStubController.
@@ -234,7 +234,7 @@ protected:
     /// addition option, stub_option_x_.
     ///
     /// @return returns a string containing the option letters.
-    virtual const std::string getCustomOpts();
+    virtual const std::string getCustomOpts() const;
 
 private:
     /// @brief Constructor is private to protect singleton integrity.
@@ -378,9 +378,9 @@ public:
 
     /// @Wrapper to invoke the Controller's launch method.  Please refer to
     /// DControllerBase::launch for details.
-    int launch(int argc, char* argv[]) {
+    void launch(int argc, char* argv[]) {
         optind = 1;
-        return (getController()->launch(argc, argv));
+        getController()->launch(argc, argv);
     }
 
     /// @Wrapper to invoke the Controller's disconnectSession method.  Please