From: Thomas Markwalder Date: Mon, 24 Jun 2019 19:33:53 +0000 (-0400) Subject: [#691,!395] HAService now registers HTTP client sockets with InterfaceMgr X-Git-Tag: Kea-1.6.0-beta2~201 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ff3d254d65f325bd904e675c6ee56058d4895284;p=thirdparty%2Fkea.git [#691,!395] HAService now registers HTTP client sockets with InterfaceMgr src/hooks/dhcp/high_availability/ha_service.cc HAService clientConnectHandler() - new client connection connect callback clientCloseHandler() - new client connection close callback asyncSendLeaseUpdate() asyncSendHeartbeat() asyncDisableDHCPService() asyncEnableDHCPService() asyncSyncLeasesInternal() - added new call backs to HttpClient::asyncSendRequest() invocation src/lib/http/client.cc Connection::resetState() - added reset of close callback --- diff --git a/src/hooks/dhcp/high_availability/ha_service.cc b/src/hooks/dhcp/high_availability/ha_service.cc index 1abf3e4f14..fc5cb59e0e 100644 --- a/src/hooks/dhcp/high_availability/ha_service.cc +++ b/src/hooks/dhcp/high_availability/ha_service.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -270,7 +271,7 @@ HAService::readyStateHandler() { case HA_HOT_STANDBY_ST: verboseTransition(HA_HOT_STANDBY_ST); break; - + case HA_LOAD_BALANCING_ST: verboseTransition(HA_LOAD_BALANCING_ST); break; @@ -852,7 +853,11 @@ HAService::asyncSendLeaseUpdate(const QueryPtrType& query, // Then it returns control to the DHCP server. runModel(HA_LEASE_UPDATES_COMPLETE_EVT); } - }); + }, + HttpClient::RequestTimeout(10000), + boost::bind(&HAService::clientConnectHandler, this, _1, _2), + boost::bind(&HAService::clientCloseHandler, this, _1) + ); // Request scheduled, so update the request counters for the query. if (pending_requests_.count(query) == 0) { @@ -1051,7 +1056,11 @@ HAService::asyncSendHeartbeat() { // asynchronous tasks etc. Then it returns control to the DHCP server. startHeartbeat(); runModel(HA_HEARTBEAT_COMPLETE_EVT); - }); + }, + HttpClient::RequestTimeout(10000), + boost::bind(&HAService::clientConnectHandler, this, _1, _2), + boost::bind(&HAService::clientCloseHandler, this, _1) + ); } void @@ -1137,7 +1146,11 @@ HAService::asyncDisableDHCPService(HttpClient& http_client, post_request_action(error_message.empty(), error_message); } - }); + }, + HttpClient::RequestTimeout(10000), + boost::bind(&HAService::clientConnectHandler, this, _1, _2), + boost::bind(&HAService::clientCloseHandler, this, _1) + ); } void @@ -1204,7 +1217,11 @@ HAService::asyncEnableDHCPService(HttpClient& http_client, post_request_action(error_message.empty(), error_message); } - }); + }, + HttpClient::RequestTimeout(10000), + boost::bind(&HAService::clientConnectHandler, this, _1, _2), + boost::bind(&HAService::clientCloseHandler, this, _1) + ); } void @@ -1440,7 +1457,12 @@ HAService::asyncSyncLeasesInternal(http::HttpClient& http_client, error_message, dhcp_disabled); } - }, HttpClient::RequestTimeout(config_->getSyncTimeout())); + }, + HttpClient::RequestTimeout(config_->getSyncTimeout()), + boost::bind(&HAService::clientConnectHandler, this, _1, _2), + boost::bind(&HAService::clientCloseHandler, this, _1) + ); + } ConstElementPtr @@ -1596,6 +1618,30 @@ HAService::verifyAsyncResponse(const HttpResponsePtr& response) { return (args); } +bool +HAService::clientConnectHandler(const boost::system::error_code& ec, int tcp_native_fd) { + if (!ec || ec.value() == boost::asio::error::in_progress) { + IfaceMgr::instance().addExternalSocket(tcp_native_fd, + [this]() { + // Callback is a NOP. Ready events handlers are run by an explicit + // call IOService ready in kea-dhcp code. We are registering + // the socket to interrupt main-thread select(). + }); + } + + // If ec.value() == boost::asio::error::already_connected, we should already + // be registered, so nothing to do. If it is any other value, than connect + // failed and Connection logic should handle that, not us, so no matter + // what happens we're returning true. + return (true); +} + +void +HAService::clientCloseHandler(int tcp_native_fd) { + if (tcp_native_fd >= 0) { + IfaceMgr::instance().deleteExternalSocket(tcp_native_fd); + } +}; } // end of namespace isc::ha } // end of namespace isc diff --git a/src/hooks/dhcp/high_availability/ha_service.h b/src/hooks/dhcp/high_availability/ha_service.h index 6acc3ac4f8..770b7add98 100644 --- a/src/hooks/dhcp/high_availability/ha_service.h +++ b/src/hooks/dhcp/high_availability/ha_service.h @@ -727,6 +727,26 @@ protected: /// @throw CtrlChannelError if response is invalid or contains an error. data::ConstElementPtr verifyAsyncResponse(const http::HttpResponsePtr& response); + /// @brief HttpClient connect callback handler + /// + /// Passed into HttpClient calls to allow registration of client's TCP socket + /// with an external monitor (such as IfaceMgr's main-thread select()). + /// + /// @param ec Error status of the ASIO connect + /// @param tcp_native_fd socket descriptor to register + /// @param returns true. Registeration cannot fail, and if ec indicates a real + /// error we want Connection logic to process it. + virtual bool clientConnectHandler(const boost::system::error_code& ec, int tcp_native_fd); + + /// @brief HttpClient close callback handler + /// + /// Passed into HttpClient calls to allow unregistration of client's + /// TCP socket with an external monitor (such as IfaceMgr's + /// main-thread select()). + /// + /// @param tcp_native_fd socket descriptor to register + virtual void clientCloseHandler(int tcp_native_fd); + /// @brief Pointer to the IO service object shared between this hooks /// library and the DHCP server. asiolink::IOServicePtr io_service_; diff --git a/src/lib/http/client.cc b/src/lib/http/client.cc index db6473115e..b9bafda0bb 100644 --- a/src/lib/http/client.cc +++ b/src/lib/http/client.cc @@ -500,6 +500,7 @@ Connection::resetState() { current_response_.reset(); parser_.reset(); current_callback_ = HttpClient::RequestHandler(); + close_callback_ = HttpClient::CloseHandler(); } void @@ -529,8 +530,8 @@ Connection::doTransaction(const HttpRequestPtr& request, // data over this socket, when the peer may close the connection. In this // case we'll need to re-transmit but we don't handle it here. if (socket_.getASIOSocket().is_open() && !socket_.isUsable()) { - if (close_callback) { - close_callback(socket_.getNative()); + if (close_callback_) { + close_callback_(socket_.getNative()); } socket_.close(); }