diff --git a/src/lib/tcp/tcp_connection.cc b/src/lib/tcp/tcp_connection.cc index bd46af005c..3de0947cb1 100644 --- a/src/lib/tcp/tcp_connection.cc +++ b/src/lib/tcp/tcp_connection.cc @@ -43,8 +43,10 @@ TcpConnection::TcpConnection(asiolink::IOService& io_service, const TlsContextPtr& tls_context, TcpConnectionPool& connection_pool, const TcpConnectionAcceptorCallback& callback, + const long request_timeout, const long idle_timeout) : request_timer_(io_service), + request_timeout_(request_timeout), tls_context_(tls_context), idle_timeout_(idle_timeout), tcp_socket_(), @@ -211,16 +213,15 @@ TcpConnection::doHandshake() { } void -TcpConnection::doRead(TcpRequestPtr /* request */) { -#if 0 +TcpConnection::doRead(TcpRequestPtr request) { try { TCPEndpoint endpoint; - // Transaction hasn't been created if we are starting to read the + // Request hasn't been created if we are starting to read the // new request. - if (!transaction) { - transaction = Transaction::create(response_creator_); - recordParameters(transaction->getRequest()); + if (!request) { + request.reset(new TcpRequest()); + // recordParameters(transaction->getRequest()); } // Create instance of the callback. It is safe to pass the local instance @@ -228,27 +229,25 @@ TcpConnection::doRead(TcpRequestPtr /* request */) { // as needed. SocketCallback cb(std::bind(&TcpConnection::socketReadCallback, shared_from_this(), - transaction, + request, ph::_1, // error - ph::_2)); //bytes_transferred + ph::_2)); // bytes_transferred if (tcp_socket_) { - tcp_socket_->asyncReceive(static_cast(transaction->getInputBufData()), - transaction->getInputBufSize(), + tcp_socket_->asyncReceive(static_cast(request->getInputBufData()), + request->getInputBufSize(), 0, &endpoint, cb); return; } + if (tls_socket_) { - tls_socket_->asyncReceive(static_cast(transaction->getInputBufData()), - transaction->getInputBufSize(), + tls_socket_->asyncReceive(static_cast(request->getInputBufData()), + request->getInputBufSize(), 0, &endpoint, cb); return; } } catch (...) { stopThisConnection(); } -#else - isc_throw(NotImplemented, "TcpConnection::doRead()"); -#endif } void diff --git a/src/lib/tcp/tcp_connection.h b/src/lib/tcp/tcp_connection.h index 1d24cb9135..3ad0678ebd 100644 --- a/src/lib/tcp/tcp_connection.h +++ b/src/lib/tcp/tcp_connection.h @@ -22,8 +22,26 @@ namespace isc { namespace tcp { -/// @todo TKM these are place holders while I think output how it should work -typedef util::InputBuffer TcpRequest; +class TcpRequest { +public: + /// @brief Constructor. + TcpRequest(){}; + + /// @brief Returns pointer to the first byte of the input buffer. + char* getInputBufData() { + return (input_buf_.data()); + } + + /// @brief Returns input buffer size (i.e. capacity). + size_t getInputBufSize() const { + return (input_buf_.size()); + } + +private: + /// @brief Buffer for received data. + std::array input_buf_; +}; + typedef boost::shared_ptr TcpRequestPtr; typedef util::OutputBuffer TcpResponse; @@ -107,6 +125,7 @@ public: const asiolink::TlsContextPtr& tls_context, TcpConnectionPool& connection_pool, const TcpConnectionAcceptorCallback& callback, + const long request_timeout, const long idle_timeout); /// @brief Destructor. diff --git a/src/lib/tcp/tcp_listener.cc b/src/lib/tcp/tcp_listener.cc index 23f1504a97..e535270e10 100644 --- a/src/lib/tcp/tcp_listener.cc +++ b/src/lib/tcp/tcp_listener.cc @@ -18,9 +18,11 @@ TcpListener::TcpListener(IOService& io_service, const IOAddress& server_address, const unsigned short server_port, const TlsContextPtr& tls_context, + const RequestTimeout& request_timeout, const IdleTimeout& idle_timeout) : io_service_(io_service), tls_context_(tls_context), acceptor_(), - endpoint_(), connections_(), idle_timeout_(idle_timeout.value_) { + endpoint_(), connections_(), request_timeout_(request_timeout.value_), + idle_timeout_(idle_timeout.value_) { // Create the TCP or TLS acceptor. if (!tls_context) { @@ -37,6 +39,12 @@ TcpListener::TcpListener(IOService& io_service, << server_address << ":" << server_port); } + // Request timeout is signed and must be greater than 0. + if (request_timeout_ <= 0) { + isc_throw(TcpListenerError, "Invalid desired TCP request timeout " + << request_timeout_); + } + // Idle persistent connection timeout is signed and must be greater than 0. if (idle_timeout_ <= 0) { isc_throw(TcpListenerError, "Invalid desired TCP idle persistent connection" @@ -99,8 +107,8 @@ TcpListener::createConnection(const TcpConnectionAcceptorCallback& /* callback * /// @todo TKM - I think what we want is to define TcpConnectionFactory /// instead of a response creator. Let TcpListener accept a factory /// for that, which is used here to create for BLQ an LeaseQueryConnection - return (connection_factory_(io_service_, acceptor_, tls_context_, - connections_, callback, idle_timeout_)); + return (connectionFactory(io_service_, acceptor_, tls_context_, + connections_, callback, request_timeout_, idle_timeout_)); #endif } diff --git a/src/lib/tcp/tcp_listener.h b/src/lib/tcp/tcp_listener.h index c8401f41b8..262fac6427 100644 --- a/src/lib/tcp/tcp_listener.h +++ b/src/lib/tcp/tcp_listener.h @@ -60,6 +60,8 @@ public: /// @param server_address Address on which the TCP service should run. /// @param server_port Port number on which the TCP service should run. /// @param tls_context TLS context. + /// @param request_timeout Timeout maximum amount of time allotted for + /// a request to be processed. /// @param idle_timeout Timeout after which an idle persistent TCP /// connection is closed by the server. /// @@ -69,6 +71,7 @@ public: const asiolink::IOAddress& server_address, const unsigned short server_port, const asiolink::TlsContextPtr& tls_context, + const RequestTimeout& request_timeout, const IdleTimeout& idle_timeout); /// @brief Virtual destructor. @@ -138,6 +141,9 @@ protected: /// @brief Pool of active connections. TcpConnectionPool connections_; + /// @brief Maximum amount of time request to be processed. + long request_timeout_; + /// @brief Timeout after which idle persistent connection is closed by /// the server. long idle_timeout_; diff --git a/src/lib/tcp/tests/tcp_listener_unittests.cc b/src/lib/tcp/tests/tcp_listener_unittests.cc index df9d836702..1b4e3e0596 100644 --- a/src/lib/tcp/tests/tcp_listener_unittests.cc +++ b/src/lib/tcp/tests/tcp_listener_unittests.cc @@ -64,9 +64,10 @@ public: const IOAddress& server_address, const unsigned short server_port, const TlsContextPtr& tls_context, + const RequestTimeout& request_timeout, const IdleTimeout& idle_timeout) : TcpListener(io_service, server_address, server_port, - tls_context, idle_timeout) { + tls_context, request_timeout, idle_timeout) { } protected: @@ -82,7 +83,7 @@ protected: TcpConnectionPtr conn(new TcpConnection(io_service_, acceptor_, tls_context_, connections_, - callback, idle_timeout_)); + callback, request_timeout_, idle_timeout_)); return (conn); } }; @@ -246,16 +247,14 @@ public: std::list clients_; }; -// This test verifies that HTTP connection can be established and used to -// transmit HTTP request and receive a response. -TEST_F(TcpListenerTest, listen) { - const std::string request = "POST /foo/bar HTTP/1.1\r\n" - "Content-Type: application/json\r\n" - "Content-Length: 3\r\n\r\n" - "{ }"; +// This test verifies that A TCP connection can be established and used to +// transmit a streamed request and receive a streamed response. +TEST_F(TcpListenerTest, DISABLED_listen) { + const std::string request = "inbound message request"; - TcpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT, - TlsContextPtr(), TcpListener::IdleTimeout(IDLE_TIMEOUT)); + TcpTestListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT, + TlsContextPtr(), TcpListener::RequestTimeout(REQUEST_TIMEOUT), + TcpListener::IdleTimeout(IDLE_TIMEOUT)); ASSERT_NO_THROW(listener.start()); ASSERT_EQ(SERVER_ADDRESS, listener.getLocalAddress().toText()); ASSERT_EQ(SERVER_PORT, listener.getLocalPort());