]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3478] Checkpoint: server connection
authorFrancis Dupont <fdupont@isc.org>
Wed, 31 Jul 2024 19:22:37 +0000 (21:22 +0200)
committerFrancis Dupont <fdupont@isc.org>
Wed, 21 Aug 2024 07:58:57 +0000 (09:58 +0200)
src/lib/http/connection.cc
src/lib/http/connection.h

index 487566c1988b4c2498c735f6fe178a86fde5629b..141390cd260d7c31e35046acb0aaef225c2f22c6 100644 (file)
@@ -7,6 +7,7 @@
 #include <config.h>
 
 #include <asiolink/asio_wrapper.h>
+#include <dhcp/iface_mgr.h>
 #include <http/connection.h>
 #include <http/connection_pool.h>
 #include <http/http_log.h>
@@ -15,6 +16,8 @@
 #include <functional>
 
 using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::util;
 namespace ph = std::placeholders;
 
 namespace {
@@ -80,7 +83,8 @@ HttpConnection::HttpConnection(const asiolink::IOServicePtr& io_service,
       connection_pool_(connection_pool),
       response_creator_(response_creator),
       acceptor_callback_(callback),
-      use_external_(false) {
+      use_external_(false),
+      watch_socket_() {
     if (!tls_context) {
         tcp_socket_.reset(new asiolink::TCPSocket<SocketCallback>(io_service));
     } else {
@@ -131,6 +135,11 @@ HttpConnection::recordParameters(const HttpRequestPtr& request) const {
 
 void
 HttpConnection::shutdownCallback(const boost::system::error_code&) {
+    if (use_external_) {
+        IfaceMgr::instance().deleteExternalSocket(tls_socket_->getNative());
+        closeWatchSocket();
+    }
+
     tls_socket_->close();
 }
 
@@ -138,6 +147,10 @@ void
 HttpConnection::shutdown() {
     request_timer_.cancel();
     if (tcp_socket_) {
+        if (use_external_) {
+            IfaceMgr::instance().deleteExternalSocket(tcp_socket_->getNative());
+            closeWatchSocket();
+        }
         tcp_socket_->close();
         return;
     }
@@ -153,14 +166,36 @@ HttpConnection::shutdown() {
     isc_throw(Unexpected, "internal error: unable to shutdown the socket");
 }
 
+void
+HttpConnection::closeWatchSocket() {
+    if (!watch_socket_) {
+        /// Should not happen...
+        return;
+    }
+    IfaceMgr::instance().deleteExternalSocket(watch_socket_->getSelectFd());
+    // Close watch socket and log errors if occur.
+    std::string watch_error;
+    if (!watch_socket_->closeSocket(watch_error)) {
+        /// log
+    }
+}
+
 void
 HttpConnection::close() {
     request_timer_.cancel();
     if (tcp_socket_) {
+        if (use_external_) {
+            IfaceMgr::instance().deleteExternalSocket(tcp_socket_->getNative());
+            closeWatchSocket();
+        }
         tcp_socket_->close();
         return;
     }
     if (tls_socket_) {
+        if (use_external_) {
+            IfaceMgr::instance().deleteExternalSocket(tls_socket_->getNative());
+            closeWatchSocket();
+        }
         tls_socket_->close();
         return;
     }
@@ -214,6 +249,17 @@ HttpConnection::asyncAccept() {
             }
             tls_acceptor->asyncAccept(*tls_socket_, cb);
         }
+        if (use_external_) {
+            auto& iface_mgr = IfaceMgr::instance ();
+            if (tcp_socket_) {
+                iface_mgr.addExternalSocket(tcp_socket_->getNative(), 0);
+            }
+            if (tls_socket_) {
+                iface_mgr.addExternalSocket(tls_socket_->getNative(), 0);
+            }
+            watch_socket_.reset(new WatchSocket());
+            iface_mgr.addExternalSocket(watch_socket_->getSelectFd(), 0);
+        }
     } catch (const std::exception& ex) {
         isc_throw(HttpConnectionError, "unable to start accepting TCP "
                   "connections: " << ex.what());
@@ -236,7 +282,12 @@ HttpConnection::doHandshake() {
                                 ph::_1)); // error
     try {
         tls_socket_->handshake(cb);
-
+        if (use_external_) {
+            // Asynchronous handshake has been scheduled and we need to
+            // indicate this to break the synchronous select(). The handler
+            // should clear this status when invoked.
+            watch_socket_->markReady();
+        }
     } catch (const std::exception& ex) {
         isc_throw(HttpConnectionError, "unable to perform TLS handshake: "
                   << ex.what());
@@ -296,12 +347,26 @@ HttpConnection::doWrite(HttpConnection::TransactionPtr transaction) {
                 tcp_socket_->asyncSend(transaction->getOutputBufData(),
                                        transaction->getOutputBufSize(),
                                        cb);
+                if (use_external_) {
+                    // Asynchronous send has been scheduled and we
+                    // need to indicate this to break the synchronous
+                    // select(). The handler should clear this status
+                    // when invoked.
+                    watch_socket_->markReady();
+                }
                 return;
             }
             if (tls_socket_) {
                 tls_socket_->asyncSend(transaction->getOutputBufData(),
                                        transaction->getOutputBufSize(),
                                        cb);
+                if (use_external_) {
+                    // Asynchronous send has been scheduled and we
+                    // need to indicate this to break the synchronous
+                    // select(). The handler should clear this status
+                    // when invoked.
+                    watch_socket_->markReady();
+                }
                 return;
             }
         } else {
@@ -366,6 +431,15 @@ HttpConnection::acceptorCallback(const boost::system::error_code& ec) {
 
 void
 HttpConnection::handshakeCallback(const boost::system::error_code& ec) {
+    if (use_external_) {
+        // Clear the watch socket so as the future send operation can
+        // mark it again to interrupt the synchronous select() call.
+        try {
+            watch_socket_->clearReady();
+        } catch (const std::exception& ex) {
+            // log.
+        }
+    }
     if (ec) {
         LOG_INFO(http_logger, HTTP_CONNECTION_HANDSHAKE_FAILED)
             .arg(getRemoteEndpointAddressAsText())
@@ -477,6 +551,15 @@ HttpConnection::socketReadCallback(HttpConnection::TransactionPtr transaction,
 void
 HttpConnection::socketWriteCallback(HttpConnection::TransactionPtr transaction,
                                     boost::system::error_code ec, size_t length) {
+    if (use_external_) {
+        // Clear the watch socket so as the future send operation can
+        // mark it again to interrupt the synchronous select() call.
+        try {
+            watch_socket_->clearReady();
+        } catch (const std::exception& ex) {
+            // log.
+        }
+    }
     if (ec) {
         // IO service has been stopped and the connection is probably
         // going to be shutting down.
index cea77244512a2ff17d31409c675e23344f932071..39e165964ed4df6a2f214547e1ac4b63caf1b73b 100644 (file)
@@ -12,6 +12,7 @@
 #include <http/http_acceptor.h>
 #include <http/request_parser.h>
 #include <http/response_creator_factory.h>
+#include <util/watch_socket.h>
 #include <boost/enable_shared_from_this.hpp>
 #include <boost/system/error_code.hpp>
 #include <boost/shared_ptr.hpp>
@@ -398,9 +399,12 @@ protected:
     /// @brief Stops current connection.
     void stopThisConnection();
 
-    /// @brief returns remote address in textual form
+    /// @brief Returns remote address in textual form
     std::string getRemoteEndpointAddressAsText() const;
 
+    /// @brief Close the watch socket.
+    void closeWatchSocket();
+
     /// @brief Timer used to detect Request Timeout.
     asiolink::IntervalTimer request_timer_;
 
@@ -435,6 +439,10 @@ protected:
 
     /// @brief Use external sockets flag.
     bool use_external_;
+
+    /// @brief Pointer to watch socket instance used to signal that the socket
+    /// is ready for read or write when use external sockets is true.
+    util::WatchSocketPtr watch_socket_;
 };
 
 } // end of namespace isc::http