Parcourir la source

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

Marcin Siodelski il y a 7 ans
Parent
commit
d912be1f7f

+ 22 - 1
src/lib/asiolink/unix_domain_socket.cc

@@ -145,6 +145,9 @@ public:
                         const boost::system::error_code& ec,
                         const boost::system::error_code& ec,
                         size_t length);
                         size_t length);
 
 
+    /// @brief Disables read and write operations on the socket.
+    void shutdown();
+
     /// @brief Closes the socket.
     /// @brief Closes the socket.
     void close();
     void close();
 
 
@@ -245,8 +248,21 @@ UnixDomainSocketImpl::receiveHandler(const UnixDomainSocket::Handler& remote_han
 }
 }
 
 
 void
 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() {
 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)
 UnixDomainSocket::UnixDomainSocket(IOService& io_service)
@@ -313,6 +329,11 @@ UnixDomainSocket::asyncReceive(void* data, const size_t length,
 }
 }
 
 
 void
 void
+UnixDomainSocket::shutdown() {
+    impl_->shutdown();
+}
+
+void
 UnixDomainSocket::close() {
 UnixDomainSocket::close() {
     impl_->close();
     impl_->close();
 }
 }

+ 7 - 0
src/lib/asiolink/unix_domain_socket.h

@@ -104,7 +104,14 @@ public:
     /// error is signalled.
     /// error is signalled.
     void asyncReceive(void* data, const size_t length, const Handler& handler);
     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.
     /// @brief Closes the socket.
+    ///
+    /// @throw UnixDomainSocketError if an error occurs during closure.
     void close();
     void close();
 
 
     /// @brief Returns reference to the underlying ASIO socket.
     /// @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.
     /// @brief Start asynchronous read over the unix domain socket.
     ///
     ///
     /// This method doesn't block. Once the transmission is received over the
     /// 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
 void
 Connection::receiveHandler(const boost::system::error_code& ec,
 Connection::receiveHandler(const boost::system::error_code& ec,
@@ -320,6 +336,10 @@ Connection::sendHandler(const boost::system::error_code& ec,
             doSend();
             doSend();
             return;
             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.
     // All data sent or an error has occurred. Close the connection.
@@ -328,6 +348,9 @@ Connection::sendHandler(const boost::system::error_code& ec,
 
 
 void
 void
 Connection::timeoutHandler() {
 Connection::timeoutHandler() {
+    LOG_INFO(command_logger, COMMAND_SOCKET_CONNECTION_TIMEOUT)
+        .arg(socket_->getNative());
+
     ConstElementPtr rsp = createAnswer(CONTROL_RESULT_ERROR, "Connection over"
     ConstElementPtr rsp = createAnswer(CONTROL_RESULT_ERROR, "Connection over"
                                        " control channel timed out");
                                        " control channel timed out");
     response_ = rsp->str();
     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
 This is an informational message that a new incoming command connection was
 detected and a dedicated socket was opened for that connection.
 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
 % COMMAND_SOCKET_READ Received %1 bytes over command socket %2
 This debug message indicates that specified number of bytes was received
 This debug message indicates that specified number of bytes was received
 over command socket identified by specified file descriptor.
 over command socket identified by specified file descriptor.