#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>
#include <functional>
using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::util;
namespace ph = std::placeholders;
namespace {
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 {
void
HttpConnection::shutdownCallback(const boost::system::error_code&) {
+ if (use_external_) {
+ IfaceMgr::instance().deleteExternalSocket(tls_socket_->getNative());
+ closeWatchSocket();
+ }
+
tls_socket_->close();
}
HttpConnection::shutdown() {
request_timer_.cancel();
if (tcp_socket_) {
+ if (use_external_) {
+ IfaceMgr::instance().deleteExternalSocket(tcp_socket_->getNative());
+ closeWatchSocket();
+ }
tcp_socket_->close();
return;
}
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;
}
}
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());
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());
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 {
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())
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.
#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>
/// @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_;
/// @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