Browse Source

[5318] Call shutdown prior to closing the control socket.

Marcin Siodelski 7 years ago
parent
commit
d912be1f7f

+ 22 - 1
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();
 
@@ -245,8 +248,21 @@ UnixDomainSocketImpl::receiveHandler(const UnixDomainSocket::Handler& remote_han
 }
 
 void
+UnixDomainSocketImpl::shutdown() {
+    boost::system::error_code ec;
+    static_cast<void>(socket_.shutdown(stream_protocol::socket::shutdown_both, ec));
+    if (ec) {
+        isc_throw(UnixDomainSocketError, ec.message());
+    }
+}
+
+void
 UnixDomainSocketImpl::close() {
-    static_cast<void>(socket_.close());
+    boost::system::error_code ec;
+    static_cast<void>(socket_.close(ec));
+    if (ec) {
+        isc_throw(UnixDomainSocketError, ec.message());
+    }
 }
 
 UnixDomainSocket::UnixDomainSocket(IOService& io_service)
@@ -313,6 +329,11 @@ UnixDomainSocket::asyncReceive(void* data, const size_t length,
 }
 
 void
+UnixDomainSocket::shutdown() {
+    impl_->shutdown();
+}
+
+void
 UnixDomainSocket::close() {
     impl_->close();
 }

+ 7 - 0
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.

+ 23 - 0
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();

+ 9 - 0
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.