From: Marcin Siodelski Date: Tue, 4 Jul 2017 07:47:02 +0000 (+0200) Subject: [5318] Call shutdown prior to closing the control socket. X-Git-Tag: trac5227_base~8^2~1^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d912be1f7f444b4d5a3559477f0b5ea66b2845db;p=thirdparty%2Fkea.git [5318] Call shutdown prior to closing the control socket. --- diff --git a/src/lib/asiolink/unix_domain_socket.cc b/src/lib/asiolink/unix_domain_socket.cc index ae639df138..1551ec9026 100644 --- a/src/lib/asiolink/unix_domain_socket.cc +++ b/src/lib/asiolink/unix_domain_socket.cc @@ -145,6 +145,9 @@ public: const boost::system::error_code& ec, size_t length); + /// @brief Disables read and write operations on the socket. + void shutdown(); + /// @brief Closes the socket. void close(); @@ -244,9 +247,22 @@ UnixDomainSocketImpl::receiveHandler(const UnixDomainSocket::Handler& remote_han remote_handler(ec, length); } +void +UnixDomainSocketImpl::shutdown() { + boost::system::error_code ec; + static_cast(socket_.shutdown(stream_protocol::socket::shutdown_both, ec)); + if (ec) { + isc_throw(UnixDomainSocketError, ec.message()); + } +} + void UnixDomainSocketImpl::close() { - static_cast(socket_.close()); + boost::system::error_code ec; + static_cast(socket_.close(ec)); + if (ec) { + isc_throw(UnixDomainSocketError, ec.message()); + } } UnixDomainSocket::UnixDomainSocket(IOService& io_service) @@ -312,6 +328,11 @@ UnixDomainSocket::asyncReceive(void* data, const size_t length, impl_->asyncReceive(data, length, handler); } +void +UnixDomainSocket::shutdown() { + impl_->shutdown(); +} + void UnixDomainSocket::close() { impl_->close(); diff --git a/src/lib/asiolink/unix_domain_socket.h b/src/lib/asiolink/unix_domain_socket.h index ed8cfdd0ed..6f0fe8c517 100644 --- a/src/lib/asiolink/unix_domain_socket.h +++ b/src/lib/asiolink/unix_domain_socket.h @@ -104,7 +104,14 @@ public: /// error is signalled. void asyncReceive(void* data, const size_t length, const Handler& handler); + /// @brief Disables read and write operations on the socket. + /// + /// @throw UnixDomainSocketError if an error occurs during shutdown. + void shutdown(); + /// @brief Closes the socket. + /// + /// @throw UnixDomainSocketError if an error occurs during closure. void close(); /// @brief Returns reference to the underlying ASIO socket. diff --git a/src/lib/config/command_mgr.cc b/src/lib/config/command_mgr.cc index 8795d7062e..6b4a7c044b 100644 --- a/src/lib/config/command_mgr.cc +++ b/src/lib/config/command_mgr.cc @@ -100,6 +100,12 @@ public: } } + /// @brief Gracefully terminates current connection. + /// + /// This method should be called prior to closing the socket to initiate + /// graceful shutdown. + void terminate(); + /// @brief Start asynchronous read over the unix domain socket. /// /// This method doesn't block. Once the transmission is received over the @@ -213,6 +219,16 @@ private: }; +void +Connection::terminate() { + try { + socket_->shutdown(); + + } catch (const std::exception& ex) { + LOG_ERROR(command_logger, COMMAND_SOCKET_CONNECTION_SHUTDOWN_FAIL) + .arg(ex.what()); + } +} void Connection::receiveHandler(const boost::system::error_code& ec, @@ -320,6 +336,10 @@ Connection::sendHandler(const boost::system::error_code& ec, doSend(); return; } + + // Gracefully shutdown the connection and close the socket if + // we have sent the whole response. + terminate(); } // All data sent or an error has occurred. Close the connection. @@ -328,6 +348,9 @@ Connection::sendHandler(const boost::system::error_code& ec, void Connection::timeoutHandler() { + LOG_INFO(command_logger, COMMAND_SOCKET_CONNECTION_TIMEOUT) + .arg(socket_->getNative()); + ConstElementPtr rsp = createAnswer(CONTROL_RESULT_ERROR, "Connection over" " control channel timed out"); response_ = rsp->str(); diff --git a/src/lib/config/config_messages.mes b/src/lib/config/config_messages.mes index 49aeb942a8..70c44f7f77 100644 --- a/src/lib/config/config_messages.mes +++ b/src/lib/config/config_messages.mes @@ -73,6 +73,15 @@ detailed error is provided as an argument. This is an informational message that a new incoming command connection was detected and a dedicated socket was opened for that connection. +% COMMAND_SOCKET_CONNECTION_SHUTDOWN_FAIL Encountered error %1 while trying to gracefully shutdown socket +This message indicates an error while trying to gracefully shutdown command +connection. The type of the error is included in the message. + +% COMMAND_SOCKET_CONNECTION_TIMEOUT Timeout occurred for connection over socket %1 +This is an informational message that indicates that the timeout has +occurred for one of the command channel connections. The response +sent by the server indicates a timeout and is then closed. + % COMMAND_SOCKET_READ Received %1 bytes over command socket %2 This debug message indicates that specified number of bytes was received over command socket identified by specified file descriptor.