Browse Source

[3399] Missign ctrl_dhcp4_srv.cc added.

Tomek Mrugalski 11 years ago
parent
commit
ab26175680
1 changed files with 183 additions and 0 deletions
  1. 183 0
      src/bin/dhcp4/ctrl_dhcp4_srv.cc

+ 183 - 0
src/bin/dhcp4/ctrl_dhcp4_srv.cc

@@ -0,0 +1,183 @@
+// Copyright (C) 2014 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/data.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
+#include <dhcp4/dhcp4_log.h>
+#include <hooks/hooks_manager.h>
+#include <dhcp4/json_config_parser.h>
+
+using namespace isc::data;
+using namespace isc::hooks;
+using namespace std;
+
+namespace isc {
+namespace dhcp {
+
+ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL;
+
+ConstElementPtr
+ControlledDhcpv4Srv::commandShutdownHandler(const string&, ConstElementPtr) {
+    if (ControlledDhcpv4Srv::server_) {
+        ControlledDhcpv4Srv::server_->shutdown();
+    } else {
+        LOG_WARN(dhcp4_logger, DHCP4_NOT_RUNNING);
+        ConstElementPtr answer = isc::config::createAnswer(1,
+                                              "Shutdown failure.");
+        return (answer);
+    }
+    ConstElementPtr answer = isc::config::createAnswer(0, "Shutting down.");
+        return (answer);
+}
+
+ConstElementPtr
+ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
+
+    /// @todo delete any stored CalloutHandles referring to the old libraries
+    /// Get list of currently loaded libraries and reload them.
+    vector<string> loaded = HooksManager::getLibraryNames();
+    bool status = HooksManager::loadLibraries(loaded);
+    if (!status) {
+        LOG_ERROR(dhcp4_logger, DHCP4_HOOKS_LIBS_RELOAD_FAIL);
+        ConstElementPtr answer = isc::config::createAnswer(1,
+                                 "Failed to reload hooks libraries.");
+        return (answer);
+    }
+    ConstElementPtr answer = isc::config::createAnswer(0,
+                             "Hooks libraries successfully reloaded.");
+    return (answer);
+}
+
+ConstElementPtr
+ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
+                                                ConstElementPtr args) {
+    return (processConfig(args));
+}
+
+ConstElementPtr
+ControlledDhcpv4Srv::processCommand(const string& command,
+                                    ConstElementPtr args) {
+    LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_COMMAND_RECEIVED)
+              .arg(command).arg(args->str());
+
+    ControlledDhcpv4Srv* srv = ControlledDhcpv4Srv::getInstance();
+
+    if (!srv) {
+        ConstElementPtr no_srv = isc::config::createAnswer(1,
+          "Server object not initialized, can't process command '" +
+          command + "'.");
+        return (no_srv);
+    }
+
+    try {
+        if (command == "shutdown") {
+            return (srv->commandShutdownHandler(command, args));
+
+        } else if (command == "libreload") {
+            return (srv->commandLibReloadHandler(command, args));
+
+        } else if (command == "config-reload") {
+            return (srv->commandConfigReloadHandler(command, args));
+
+        }
+        ConstElementPtr answer = isc::config::createAnswer(1,
+                                 "Unrecognized command:" + command);
+        return (answer);
+    } catch (const Exception& ex) {
+        return (isc::config::createAnswer(1, "Error while processing command '"
+                                          + command + "':" + ex.what()));
+    }
+}
+
+isc::data::ConstElementPtr
+ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
+    ControlledDhcpv4Srv* srv = ControlledDhcpv4Srv::getInstance();
+
+    if (!srv) {
+        ConstElementPtr no_srv = isc::config::createAnswer(1,
+          "Server object not initialized, can't process config.");
+        return (no_srv);
+    }
+    
+    ConstElementPtr answer = configureDhcp4Server(*srv, config);
+
+    // Check that configuration was successful. If not, do not reopen sockets
+    // and don't bother with DDNS stuff.
+    try {
+        int rcode = 0;
+        isc::config::parseAnswer(rcode, answer);
+        if (rcode != 0) {
+            return (answer);
+        }
+    } catch (const std::exception& ex) {
+        return (isc::config::createAnswer(1, "Failed to process configuration:"
+                                          + string(ex.what())));
+    }
+
+    // Server will start DDNS communications if its enabled.
+    try {
+        srv->startD2();
+    } catch (const std::exception& ex) {
+        std::ostringstream err;
+        err << "error starting DHCP_DDNS client "
+                " after server reconfiguration: " << ex.what();
+        return (isc::config::createAnswer(1, err.str()));
+    }
+
+    // Configuration may change active interfaces. Therefore, we have to reopen
+    // sockets according to new configuration. This operation is not exception
+    // safe and we really don't want to emit exceptions to the callback caller.
+    // Instead, catch an exception and create appropriate answer.
+    try {
+        srv->openActiveSockets(srv->getPort(), server_->useBroadcast());
+    } catch (std::exception& ex) {
+        std::ostringstream err;
+        err << "failed to open sockets after server reconfiguration: " << ex.what();
+        answer = isc::config::createAnswer(1, err.str());
+    }
+    return (answer);
+}
+
+ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/)
+    :Dhcpv4Srv(port) {
+    if (server_) {
+        isc_throw(InvalidOperation,
+                  "There is another Dhcpv4Srv instance already.");
+    }
+    server_ = this; // remember this instance for use in callback
+}
+
+void ControlledDhcpv4Srv::shutdown() {
+    io_service_.stop(); // Stop ASIO transmissions
+    Dhcpv4Srv::shutdown(); // Initiate DHCPv4 shutdown procedure.
+}
+
+ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
+    cleanup();
+    
+    server_ = NULL; // forget this instance. There should be no callback anymore
+                    // at this stage anyway.
+}
+
+void ControlledDhcpv4Srv::sessionReader(void) {
+    // Process one asio event. If there are more events, iface_mgr will call
+    // this callback more than once.
+    if (server_) {
+        server_->io_service_.run_one();
+    }
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace