#include <config/ccsession.h>
#include <dhcp/iface_mgr.h>
#include <dhcpsrv/dhcp_config_parser.h>
+#include <dhcpsrv/cfgmgr.h>
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/spec_config.h>
#include <dhcp4/config_parser.h>
#include <exceptions/exceptions.h>
+#include <boost/bind.hpp>
#include <util/buffer.h>
-#include <cassert>
-#include <iostream>
#include <cassert>
#include <iostream>
+#include <sstream>
using namespace isc::asiolink;
using namespace isc::cc;
}
// Configure the server.
- return (configureDhcp4Server(*server_, merged_config));
+ ConstElementPtr answer = configureDhcp4Server(*server_, merged_config);
+
+ // Check that configuration was successful. If not, do not reopen sockets.
+ int rcode = 0;
+ parseAnswer(rcode, answer);
+ if (rcode != 0) {
+ return (answer);
+ }
+
+ // 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 {
+ server_->openActiveSockets(server_->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);
}
ConstElementPtr
}
}
+void
+ControlledDhcpv4Srv::openActiveSockets(const uint16_t port, const bool use_bcast) {
+ IfaceMgr::instance().closeSockets();
+
+ // Get the reference to the collection of interfaces. This reference should be
+ // valid as long as the program is run because IfaceMgr is a singleton.
+ // Therefore we can safely iterate over instances of all interfaces and modify
+ // their flags. Here we modify flags which indicate wheter socket should be
+ // open for a particular interface or not.
+ IfaceMgr::IfaceCollection ifaces = IfaceMgr::instance().getIfaces();
+ for (IfaceMgr::IfaceCollection::iterator iface = ifaces.begin();
+ iface != ifaces.end(); ++iface) {
+ iface->inactive_ = !CfgMgr::instance().isActiveIface(iface->getName());
+ }
+ // Let's reopen active sockets. openSockets4 will check internally whether
+ // sockets are marked active or inactive.
+ IfaceMgr::instance().openSockets4(port, use_bcast);
+}
+
};
};
/// when there is a new command or configuration sent over msgq.
static void sessionReader(void);
+ /// @brief Open sockets which are marked as active in @c CfgMgr.
+ ///
+ /// This function reopens sockets according to the current settings in the
+ /// Configuration Manager. It holds the list of the interfaces which server
+ /// should listen on. This function will open sockets on these interfaces
+ /// only. This function is not exception safe.
+ ///
+ /// @param port UDP port on which server should listen.
+ /// @param use_bcast should broadcast flags be set on the sockets.
+ static void openActiveSockets(const uint16_t port, const bool use_bcast);
+
/// @brief IOService object, used for all ASIO operations.
isc::asiolink::IOService io_service_;
// grants those options and a single, fixed, hardcoded lease.
Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig, const bool use_bcast,
- const bool direct_response_desired) {
+ const bool direct_response_desired)
+ : port_(port), use_bcast_(use_bcast) {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port);
try {
// First call to instance() will create IfaceMgr (it's a singleton)
if (port) {
// open sockets only if port is non-zero. Port 0 is used
// for non-socket related testing.
- IfaceMgr::instance().openSockets4(port, use_bcast);
+ IfaceMgr::instance().openSockets4(port_, use_bcast_);
}
string srvid_file = CfgMgr::instance().getDataDir() + "/" + string(SERVER_ID_FILE);
/// be freed by the caller.
static const char* serverReceivedPacketName(uint8_t type);
+ ///
+ /// @name Public accessors returning values required to (re)open sockets.
+ ///
+ /// These accessors must be public because sockets are reopened from the
+ /// static configuration callback handler. This callback handler invokes
+ /// @c ControlledDhcpv4Srv::openActiveSockets which requires parameters
+ /// which has to be retrieved from the @c ControlledDhcpv4Srv object.
+ /// They are retrieved using these public functions
+ //@{
+ ///
+ /// @brief Get UDP port on which server should listen.
+ ///
+ /// @return UDP port on which server should listen.
+ uint16_t getPort() const {
+ return (port_);
+ }
+
+ /// @brief Return bool value indicating that broadcast flags should be set
+ /// on sockets.
+ ///
+ /// @return A bool value indicating that broadcast should be used (if true).
+ bool useBroadcast() const {
+ return (use_bcast_);
+ }
+ //@}
+
protected:
/// @brief verifies if specified packet meets RFC requirements
/// during normal operation (e.g. to use different allocators)
boost::shared_ptr<AllocEngine> alloc_engine_;
+ uint16_t port_; ///< UDP port number on which server listens.
+ bool use_bcast_; ///< Should broadcast be enabled on sockets (if true).
+
};
}; // namespace isc::dhcp
Iface::Iface(const std::string& name, int ifindex)
:name_(name), ifindex_(ifindex), mac_len_(0), hardware_type_(0),
flag_loopback_(false), flag_up_(false), flag_running_(false),
- flag_multicast_(false), flag_broadcast_(false), flags_(0)
+ flag_multicast_(false), flag_broadcast_(false), flags_(0),
+ inactive_(false)
{
memset(mac_, 0, sizeof(mac_));
}
if (iface->flag_loopback_ ||
!iface->flag_up_ ||
- !iface->flag_running_) {
+ !iface->flag_running_,
+ iface->inactive_) {
continue;
}
if (iface->flag_loopback_ ||
!iface->flag_up_ ||
- !iface->flag_running_) {
+ !iface->flag_running_,
+ !iface->inactive_) {
continue;
}
/// Interface flags (this value is as is returned by OS,
/// it may mean different things on different OSes).
uint32_t flags_;
+
+ /// Interface is inactive. This can be explicitly set to prevent Interface
+ /// Manager from opening the socket on this interface.
+ bool inactive_;
};
/// @brief Handles network interfaces, transmission and reception.