"Fossies" - the Fresh Open Source Software Archive

Member "kea-1.6.2/src/lib/config/command_mgr.cc" (21 Feb 2020, 22668 Bytes) of package /linux/misc/kea-1.6.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "command_mgr.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.1_vs_1.6.2.

    1 // Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC")
    2 //
    3 // This Source Code Form is subject to the terms of the Mozilla Public
    4 // License, v. 2.0. If a copy of the MPL was not distributed with this
    5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
    6 
    7 #include <config.h>
    8 
    9 #include <asiolink/asio_wrapper.h>
   10 #include <asiolink/interval_timer.h>
   11 #include <asiolink/io_service.h>
   12 #include <asiolink/unix_domain_socket.h>
   13 #include <asiolink/unix_domain_socket_acceptor.h>
   14 #include <asiolink/unix_domain_socket_endpoint.h>
   15 #include <config/command_mgr.h>
   16 #include <cc/data.h>
   17 #include <cc/command_interpreter.h>
   18 #include <cc/json_feed.h>
   19 #include <dhcp/iface_mgr.h>
   20 #include <config/config_log.h>
   21 #include <config/timeouts.h>
   22 #include <util/watch_socket.h>
   23 #include <boost/bind.hpp>
   24 #include <boost/enable_shared_from_this.hpp>
   25 #include <array>
   26 #include <unistd.h>
   27 #include <sys/file.h>
   28 
   29 using namespace isc;
   30 using namespace isc::asiolink;
   31 using namespace isc::config;
   32 using namespace isc::data;
   33 
   34 namespace {
   35 
   36 /// @brief Maximum size of the data chunk sent/received over the socket.
   37 const size_t BUF_SIZE = 32768;
   38 
   39 class ConnectionPool;
   40 
   41 /// @brief Represents a single connection over control socket.
   42 ///
   43 /// An instance of this object is created when the @c CommandMgr acceptor
   44 /// receives new connection from a controlling client.
   45 class Connection : public boost::enable_shared_from_this<Connection> {
   46 public:
   47 
   48     /// @brief Constructor.
   49     ///
   50     /// This constructor registers a socket of this connection in the Interface
   51     /// Manager to cause the blocking call to @c select() to return as soon as
   52     /// a transmission over the control socket is received.
   53     ///
   54     /// It installs two external sockets on the @IfaceMgr to break synchronous
   55     /// calls to @select(). The @c WatchSocket is used for send operations
   56     /// over the connection. The native socket is used for signaling reads
   57     /// over the connection.
   58     ///
   59     /// @param io_service IOService object used to handle the asio operations
   60     /// @param socket Pointer to the object representing a socket which is used
   61     /// for data transmission.
   62     /// @param connection_pool Reference to the connection pool to which this
   63     /// connection belongs.
   64     /// @param timeout Connection timeout (in seconds).
   65     Connection(const IOServicePtr& io_service,
   66                const boost::shared_ptr<UnixDomainSocket>& socket,
   67                ConnectionPool& connection_pool,
   68                const long timeout)
   69         : socket_(socket), timeout_timer_(*io_service), timeout_(timeout),
   70           buf_(), response_(), connection_pool_(connection_pool), feed_(),
   71           response_in_progress_(false), watch_socket_(new util::WatchSocket()) {
   72 
   73         LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_SOCKET_CONNECTION_OPENED)
   74             .arg(socket_->getNative());
   75 
   76         // Callback value of 0 is used to indicate that callback function is
   77         // not installed.
   78         isc::dhcp::IfaceMgr::instance().addExternalSocket(watch_socket_->getSelectFd(), 0);
   79         isc::dhcp::IfaceMgr::instance().addExternalSocket(socket_->getNative(), 0);
   80 
   81         // Initialize state model for receiving and preparsing commands.
   82         feed_.initModel();
   83 
   84         // Start timer for detecting timeouts.
   85         scheduleTimer();
   86     }
   87 
   88     /// @brief Destructor.
   89     ///
   90     /// Cancels timeout timer if one is scheduled.
   91     ~Connection() {
   92         timeout_timer_.cancel();
   93     }
   94 
   95     /// @brief This method schedules timer or reschedules existing timer.
   96     void scheduleTimer() {
   97         timeout_timer_.setup(boost::bind(&Connection::timeoutHandler, this),
   98                              timeout_, IntervalTimer::ONE_SHOT);
   99     }
  100 
  101     /// @brief Close current connection.
  102     ///
  103     /// Connection is not closed if the invocation of this method is a result of
  104     /// server reconfiguration. The connection will be closed once a response is
  105     /// sent to the client. Closing a socket during processing a request would
  106     /// cause the server to not send a response to the client.
  107     void stop() {
  108         if (!response_in_progress_) {
  109             LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_SOCKET_CONNECTION_CLOSED)
  110                 .arg(socket_->getNative());
  111 
  112             isc::dhcp::IfaceMgr::instance().deleteExternalSocket(watch_socket_->getSelectFd());
  113             isc::dhcp::IfaceMgr::instance().deleteExternalSocket(socket_->getNative());
  114 
  115             // Close watch socket and log errors if occur.
  116             std::string watch_error;
  117             if (!watch_socket_->closeSocket(watch_error)) {
  118                 LOG_ERROR(command_logger, COMMAND_WATCH_SOCKET_CLOSE_ERROR)
  119                     .arg(watch_error);
  120             }
  121 
  122             socket_->close();
  123             timeout_timer_.cancel();
  124         }
  125     }
  126 
  127     /// @brief Gracefully terminates current connection.
  128     ///
  129     /// This method should be called prior to closing the socket to initiate
  130     /// graceful shutdown.
  131     void terminate();
  132 
  133     /// @brief Start asynchronous read over the unix domain socket.
  134     ///
  135     /// This method doesn't block. Once the transmission is received over the
  136     /// socket, the @c Connection::receiveHandler callback is invoked to
  137     /// process received data.
  138     void doReceive() {
  139         socket_->asyncReceive(&buf_[0], sizeof(buf_),
  140                               boost::bind(&Connection::receiveHandler,
  141                                           shared_from_this(), _1, _2));
  142     }
  143 
  144     /// @brief Starts asynchronous send over the unix domain socket.
  145     ///
  146     /// This method doesn't block. Once the send operation (that covers the whole
  147     /// data if it's small or first BUF_SIZE bytes if its large) is completed, the
  148     /// @c Connection::sendHandler callback is invoked. That handler will either
  149     /// close the connection gracefully if all data has been sent, or will
  150     /// call @ref doSend() again to send the next chunk of data.
  151     void doSend() {
  152         size_t chunk_size = (response_.size() < BUF_SIZE) ? response_.size() : BUF_SIZE;
  153         socket_->asyncSend(&response_[0], chunk_size,
  154            boost::bind(&Connection::sendHandler, shared_from_this(), _1, _2));
  155 
  156         // Asynchronous send has been scheduled and we need to indicate this
  157         // to break the synchronous select(). The handler should clear this
  158         // status when invoked.
  159         try {
  160             watch_socket_->markReady();
  161 
  162         } catch (const std::exception& ex) {
  163             LOG_ERROR(command_logger, COMMAND_WATCH_SOCKET_MARK_READY_ERROR)
  164                 .arg(ex.what());
  165         }
  166     }
  167 
  168     /// @brief Handler invoked when the data is received over the control
  169     /// socket.
  170     ///
  171     /// It collects received data into the @c isc::config::JSONFeed object and
  172     /// schedules additional asynchronous read of data if this object signals
  173     /// that command is incomplete. When the entire command is received, the
  174     /// handler processes this command and asynchronously responds to the
  175     /// controlling client.
  176     //
  177     ///
  178     /// @param ec Error code.
  179     /// @param bytes_transferred Number of bytes received.
  180     void receiveHandler(const boost::system::error_code& ec,
  181                         size_t bytes_transferred);
  182 
  183 
  184     /// @brief Handler invoked when the data is sent over the control socket.
  185     ///
  186     /// If there are still data to be sent, another asynchronous send is
  187     /// scheduled. When the entire command is sent, the connection is shutdown
  188     /// and closed.
  189     ///
  190     /// @param ec Error code.
  191     /// @param bytes_transferred Number of bytes sent.
  192     void sendHandler(const boost::system::error_code& ec,
  193                      size_t bytes_transferred);
  194 
  195     /// @brief Handler invoked when timeout has occurred.
  196     ///
  197     /// Asynchronously sends a response to the client indicating that the
  198     /// timeout has occurred.
  199     void timeoutHandler();
  200 
  201 private:
  202 
  203     /// @brief Pointer to the socket used for transmission.
  204     boost::shared_ptr<UnixDomainSocket> socket_;
  205 
  206     /// @brief Interval timer used to detect connection timeouts.
  207     IntervalTimer timeout_timer_;
  208 
  209     /// @brief Connection timeout (in milliseconds)
  210     long timeout_;
  211 
  212     /// @brief Buffer used for received data.
  213     std::array<char, BUF_SIZE> buf_;
  214 
  215     /// @brief Response created by the server.
  216     std::string response_;
  217 
  218     /// @brief Reference to the pool of connections.
  219     ConnectionPool& connection_pool_;
  220 
  221     /// @brief State model used to receive data over the connection and detect
  222     /// when the command ends.
  223     JSONFeed feed_;
  224 
  225     /// @brief Boolean flag indicating if the request to stop connection is a
  226     /// result of server reconfiguration.
  227     bool response_in_progress_;
  228 
  229     /// @brief Pointer to watch socket instance used to signal that the socket
  230     /// is ready for read or write.
  231     util::WatchSocketPtr watch_socket_;
  232 };
  233 
  234 /// @brief Pointer to the @c Connection.
  235 typedef boost::shared_ptr<Connection> ConnectionPtr;
  236 
  237 /// @brief Holds all open connections.
  238 class ConnectionPool {
  239 public:
  240 
  241     /// @brief Starts new connection.
  242     ///
  243     /// @param connection Pointer to the new connection object.
  244     void start(const ConnectionPtr& connection) {
  245         connection->doReceive();
  246         connections_.insert(connection);
  247     }
  248 
  249     /// @brief Stops running connection.
  250     ///
  251     /// @param connection Pointer to the new connection object.
  252     void stop(const ConnectionPtr& connection) {
  253         try {
  254             connection->stop();
  255             connections_.erase(connection);
  256         } catch (const std::exception& ex) {
  257             LOG_ERROR(command_logger, COMMAND_SOCKET_CONNECTION_CLOSE_FAIL)
  258                 .arg(ex.what());
  259         }
  260     }
  261 
  262     /// @brief Stops all connections which are allowed to stop.
  263     void stopAll() {
  264         for (auto conn = connections_.begin(); conn != connections_.end();
  265              ++conn) {
  266             (*conn)->stop();
  267         }
  268         connections_.clear();
  269     }
  270 
  271 private:
  272 
  273     /// @brief Pool of connections.
  274     std::set<ConnectionPtr> connections_;
  275 
  276 };
  277 
  278 void
  279 Connection::terminate() {
  280     try {
  281         socket_->shutdown();
  282 
  283     } catch (const std::exception& ex) {
  284         LOG_ERROR(command_logger, COMMAND_SOCKET_CONNECTION_SHUTDOWN_FAIL)
  285             .arg(ex.what());
  286     }
  287 }
  288 
  289 void
  290 Connection::receiveHandler(const boost::system::error_code& ec,
  291                            size_t bytes_transferred) {
  292     if (ec) {
  293         if (ec.value() == boost::asio::error::eof) {
  294             std::stringstream os;
  295             if (feed_.getProcessedText().empty()) {
  296                os << "no input data to discard";
  297             }
  298             else {
  299                os << "discarding partial command of "
  300                   << feed_.getProcessedText().size() << " bytes";
  301             }
  302 
  303             // Foreign host has closed the connection. We should remove it from the
  304             // connection pool.
  305             LOG_INFO(command_logger, COMMAND_SOCKET_CLOSED_BY_FOREIGN_HOST)
  306                 .arg(socket_->getNative()).arg(os.str());
  307         } else if (ec.value() != boost::asio::error::operation_aborted) {
  308             LOG_ERROR(command_logger, COMMAND_SOCKET_READ_FAIL)
  309                 .arg(ec.value()).arg(socket_->getNative());
  310         }
  311 
  312         connection_pool_.stop(shared_from_this());
  313         return;
  314 
  315     } else if (bytes_transferred == 0) {
  316         // Nothing received. Close the connection.
  317         connection_pool_.stop(shared_from_this());
  318         return;
  319     }
  320 
  321     LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_SOCKET_READ)
  322         .arg(bytes_transferred).arg(socket_->getNative());
  323 
  324     // Reschedule the timer because the transaction is ongoing.
  325     scheduleTimer();
  326 
  327     ConstElementPtr rsp;
  328 
  329     try {
  330         // Received some data over the socket. Append them to the JSON feed
  331         // to see if we have reached the end of command.
  332         feed_.postBuffer(&buf_[0], bytes_transferred);
  333         feed_.poll();
  334         // If we haven't yet received the full command, continue receiving.
  335         if (feed_.needData()) {
  336             doReceive();
  337             return;
  338         }
  339 
  340         // Received entire command. Parse the command into JSON.
  341         if (feed_.feedOk()) {
  342             ConstElementPtr cmd = feed_.toElement();
  343             response_in_progress_ = true;
  344 
  345             // Cancel the timer to make sure that long lasting command
  346             // processing doesn't cause the timeout.
  347             timeout_timer_.cancel();
  348 
  349             // If successful, then process it as a command.
  350             rsp = CommandMgr::instance().processCommand(cmd);
  351 
  352             response_in_progress_ = false;
  353 
  354         } else {
  355             // Failed to parse command as JSON or process the received command.
  356             // This exception will be caught below and the error response will
  357             // be sent.
  358             isc_throw(BadValue, feed_.getErrorMessage());
  359         }
  360 
  361     } catch (const Exception& ex) {
  362         LOG_WARN(command_logger, COMMAND_PROCESS_ERROR1).arg(ex.what());
  363         rsp = createAnswer(CONTROL_RESULT_ERROR, std::string(ex.what()));
  364     }
  365 
  366     // No response generated. Connection will be closed.
  367     if (!rsp) {
  368         LOG_WARN(command_logger, COMMAND_RESPONSE_ERROR);
  369         rsp = createAnswer(CONTROL_RESULT_ERROR,
  370                            "internal server error: no response generated");
  371 
  372     } else {
  373 
  374         // Reschedule the timer as it may be either canceled or need to be
  375         // updated to not timeout before we manage to the send the reply.
  376         scheduleTimer();
  377 
  378         // Let's convert JSON response to text. Note that at this stage
  379         // the rsp pointer is always set.
  380         response_ = rsp->str();
  381 
  382         doSend();
  383         return;
  384     }
  385 
  386     // Close the connection if we have sent the entire response.
  387     connection_pool_.stop(shared_from_this());
  388 }
  389 
  390 void
  391 Connection::sendHandler(const boost::system::error_code& ec,
  392                         size_t bytes_transferred) {
  393     // Clear the watch socket so as the future send operation can mark it
  394     // again to interrupt the synchronous select() call.
  395     try {
  396         watch_socket_->clearReady();
  397 
  398     } catch (const std::exception& ex) {
  399         LOG_ERROR(command_logger, COMMAND_WATCH_SOCKET_CLEAR_ERROR)
  400             .arg(ex.what());
  401     }
  402 
  403     if (ec) {
  404         // If an error occurred, log this error and stop the connection.
  405         if (ec.value() != boost::asio::error::operation_aborted) {
  406             LOG_ERROR(command_logger, COMMAND_SOCKET_WRITE_FAIL)
  407                 .arg(socket_->getNative()).arg(ec.message());
  408         }
  409 
  410     } else {
  411 
  412         // Reschedule the timer because the transaction is ongoing.
  413         scheduleTimer();
  414 
  415         // No error. We are in a process of sending a response. Need to
  416         // remove the chunk that we have managed to sent with the previous
  417         // attempt.
  418         response_.erase(0, bytes_transferred);
  419 
  420         LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_SOCKET_WRITE)
  421             .arg(bytes_transferred).arg(response_.size())
  422             .arg(socket_->getNative());
  423 
  424         // Check if there is any data left to be sent and sent it.
  425         if (!response_.empty()) {
  426             doSend();
  427             return;
  428         }
  429 
  430         // Gracefully shutdown the connection and close the socket if
  431         // we have sent the whole response.
  432         terminate();
  433     }
  434 
  435     // All data sent or an error has occurred. Close the connection.
  436     connection_pool_.stop(shared_from_this());
  437 }
  438 
  439 void
  440 Connection::timeoutHandler() {
  441     LOG_INFO(command_logger, COMMAND_SOCKET_CONNECTION_TIMEOUT)
  442         .arg(socket_->getNative());
  443 
  444     try {
  445         socket_->cancel();
  446 
  447     } catch (const std::exception& ex) {
  448         LOG_ERROR(command_logger, COMMAND_SOCKET_CONNECTION_CANCEL_FAIL)
  449             .arg(socket_->getNative())
  450             .arg(ex.what());
  451     }
  452 
  453     std::stringstream os;
  454     os << "Connection over control channel timed out";
  455     if (!feed_.getProcessedText().empty()) {
  456         os << ", discarded partial command of "
  457            << feed_.getProcessedText().size() << " bytes";
  458     }
  459 
  460     ConstElementPtr rsp = createAnswer(CONTROL_RESULT_ERROR, os.str());
  461     response_ = rsp->str();
  462     doSend();
  463 }
  464 
  465 
  466 }
  467 
  468 namespace isc {
  469 namespace config {
  470 
  471 /// @brief Implementation of the @c CommandMgr.
  472 class CommandMgrImpl {
  473 public:
  474 
  475     /// @brief Constructor.
  476     CommandMgrImpl()
  477         : io_service_(), acceptor_(), socket_(), socket_name_(),
  478           connection_pool_(), timeout_(TIMEOUT_DHCP_SERVER_RECEIVE_COMMAND) {
  479     }
  480 
  481     /// @brief Opens acceptor service allowing the control clients to connect.
  482     ///
  483     /// @param socket_info Configuration information for the control socket.
  484     /// @throw BadSocketInfo When socket configuration is invalid.
  485     /// @throw SocketError When socket operation fails.
  486     void openCommandSocket(const isc::data::ConstElementPtr& socket_info);
  487 
  488     /// @brief Asynchronously accepts next connection.
  489     void doAccept();
  490 
  491     /// @brief Returns the lock file name
  492     std::string getLockName() {
  493         return (std::string(socket_name_ + ".lock"));
  494     }
  495 
  496     /// @brief Pointer to the IO service used by the server process for running
  497     /// asynchronous tasks.
  498     IOServicePtr io_service_;
  499 
  500     /// @brief Pointer to the acceptor service.
  501     boost::shared_ptr<UnixDomainSocketAcceptor> acceptor_;
  502 
  503     /// @brief Pointer to the socket into which the new connection is accepted.
  504     boost::shared_ptr<UnixDomainSocket> socket_;
  505 
  506     /// @brief Path to the unix domain socket descriptor.
  507     ///
  508     /// This is used to remove the socket file once the connection terminates.
  509     std::string socket_name_;
  510 
  511     /// @brief Pool of connections.
  512     ConnectionPool connection_pool_;
  513 
  514     /// @brief Connection timeout
  515     long timeout_;
  516 };
  517 
  518 void
  519 CommandMgrImpl::openCommandSocket(const isc::data::ConstElementPtr& socket_info) {
  520     socket_name_.clear();
  521 
  522     if(!socket_info) {
  523         isc_throw(BadSocketInfo, "Missing socket_info parameters, can't create socket.");
  524     }
  525 
  526     ConstElementPtr type = socket_info->get("socket-type");
  527     if (!type) {
  528         isc_throw(BadSocketInfo, "Mandatory 'socket-type' parameter missing");
  529     }
  530 
  531     // Only supporting unix sockets right now.
  532     if (type->stringValue() != "unix") {
  533         isc_throw(BadSocketInfo, "Invalid 'socket-type' parameter value "
  534                   << type->stringValue());
  535     }
  536 
  537     // UNIX socket is requested. It takes one parameter: socket-name that
  538     // specifies UNIX path of the socket.
  539     ConstElementPtr name = socket_info->get("socket-name");
  540     if (!name) {
  541         isc_throw(BadSocketInfo, "Mandatory 'socket-name' parameter missing");
  542     }
  543 
  544     if (name->getType() != Element::string) {
  545         isc_throw(BadSocketInfo, "'socket-name' parameter expected to be a string");
  546     }
  547 
  548     socket_name_ = name->stringValue();
  549 
  550     // First let's open lock file.
  551     std::string lock_name = getLockName();
  552     int lock_fd = open(lock_name.c_str(), O_RDONLY | O_CREAT, 0600);
  553     if (lock_fd == -1) {
  554         std::string errmsg = strerror(errno);
  555         isc_throw(SocketError, "cannot create socket lockfile, "
  556                   << lock_name  << ", : " << errmsg);
  557     }
  558 
  559     // Try to acquire lock. If we can't somebody else is actively
  560     // using it.
  561     int ret = flock(lock_fd, LOCK_EX | LOCK_NB);
  562     if (ret != 0) {
  563         std::string errmsg = strerror(errno);
  564         isc_throw(SocketError, "cannot lock socket lockfile, "
  565                   << lock_name  << ", : " << errmsg);
  566     }
  567 
  568     // We have the lock, so let's remove the pre-existing socket
  569     // file if it exists.
  570     static_cast<void>(::remove(socket_name_.c_str()));
  571 
  572     LOG_INFO(command_logger, COMMAND_ACCEPTOR_START)
  573         .arg(socket_name_);
  574 
  575     try {
  576         // Start asynchronous acceptor service.
  577         acceptor_.reset(new UnixDomainSocketAcceptor(*io_service_));
  578         UnixDomainSocketEndpoint endpoint(socket_name_);
  579         acceptor_->open(endpoint);
  580         acceptor_->bind(endpoint);
  581         acceptor_->listen();
  582         // Install this socket in Interface Manager.
  583         isc::dhcp::IfaceMgr::instance().addExternalSocket(acceptor_->getNative(), 0);
  584 
  585         doAccept();
  586 
  587     } catch (const std::exception& ex) {
  588         isc_throw(SocketError, ex.what());
  589     }
  590 }
  591 
  592 void
  593 CommandMgrImpl::doAccept() {
  594     // Create a socket into which the acceptor will accept new connection.
  595     socket_.reset(new UnixDomainSocket(*io_service_));
  596     acceptor_->asyncAccept(*socket_, [this](const boost::system::error_code& ec) {
  597         if (!ec) {
  598             // New connection is arriving. Start asynchronous transmission.
  599             ConnectionPtr connection(new Connection(io_service_, socket_,
  600                                                     connection_pool_,
  601                                                     timeout_));
  602             connection_pool_.start(connection);
  603 
  604         } else if (ec.value() != boost::asio::error::operation_aborted) {
  605             LOG_ERROR(command_logger, COMMAND_SOCKET_ACCEPT_FAIL)
  606                 .arg(acceptor_->getNative()).arg(ec.message());
  607         }
  608 
  609         // Unless we're stopping the service, start accepting connections again.
  610         if (ec.value() != boost::asio::error::operation_aborted) {
  611             doAccept();
  612         }
  613     });
  614 }
  615 
  616 CommandMgr::CommandMgr()
  617     : HookedCommandMgr(), impl_(new CommandMgrImpl()) {
  618 }
  619 
  620 void
  621 CommandMgr::openCommandSocket(const isc::data::ConstElementPtr& socket_info) {
  622     impl_->openCommandSocket(socket_info);
  623 }
  624 
  625 void CommandMgr::closeCommandSocket() {
  626     // Close acceptor if the acceptor is open.
  627     if (impl_->acceptor_ && impl_->acceptor_->isOpen()) {
  628         isc::dhcp::IfaceMgr::instance().deleteExternalSocket(impl_->acceptor_->getNative());
  629         impl_->acceptor_->close();
  630         static_cast<void>(::remove(impl_->socket_name_.c_str()));
  631         static_cast<void>(::remove(impl_->getLockName().c_str()));
  632     }
  633 
  634     // Stop all connections which can be closed. The only connection that won't
  635     // be closed is the one over which we have received a request to reconfigure
  636     // the server. This connection will be held until the CommandMgr responds to
  637     // such request.
  638     impl_->connection_pool_.stopAll();
  639 }
  640 
  641 int
  642 CommandMgr::getControlSocketFD() {
  643     return (impl_->acceptor_ ? impl_->acceptor_->getNative() : -1);
  644 }
  645 
  646 
  647 CommandMgr&
  648 CommandMgr::instance() {
  649     static CommandMgr cmd_mgr;
  650     return (cmd_mgr);
  651 }
  652 
  653 void
  654 CommandMgr::setIOService(const IOServicePtr& io_service) {
  655     impl_->io_service_ = io_service;
  656 }
  657 
  658 void
  659 CommandMgr::setConnectionTimeout(const long timeout) {
  660     impl_->timeout_ = timeout;
  661 }
  662 
  663 
  664 }; // end of isc::config
  665 }; // end of isc