From c5b655c954d1eedcc3c255e2011182534eb626f4 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Tue, 19 Feb 2019 09:36:13 -0800 Subject: [PATCH] basic_stream connects are members --- doc/qbk/quickref.xml | 2 - .../async-ssl/http_client_async_ssl.cpp | 3 +- .../http/client/async/http_client_async.cpp | 3 +- .../client/coro-ssl/http_client_coro_ssl.cpp | 2 +- example/http/client/coro/http_client_coro.cpp | 2 +- example/http/client/crawl/http_crawl.cpp | 3 +- .../client/sync-ssl/http_client_sync_ssl.cpp | 2 +- example/http/client/sync/http_client_sync.cpp | 2 +- .../async-ssl/websocket_client_async_ssl.cpp | 3 +- .../client/async/websocket_client_async.cpp | 3 +- .../coro-ssl/websocket_client_coro_ssl.cpp | 2 +- .../client/coro/websocket_client_coro.cpp | 2 +- include/boost/beast/core/basic_stream.hpp | 1213 ++++++++--------- .../boost/beast/core/detail/stream_base.hpp | 3 - .../boost/beast/core/impl/basic_stream.hpp | 466 +++---- test/beast/core/basic_stream.cpp | 35 +- test/doc/websocket_snippets.cpp | 2 +- 17 files changed, 832 insertions(+), 916 deletions(-) diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml index ed537b4a..96b8c780 100644 --- a/doc/qbk/quickref.xml +++ b/doc/qbk/quickref.xml @@ -64,12 +64,10 @@ Functions allocate_stable 🞲 - async_connect 🞲 beast_close_socket 🞲 bind_front_handler 🞲 bind_handler close_socket 🞲 - connect 🞲 generic_category get_lowest_layer 🞲 iequals diff --git a/example/http/client/async-ssl/http_client_async_ssl.cpp b/example/http/client/async-ssl/http_client_async_ssl.cpp index 563349ae..4f56f326 100644 --- a/example/http/client/async-ssl/http_client_async_ssl.cpp +++ b/example/http/client/async-ssl/http_client_async_ssl.cpp @@ -103,8 +103,7 @@ public: beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); // Make the connection on the IP address we get from a lookup - beast::async_connect( - beast::get_lowest_layer(stream_), + beast::get_lowest_layer(stream_).async_connect( results, beast::bind_front_handler( &session::on_connect, diff --git a/example/http/client/async/http_client_async.cpp b/example/http/client/async/http_client_async.cpp index c1a58935..4a28dd33 100644 --- a/example/http/client/async/http_client_async.cpp +++ b/example/http/client/async/http_client_async.cpp @@ -91,8 +91,7 @@ public: stream_.expires_after(std::chrono::seconds(30)); // Make the connection on the IP address we get from a lookup - beast::async_connect( - stream_, + stream_.async_connect( results, beast::bind_front_handler( &session::on_connect, diff --git a/example/http/client/coro-ssl/http_client_coro_ssl.cpp b/example/http/client/coro-ssl/http_client_coro_ssl.cpp index 6157e5b7..34d65e07 100644 --- a/example/http/client/coro-ssl/http_client_coro_ssl.cpp +++ b/example/http/client/coro-ssl/http_client_coro_ssl.cpp @@ -74,7 +74,7 @@ do_session( beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(30)); // Make the connection on the IP address we get from a lookup - beast::async_connect(get_lowest_layer(stream), results, yield[ec]); + get_lowest_layer(stream).async_connect(results, yield[ec]); if(ec) return fail(ec, "connect"); diff --git a/example/http/client/coro/http_client_coro.cpp b/example/http/client/coro/http_client_coro.cpp index b415a990..ba2445b2 100644 --- a/example/http/client/coro/http_client_coro.cpp +++ b/example/http/client/coro/http_client_coro.cpp @@ -61,7 +61,7 @@ do_session( stream.expires_after(std::chrono::seconds(30)); // Make the connection on the IP address we get from a lookup - beast::async_connect(stream, results, yield[ec]); + stream.async_connect(results, yield[ec]); if(ec) return fail(ec, "connect"); diff --git a/example/http/client/crawl/http_crawl.cpp b/example/http/client/crawl/http_crawl.cpp index b4e33446..cd1f983b 100644 --- a/example/http/client/crawl/http_crawl.cpp +++ b/example/http/client/crawl/http_crawl.cpp @@ -223,8 +223,7 @@ public: stream_.expires_after(std::chrono::seconds(10)); // Make the connection on the IP address we get from a lookup - beast::async_connect( - stream_, + stream_.async_connect( results, beast::bind_front_handler( &worker::on_connect, diff --git a/example/http/client/sync-ssl/http_client_sync_ssl.cpp b/example/http/client/sync-ssl/http_client_sync_ssl.cpp index 28728904..62610124 100644 --- a/example/http/client/sync-ssl/http_client_sync_ssl.cpp +++ b/example/http/client/sync-ssl/http_client_sync_ssl.cpp @@ -80,7 +80,7 @@ int main(int argc, char** argv) auto const results = resolver.resolve(host, port); // Make the connection on the IP address we get from a lookup - beast::connect(beast::get_lowest_layer(stream), results); + beast::get_lowest_layer(stream).connect(results); // Perform the SSL handshake stream.handshake(ssl::stream_base::client); diff --git a/example/http/client/sync/http_client_sync.cpp b/example/http/client/sync/http_client_sync.cpp index bef72344..0b04636c 100644 --- a/example/http/client/sync/http_client_sync.cpp +++ b/example/http/client/sync/http_client_sync.cpp @@ -60,7 +60,7 @@ int main(int argc, char** argv) auto const results = resolver.resolve(host, port); // Make the connection on the IP address we get from a lookup - beast::connect(stream, results); + stream.connect(results); // Set up an HTTP GET request message http::request req{http::verb::get, target, version}; diff --git a/example/websocket/client/async-ssl/websocket_client_async_ssl.cpp b/example/websocket/client/async-ssl/websocket_client_async_ssl.cpp index 1f3e748a..064ae324 100644 --- a/example/websocket/client/async-ssl/websocket_client_async_ssl.cpp +++ b/example/websocket/client/async-ssl/websocket_client_async_ssl.cpp @@ -92,8 +92,7 @@ public: beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30)); // Make the connection on the IP address we get from a lookup - beast::async_connect( - beast::get_lowest_layer(ws_), + beast::get_lowest_layer(ws_).async_connect( results, beast::bind_front_handler( &session::on_connect, diff --git a/example/websocket/client/async/websocket_client_async.cpp b/example/websocket/client/async/websocket_client_async.cpp index 124b25c9..4c066ad0 100644 --- a/example/websocket/client/async/websocket_client_async.cpp +++ b/example/websocket/client/async/websocket_client_async.cpp @@ -86,8 +86,7 @@ public: beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30)); // Make the connection on the IP address we get from a lookup - beast::async_connect( - beast::get_lowest_layer(ws_), + beast::get_lowest_layer(ws_).async_connect( results, beast::bind_front_handler( &session::on_connect, diff --git a/example/websocket/client/coro-ssl/websocket_client_coro_ssl.cpp b/example/websocket/client/coro-ssl/websocket_client_coro_ssl.cpp index cd6ff392..fa6b40d3 100644 --- a/example/websocket/client/coro-ssl/websocket_client_coro_ssl.cpp +++ b/example/websocket/client/coro-ssl/websocket_client_coro_ssl.cpp @@ -67,7 +67,7 @@ do_session( beast::get_lowest_layer(ws).expires_after(std::chrono::seconds(30)); // Make the connection on the IP address we get from a lookup - beast::async_connect(beast::get_lowest_layer(ws), results, yield[ec]); + beast::get_lowest_layer(ws).async_connect(results, yield[ec]); if(ec) return fail(ec, "connect"); diff --git a/example/websocket/client/coro/websocket_client_coro.cpp b/example/websocket/client/coro/websocket_client_coro.cpp index 5c2c2c3f..776914bf 100644 --- a/example/websocket/client/coro/websocket_client_coro.cpp +++ b/example/websocket/client/coro/websocket_client_coro.cpp @@ -60,7 +60,7 @@ do_session( beast::get_lowest_layer(ws).expires_after(std::chrono::seconds(30)); // Make the connection on the IP address we get from a lookup - beast::async_connect(ws.next_layer(), results, yield[ec]); + beast::get_lowest_layer(ws).async_connect(results, yield[ec]); if(ec) return fail(ec, "connect"); diff --git a/include/boost/beast/core/basic_stream.hpp b/include/boost/beast/core/basic_stream.hpp index 2417b48b..ab593c33 100644 --- a/include/boost/beast/core/basic_stream.hpp +++ b/include/boost/beast/core/basic_stream.hpp @@ -188,8 +188,6 @@ namespace beast { @see - @li @ref beast::connect, @ref beast::async_connect - @li [P1322R0] Networking TS enhancement to enable custom I/O executors. */ template< @@ -224,11 +222,6 @@ private: static_assert(net::is_executor::value, "Executor requirements not met"); -// friend class template declaration in a class template is ignored -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88672 -#if BOOST_WORKAROUND(BOOST_GCC, > 0) -public: -#endif struct impl_type : boost::enable_shared_from_this , boost::empty_value @@ -274,9 +267,6 @@ public: void reset(); // set timeouts to never void close(); // cancel everything }; -#if BOOST_WORKAROUND(BOOST_GCC, > 0) -private: -#endif // We use shared ownership for the state so it can // outlive the destruction of the stream_socket object, @@ -284,16 +274,6 @@ private: // but the implementation is still waiting on a timer. boost::shared_ptr impl_; - template class async_op; - - template - friend class detail::basic_stream_connect_op; - - template - friend class basic_stream; - - struct run_async_op; - struct timeout_handler; struct ops; @@ -406,7 +386,7 @@ public: The timer applies collectively to any asynchronous reads or writes initiated after the expiration is set, until the - expiration is set again. A call to @ref beast::async_connect + expiration is set again. A call to @ref async_connect counts as both a read and a write. @param expiry_time The amount of time after which a logical @@ -429,7 +409,7 @@ public: The timer applies collectively to any asynchronous reads or writes initiated after the expiration is set, until the - expiration is set again. A call to @ref beast::async_connect + expiration is set again. A call to @ref async_connect counts as both a read and a write. @param expiry_time The time point after which a logical @@ -484,7 +464,6 @@ public: This function is used to connect the underlying socket to the specified remote endpoint. The function call will block until the connection is successfully made or an error occurs. - The underlying socket is automatically opened if needed. An automatically opened socket is not returned to the closed state upon failure. @@ -498,7 +477,7 @@ public: void connect(endpoint_type const& ep) { - impl_->socket.connect(ep); + socket().connect(ep); } /** Connect the stream to the specified endpoint. @@ -506,7 +485,6 @@ public: This function is used to connect the underlying socket to the specified remote endpoint. The function call will block until the connection is successfully made or an error occurs. - The underlying socket is automatically opened if needed. An automatically opened socket is not returned to the closed state upon failure. @@ -520,7 +498,332 @@ public: void connect(endpoint_type const& ep, error_code& ec) { - impl_->socket.connect(ep, ec); + socket().connect(ep, ec); + } + + /** Establishes a connection by trying each endpoint in a sequence. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed operation, is implemented + in terms of calls to the underlying socket's `connect` function. + + @param endpoints A sequence of endpoints. + + @returns The successfully connected endpoint. + + @throws system_error Thrown on failure. If the sequence is + empty, the associated error code is `net::error::not_found`. + Otherwise, contains the error from the last connection attempt. + */ + template::value>::type + #endif + > + typename Protocol::endpoint + connect(EndpointSequence const& endpoints) + { + return net::connect(socket(), endpoints); + } + + /** Establishes a connection by trying each endpoint in a sequence. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed operation, is implemented + in terms of calls to the underlying socket's `connect` function. + + @param endpoints A sequence of endpoints. + + @param ec Set to indicate what error occurred, if any. If the sequence is + empty, set to `net::error::not_found`. Otherwise, contains the error + from the last connection attempt. + + @returns On success, the successfully connected endpoint. Otherwise, a + default-constructed endpoint. + */ + template::value>::type + #endif + > + typename Protocol::endpoint + connect( + EndpointSequence const& endpoints, + error_code& ec + ) + { + return net::connect(socket(), endpoints, ec); + } + + /** Establishes a connection by trying each endpoint in a sequence. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed operation, is implemented + in terms of calls to the underlying socket's `connect` function. + + @param begin An iterator pointing to the start of a sequence of endpoints. + + @param end An iterator pointing to the end of a sequence of endpoints. + + @returns An iterator denoting the successfully connected endpoint. + + @throws system_error Thrown on failure. If the sequence is + empty, the associated error code is `net::error::not_found`. + Otherwise, contains the error from the last connection attempt. + */ + template + Iterator + connect( + Iterator begin, Iterator end) + { + return net::connect(socket(), begin, end); + } + + /** Establishes a connection by trying each endpoint in a sequence. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed operation, is implemented + in terms of calls to the underlying socket's `connect` function. + + @param begin An iterator pointing to the start of a sequence of endpoints. + + @param end An iterator pointing to the end of a sequence of endpoints. + + @param ec Set to indicate what error occurred, if any. If the sequence is + empty, set to boost::asio::error::not_found. Otherwise, contains the error + from the last connection attempt. + + @returns On success, an iterator denoting the successfully connected + endpoint. Otherwise, the end iterator. + */ + template + Iterator + connect( + Iterator begin, Iterator end, + error_code& ec) + { + return net::connect(socket(), begin, end, ec); + } + + /** Establishes a connection by trying each endpoint in a sequence. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed operation, is implemented + in terms of calls to the underlying socket's `connect` function. + + @param endpoints A sequence of endpoints. + + @param connect_condition A function object that is called prior to each + connection attempt. The signature of the function object must be: + @code + bool connect_condition( + error_code const& ec, + typename Protocol::endpoint const& next); + @endcode + The @c ec parameter contains the result from the most recent connect + operation. Before the first connection attempt, @c ec is always set to + indicate success. The @c next parameter is the next endpoint to be tried. + The function object should return true if the next endpoint should be tried, + and false if it should be skipped. + + @returns The successfully connected endpoint. + + @throws boost::system::system_error Thrown on failure. If the sequence is + empty, the associated error code is `net::error::not_found`. + Otherwise, contains the error from the last connection attempt. + */ + template< + class EndpointSequence, class ConnectCondition + #if ! BOOST_BEAST_DOXYGEN + ,class = typename std::enable_if< + net::is_endpoint_sequence< + EndpointSequence>::value>::type + #endif + > + typename Protocol::endpoint + connect( + EndpointSequence const& endpoints, + ConnectCondition connect_condition + ) + { + return net::connect(socket(), endpoints, connect_condition); + } + + /** Establishes a connection by trying each endpoint in a sequence. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed operation, is implemented + in terms of calls to the underlying socket's `connect` function. + + @param endpoints A sequence of endpoints. + + @param connect_condition A function object that is called prior to each + connection attempt. The signature of the function object must be: + @code + bool connect_condition( + error_code const& ec, + typename Protocol::endpoint const& next); + @endcode + The @c ec parameter contains the result from the most recent connect + operation. Before the first connection attempt, @c ec is always set to + indicate success. The @c next parameter is the next endpoint to be tried. + The function object should return true if the next endpoint should be tried, + and false if it should be skipped. + + @param ec Set to indicate what error occurred, if any. If the sequence is + empty, set to `net::error::not_found`. Otherwise, contains the error + from the last connection attempt. + + @returns On success, the successfully connected endpoint. Otherwise, a + default-constructed endpoint. + */ + template< + class EndpointSequence, class ConnectCondition + #if ! BOOST_BEAST_DOXYGEN + ,class = typename std::enable_if< + net::is_endpoint_sequence< + EndpointSequence>::value>::type + #endif + > + typename Protocol::endpoint + connect( + EndpointSequence const& endpoints, + ConnectCondition connect_condition, + error_code& ec) + { + return net::connect(socket(), endpoints, connect_condition, ec); + } + + /** Establishes a connection by trying each endpoint in a sequence. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed operation, is implemented + in terms of calls to the underlying socket's `connect` function. + + @param begin An iterator pointing to the start of a sequence of endpoints. + + @param end An iterator pointing to the end of a sequence of endpoints. + + @param connect_condition A function object that is called prior to each + connection attempt. The signature of the function object must be: + @code + bool connect_condition( + error_code const& ec, + typename Protocol::endpoint const& next); + @endcode + The @c ec parameter contains the result from the most recent connect + operation. Before the first connection attempt, @c ec is always set to + indicate success. The @c next parameter is the next endpoint to be tried. + The function object should return true if the next endpoint should be tried, + and false if it should be skipped. + + @returns An iterator denoting the successfully connected endpoint. + + @throws boost::system::system_error Thrown on failure. If the sequence is + empty, the associated @c error_code is `net::error::not_found`. + Otherwise, contains the error from the last connection attempt. + */ + template< + class Iterator, class ConnectCondition> + Iterator + connect( + Iterator begin, Iterator end, + ConnectCondition connect_condition) + { + return net::connect(socket(), begin, end, connect_condition); + } + + /** Establishes a connection by trying each endpoint in a sequence. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed operation, is implemented + in terms of calls to the underlying socket's `connect` function. + + @param begin An iterator pointing to the start of a sequence of endpoints. + + @param end An iterator pointing to the end of a sequence of endpoints. + + @param connect_condition A function object that is called prior to each + connection attempt. The signature of the function object must be: + @code + bool connect_condition( + error_code const& ec, + typename Protocol::endpoint const& next); + @endcode + The @c ec parameter contains the result from the most recent connect + operation. Before the first connection attempt, @c ec is always set to + indicate success. The @c next parameter is the next endpoint to be tried. + The function object should return true if the next endpoint should be tried, + and false if it should be skipped. + + @param ec Set to indicate what error occurred, if any. If the sequence is + empty, set to `net::error::not_found`. Otherwise, contains the error + from the last connection attempt. + + @returns On success, an iterator denoting the successfully connected + endpoint. Otherwise, the end iterator. + */ + template< + class Iterator, class ConnectCondition> + Iterator + connect( + Iterator begin, Iterator end, + ConnectCondition connect_condition, + error_code& ec) + { + return net::connect(socket(), begin, end, connect_condition, ec); } /** Connect the stream to the specified endpoint asynchronously. @@ -528,7 +831,6 @@ public: This function is used to asynchronously connect the underlying socket to the specified remote endpoint. The function call always returns immediately. - The underlying socket is automatically opened if needed. An automatically opened socket is not returned to the closed state upon failure. @@ -562,6 +864,254 @@ public: endpoint_type const& ep, ConnectHandler&& handler); + /** Establishes a connection by trying each endpoint in a sequence asynchronously. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed asynchronous operation, is + implemented in terms of calls to the underlying socket's `async_connect` + function. + + If the timeout timer expires while the operation is outstanding, + the current connection attempt will be canceled and the completion + handler will be invoked with the error @ref error::timeout. + + @param endpoints A sequence of endpoints. This this object must meet + the requirements of EndpointSequence. + + @param handler The handler to be called when the connect operation + completes. Ownership of the handler may be transferred. The function + signature of the handler must be: + @code + void handler( + // Result of operation. if the sequence is empty, set to + // net::error::not_found. Otherwise, contains the + // error from the last connection attempt. + error_code const& error, + + // On success, the successfully connected endpoint. + // Otherwise, a default-constructed endpoint. + typename Protocol::endpoint const& endpoint + ); + @endcode + Regardless of whether the asynchronous operation completes immediately + or not, the handler will not be invoked from within this function. + Invocation of the handler will be performed in a manner equivalent + to using `net::post`. + */ + template< + class EndpointSequence, + class RangeConnectHandler + #if ! BOOST_BEAST_DOXYGEN + ,class = typename std::enable_if< + net::is_endpoint_sequence< + EndpointSequence>::value>::type + #endif + > + BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (error_code, typename Protocol::endpoint)) + async_connect( + EndpointSequence const& endpoints, + RangeConnectHandler&& handler); + + /** Establishes a connection by trying each endpoint in a sequence asynchronously. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed asynchronous operation, is + implemented in terms of calls to the underlying socket's `async_connect` + function. + + If the timeout timer expires while the operation is outstanding, + the current connection attempt will be canceled and the completion + handler will be invoked with the error @ref error::timeout. + + @param endpoints A sequence of endpoints. This this object must meet + the requirements of EndpointSequence. + + @param connect_condition A function object that is called prior to each + connection attempt. The signature of the function object must be: + @code + bool connect_condition( + error_code const& ec, + typename Protocol::endpoint const& next); + @endcode + The @c ec parameter contains the result from the most recent connect + operation. Before the first connection attempt, @c ec is always set to + indicate success. The @c next parameter is the next endpoint to be tried. + The function object should return true if the next endpoint should be tried, + and false if it should be skipped. + + @param handler The handler to be called when the connect operation + completes. Ownership of the handler may be transferred. The function + signature of the handler must be: + @code + void handler( + // Result of operation. if the sequence is empty, set to + // net::error::not_found. Otherwise, contains the + // error from the last connection attempt. + error_code const& error, + + // On success, the successfully connected endpoint. + // Otherwise, a default-constructed endpoint. + typename Protocol::endpoint const& endpoint + ); + @endcode + Regardless of whether the asynchronous operation completes immediately + or not, the handler will not be invoked from within this function. + Invocation of the handler will be performed in a manner equivalent + to using `net::post`. + + @par Example + The following connect condition function object can be used to output + information about the individual connection attempts: + @code + struct my_connect_condition + { + bool operator()( + error_code const& ec, + net::ip::tcp::endpoint const& next) + { + if (ec) + std::cout << "Error: " << ec.message() << std::endl; + std::cout << "Trying: " << next << std::endl; + return true; + } + }; + @endcode + */ + template< + class EndpointSequence, + class ConnectCondition, + class RangeConnectHandler + #if ! BOOST_BEAST_DOXYGEN + ,class = typename std::enable_if< + net::is_endpoint_sequence< + EndpointSequence>::value>::type + #endif + > + BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (error_code, typename Protocol::endpoint)) + async_connect( + EndpointSequence const& endpoints, + ConnectCondition connect_condition, + RangeConnectHandler&& handler); + + /** Establishes a connection by trying each endpoint in a sequence asynchronously. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The underlying socket is automatically opened if needed. + An automatically opened socket is not returned to the + closed state upon failure. + + The algorithm, known as a composed asynchronous operation, is + implemented in terms of calls to the underlying socket's `async_connect` + function. + + If the timeout timer expires while the operation is outstanding, + the current connection attempt will be canceled and the completion + handler will be invoked with the error @ref error::timeout. + + @param begin An iterator pointing to the start of a sequence of endpoints. + + @param end An iterator pointing to the end of a sequence of endpoints. + + @param handler The handler to be called when the connect operation + completes. Ownership of the handler may be transferred. The function + signature of the handler must be: + @code + void handler( + // Result of operation. if the sequence is empty, set to + // net::error::not_found. Otherwise, contains the + // error from the last connection attempt. + error_code const& error, + + // On success, an iterator denoting the successfully + // connected endpoint. Otherwise, the end iterator. + Iterator iterator + ); + @endcode + Regardless of whether the asynchronous operation completes immediately + or not, the handler will not be invoked from within this function. + Invocation of the handler will be performed in a manner equivalent + to using `net::post`. + */ + template< + class Iterator, + class IteratorConnectHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (error_code, Iterator)) + async_connect( + Iterator begin, Iterator end, + IteratorConnectHandler&& handler); + + /** Establishes a connection by trying each endpoint in a sequence asynchronously. + + This function attempts to connect the stream to one of a sequence of + endpoints by trying each endpoint until a connection is successfully + established. + The algorithm, known as a composed asynchronous operation, is + implemented in terms of calls to the underlying socket's `async_connect` + function. + + If the timeout timer expires while the operation is outstanding, + the current connection attempt will be canceled and the completion + handler will be invoked with the error @ref error::timeout. + + @param begin An iterator pointing to the start of a sequence of endpoints. + + @param end An iterator pointing to the end of a sequence of endpoints. + + @param connect_condition A function object that is called prior to each + connection attempt. The signature of the function object must be: + @code + bool connect_condition( + error_code const& ec, + Iterator next); + @endcode + @param handler The handler to be called when the connect operation + completes. Ownership of the handler may be transferred. The function + signature of the handler must be: + @code + void handler( + // Result of operation. if the sequence is empty, set to + // net::error::not_found. Otherwise, contains the + // error from the last connection attempt. + error_code const& error, + + // On success, an iterator denoting the successfully + // connected endpoint. Otherwise, the end iterator. + Iterator iterator + ); + @endcode + Regardless of whether the asynchronous operation completes immediately + or not, the handler will not be invoked from within this function. + Invocation of the handler will be performed in a manner equivalent + to using `net::post`. + */ + template< + class Iterator, + class ConnectCondition, + class IteratorConnectHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (error_code, Iterator)) + async_connect( + Iterator begin, Iterator end, + ConnectCondition connect_condition, + IteratorConnectHandler&& handler); + //-------------------------------------------------------------------------- /** Read some data. @@ -797,615 +1347,6 @@ public: WriteHandler&& handler); }; -//------------------------------------------------------------------------------ - -/** Establishes a connection by trying each endpoint in a sequence. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed operation, is implemented - in terms of calls to the underlying socket's `connect` function. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param endpoints A sequence of endpoints. - - @returns The successfully connected endpoint. - - @throws system_error Thrown on failure. If the sequence is - empty, the associated error code is `net::error::not_found`. - Otherwise, contains the error from the last connection attempt. -*/ -template< - class Protocol, class Executor, - class EndpointSequence -#if ! BOOST_BEAST_DOXYGEN - ,class = typename std::enable_if< - net::is_endpoint_sequence< - EndpointSequence>::value>::type -#endif -> -typename Protocol::endpoint -connect( - basic_stream& stream, - EndpointSequence const& endpoints -) -{ - return net::connect(stream.socket(), endpoints); -} - -/** Establishes a connection by trying each endpoint in a sequence. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed operation, is implemented - in terms of calls to the underlying socket's `connect` function. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param endpoints A sequence of endpoints. - - @param ec Set to indicate what error occurred, if any. If the sequence is - empty, set to `net::error::not_found`. Otherwise, contains the error - from the last connection attempt. - - @returns On success, the successfully connected endpoint. Otherwise, a - default-constructed endpoint. -*/ -template< - class Protocol, class Executor, - class EndpointSequence -#if ! BOOST_BEAST_DOXYGEN - ,class = typename std::enable_if< - net::is_endpoint_sequence< - EndpointSequence>::value>::type -#endif -> -typename Protocol::endpoint -connect( - basic_stream& stream, - EndpointSequence const& endpoints, - error_code& ec -) -{ - return net::connect(stream.socket(), endpoints, ec); -} - -/** Establishes a connection by trying each endpoint in a sequence. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed operation, is implemented - in terms of calls to the underlying socket's `connect` function. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param begin An iterator pointing to the start of a sequence of endpoints. - - @param end An iterator pointing to the end of a sequence of endpoints. - - @returns An iterator denoting the successfully connected endpoint. - - @throws system_error Thrown on failure. If the sequence is - empty, the associated error code is `net::error::not_found`. - Otherwise, contains the error from the last connection attempt. -*/ -template< - class Protocol, class Executor, - class Iterator> -Iterator -connect( - basic_stream& stream, - Iterator begin, Iterator end) -{ - return net::connect(stream.socket(), begin, end); -} - -/** Establishes a connection by trying each endpoint in a sequence. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed operation, is implemented - in terms of calls to the underlying socket's `connect` function. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param begin An iterator pointing to the start of a sequence of endpoints. - - @param end An iterator pointing to the end of a sequence of endpoints. - - @param ec Set to indicate what error occurred, if any. If the sequence is - empty, set to boost::asio::error::not_found. Otherwise, contains the error - from the last connection attempt. - - @returns On success, an iterator denoting the successfully connected - endpoint. Otherwise, the end iterator. -*/ -template< - class Protocol, class Executor, - class Iterator> -Iterator -connect( - basic_stream& stream, - Iterator begin, Iterator end, - error_code& ec) -{ - return net::connect(stream.socket(), begin, end, ec); -} - -/** Establishes a connection by trying each endpoint in a sequence. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed operation, is implemented - in terms of calls to the underlying socket's `connect` function. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param endpoints A sequence of endpoints. - - @param connect_condition A function object that is called prior to each - connection attempt. The signature of the function object must be: - @code - bool connect_condition( - error_code const& ec, - typename Protocol::endpoint const& next); - @endcode - The @c ec parameter contains the result from the most recent connect - operation. Before the first connection attempt, @c ec is always set to - indicate success. The @c next parameter is the next endpoint to be tried. - The function object should return true if the next endpoint should be tried, - and false if it should be skipped. - - @returns The successfully connected endpoint. - - @throws boost::system::system_error Thrown on failure. If the sequence is - empty, the associated error code is `net::error::not_found`. - Otherwise, contains the error from the last connection attempt. -*/ -template< - class Protocol, class Executor, - class EndpointSequence, class ConnectCondition -#if ! BOOST_BEAST_DOXYGEN - ,class = typename std::enable_if< - net::is_endpoint_sequence< - EndpointSequence>::value>::type -#endif -> -typename Protocol::endpoint -connect( - basic_stream& stream, - EndpointSequence const& endpoints, - ConnectCondition connect_condition -) -{ - return net::connect(stream.socket(), endpoints, connect_condition); -} - -/** Establishes a connection by trying each endpoint in a sequence. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed operation, is implemented - in terms of calls to the underlying socket's `connect` function. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param endpoints A sequence of endpoints. - - @param connect_condition A function object that is called prior to each - connection attempt. The signature of the function object must be: - @code - bool connect_condition( - error_code const& ec, - typename Protocol::endpoint const& next); - @endcode - The @c ec parameter contains the result from the most recent connect - operation. Before the first connection attempt, @c ec is always set to - indicate success. The @c next parameter is the next endpoint to be tried. - The function object should return true if the next endpoint should be tried, - and false if it should be skipped. - - @param ec Set to indicate what error occurred, if any. If the sequence is - empty, set to `net::error::not_found`. Otherwise, contains the error - from the last connection attempt. - - @returns On success, the successfully connected endpoint. Otherwise, a - default-constructed endpoint. -*/ -template< - class Protocol, class Executor, - class EndpointSequence, class ConnectCondition -#if ! BOOST_BEAST_DOXYGEN - ,class = typename std::enable_if< - net::is_endpoint_sequence< - EndpointSequence>::value>::type -#endif -> -typename Protocol::endpoint -connect( - basic_stream& stream, - EndpointSequence const& endpoints, - ConnectCondition connect_condition, - error_code& ec) -{ - return net::connect(stream.socket(), endpoints, connect_condition, ec); -} - -/** Establishes a connection by trying each endpoint in a sequence. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed operation, is implemented - in terms of calls to the underlying socket's `connect` function. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param begin An iterator pointing to the start of a sequence of endpoints. - - @param end An iterator pointing to the end of a sequence of endpoints. - - @param connect_condition A function object that is called prior to each - connection attempt. The signature of the function object must be: - @code - bool connect_condition( - error_code const& ec, - typename Protocol::endpoint const& next); - @endcode - The @c ec parameter contains the result from the most recent connect - operation. Before the first connection attempt, @c ec is always set to - indicate success. The @c next parameter is the next endpoint to be tried. - The function object should return true if the next endpoint should be tried, - and false if it should be skipped. - - @returns An iterator denoting the successfully connected endpoint. - - @throws boost::system::system_error Thrown on failure. If the sequence is - empty, the associated @c error_code is `net::error::not_found`. - Otherwise, contains the error from the last connection attempt. -*/ -template< - class Protocol, class Executor, - class Iterator, class ConnectCondition> -Iterator -connect( - basic_stream& stream, - Iterator begin, Iterator end, - ConnectCondition connect_condition) -{ - return net::connect(stream.socket(), begin, end, connect_condition); -} - -/** Establishes a connection by trying each endpoint in a sequence. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed operation, is implemented - in terms of calls to the underlying socket's `connect` function. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param begin An iterator pointing to the start of a sequence of endpoints. - - @param end An iterator pointing to the end of a sequence of endpoints. - - @param connect_condition A function object that is called prior to each - connection attempt. The signature of the function object must be: - @code - bool connect_condition( - error_code const& ec, - typename Protocol::endpoint const& next); - @endcode - The @c ec parameter contains the result from the most recent connect - operation. Before the first connection attempt, @c ec is always set to - indicate success. The @c next parameter is the next endpoint to be tried. - The function object should return true if the next endpoint should be tried, - and false if it should be skipped. - - @param ec Set to indicate what error occurred, if any. If the sequence is - empty, set to `net::error::not_found`. Otherwise, contains the error - from the last connection attempt. - - @returns On success, an iterator denoting the successfully connected - endpoint. Otherwise, the end iterator. -*/ -template< - class Protocol, class Executor, - class Iterator, class ConnectCondition> -Iterator -connect( - basic_stream& stream, - Iterator begin, Iterator end, - ConnectCondition connect_condition, - error_code& ec) -{ - return net::connect(stream.socket(), begin, end, connect_condition, ec); -} - -/** Establishes a connection by trying each endpoint in a sequence asynchronously. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed asynchronous operation, is - implemented in terms of calls to the underlying socket's `async_connect` - function. - - If the timeout timer expires while the operation is outstanding, - the current connection attempt will be canceled and the completion - handler will be invoked with the error @ref error::timeout. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param endpoints A sequence of endpoints. This this object must meet - the requirements of EndpointSequence. - - @param handler The handler to be called when the connect operation - completes. Ownership of the handler may be transferred. The function - signature of the handler must be: - @code - void handler( - // Result of operation. if the sequence is empty, set to - // net::error::not_found. Otherwise, contains the - // error from the last connection attempt. - error_code const& error, - - // On success, the successfully connected endpoint. - // Otherwise, a default-constructed endpoint. - typename Protocol::endpoint const& endpoint - ); - @endcode - Regardless of whether the asynchronous operation completes immediately - or not, the handler will not be invoked from within this function. - Invocation of the handler will be performed in a manner equivalent - to using `net::post`. -*/ -template< - class Protocol, class Executor, class RatePolicy, - class EndpointSequence, - class RangeConnectHandler -#if ! BOOST_BEAST_DOXYGEN - ,class = typename std::enable_if< - net::is_endpoint_sequence< - EndpointSequence>::value>::type -#endif -> -BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, - void (error_code, typename Protocol::endpoint)) -async_connect( - basic_stream& stream, - EndpointSequence const& endpoints, - RangeConnectHandler&& handler); - -/** Establishes a connection by trying each endpoint in a sequence asynchronously. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed asynchronous operation, is - implemented in terms of calls to the underlying socket's `async_connect` - function. - - If the timeout timer expires while the operation is outstanding, - the current connection attempt will be canceled and the completion - handler will be invoked with the error @ref error::timeout. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param endpoints A sequence of endpoints. This this object must meet - the requirements of EndpointSequence. - - @param connect_condition A function object that is called prior to each - connection attempt. The signature of the function object must be: - @code - bool connect_condition( - error_code const& ec, - typename Protocol::endpoint const& next); - @endcode - The @c ec parameter contains the result from the most recent connect - operation. Before the first connection attempt, @c ec is always set to - indicate success. The @c next parameter is the next endpoint to be tried. - The function object should return true if the next endpoint should be tried, - and false if it should be skipped. - - @param handler The handler to be called when the connect operation - completes. Ownership of the handler may be transferred. The function - signature of the handler must be: - @code - void handler( - // Result of operation. if the sequence is empty, set to - // net::error::not_found. Otherwise, contains the - // error from the last connection attempt. - error_code const& error, - - // On success, the successfully connected endpoint. - // Otherwise, a default-constructed endpoint. - typename Protocol::endpoint const& endpoint - ); - @endcode - Regardless of whether the asynchronous operation completes immediately - or not, the handler will not be invoked from within this function. - Invocation of the handler will be performed in a manner equivalent - to using `net::post`. - - @par Example - The following connect condition function object can be used to output - information about the individual connection attempts: - @code - struct my_connect_condition - { - bool operator()( - error_code const& ec, - net::ip::tcp::endpoint const& next) - { - if (ec) - std::cout << "Error: " << ec.message() << std::endl; - std::cout << "Trying: " << next << std::endl; - return true; - } - }; - @endcode -*/ -template< - class Protocol, class Executor, class RatePolicy, - class EndpointSequence, - class ConnectCondition, - class RangeConnectHandler -#if ! BOOST_BEAST_DOXYGEN - ,class = typename std::enable_if< - net::is_endpoint_sequence< - EndpointSequence>::value>::type -#endif -> -BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, - void (error_code, typename Protocol::endpoint)) -async_connect( - basic_stream& stream, - EndpointSequence const& endpoints, - ConnectCondition connect_condition, - RangeConnectHandler&& handler); - -/** Establishes a connection by trying each endpoint in a sequence asynchronously. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed asynchronous operation, is - implemented in terms of calls to the underlying socket's `async_connect` - function. - - If the timeout timer expires while the operation is outstanding, - the current connection attempt will be canceled and the completion - handler will be invoked with the error @ref error::timeout. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param begin An iterator pointing to the start of a sequence of endpoints. - - @param end An iterator pointing to the end of a sequence of endpoints. - - @param handler The handler to be called when the connect operation - completes. Ownership of the handler may be transferred. The function - signature of the handler must be: - @code - void handler( - // Result of operation. if the sequence is empty, set to - // net::error::not_found. Otherwise, contains the - // error from the last connection attempt. - error_code const& error, - - // On success, an iterator denoting the successfully - // connected endpoint. Otherwise, the end iterator. - Iterator iterator - ); - @endcode - Regardless of whether the asynchronous operation completes immediately - or not, the handler will not be invoked from within this function. - Invocation of the handler will be performed in a manner equivalent - to using `net::post`. -*/ -template< - class Protocol, class Executor, class RatePolicy, - class Iterator, - class IteratorConnectHandler> -BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (error_code, Iterator)) -async_connect( - basic_stream& stream, - Iterator begin, Iterator end, - IteratorConnectHandler&& handler); - -/** Establishes a connection by trying each endpoint in a sequence asynchronously. - - This function attempts to connect the stream to one of a sequence of - endpoints by trying each endpoint until a connection is successfully - established. - - The algorithm, known as a composed asynchronous operation, is - implemented in terms of calls to the underlying socket's `async_connect` - function. - - If the timeout timer expires while the operation is outstanding, - the current connection attempt will be canceled and the completion - handler will be invoked with the error @ref error::timeout. - - @param stream The stream to be connected. - If the underlying socket is already open, it will be closed. - - @param begin An iterator pointing to the start of a sequence of endpoints. - - @param end An iterator pointing to the end of a sequence of endpoints. - - @param connect_condition A function object that is called prior to each - connection attempt. The signature of the function object must be: - @code - bool connect_condition( - error_code const& ec, - Iterator next); - @endcode - @param handler The handler to be called when the connect operation - completes. Ownership of the handler may be transferred. The function - signature of the handler must be: - @code - void handler( - // Result of operation. if the sequence is empty, set to - // net::error::not_found. Otherwise, contains the - // error from the last connection attempt. - error_code const& error, - - // On success, an iterator denoting the successfully - // connected endpoint. Otherwise, the end iterator. - Iterator iterator - ); - @endcode - Regardless of whether the asynchronous operation completes immediately - or not, the handler will not be invoked from within this function. - Invocation of the handler will be performed in a manner equivalent - to using `net::post`. -*/ -template< - class Protocol, class Executor, class RatePolicy, - class Iterator, - class ConnectCondition, - class IteratorConnectHandler> -BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (error_code, Iterator)) -async_connect( - basic_stream& stream, - Iterator begin, Iterator end, - ConnectCondition connect_condition, - IteratorConnectHandler&& handler); - } // beast } // boost diff --git a/include/boost/beast/core/detail/stream_base.hpp b/include/boost/beast/core/detail/stream_base.hpp index 7bd3b1ef..a65a8022 100644 --- a/include/boost/beast/core/detail/stream_base.hpp +++ b/include/boost/beast/core/detail/stream_base.hpp @@ -21,9 +21,6 @@ namespace boost { namespace beast { namespace detail { -template -class basic_stream_connect_op; - struct any_endpoint { template diff --git a/include/boost/beast/core/impl/basic_stream.hpp b/include/boost/beast/core/impl/basic_stream.hpp index c544ddf3..0c016d97 100644 --- a/include/boost/beast/core/impl/basic_stream.hpp +++ b/include/boost/beast/core/impl/basic_stream.hpp @@ -179,151 +179,6 @@ struct basic_stream:: //------------------------------------------------------------------------------ -namespace detail { - -template< - class Protocol, class Executor, class RatePolicy, - class Handler> -class basic_stream_connect_op - : public async_op_base -{ - using stream_type = beast::basic_stream< - Protocol, Executor, RatePolicy>; - - using timeout_handler = - typename stream_type::timeout_handler; - - boost::shared_ptr impl_; - typename stream_type::pending_guard pg0_; - typename stream_type::pending_guard pg1_; - - typename stream_type::op_state& - state() noexcept - { - return impl_->write; - } - -public: - template - basic_stream_connect_op( - Handler_&& h, - stream_type& s, - typename stream_type::endpoint_type ep) - : async_op_base( - std::forward(h), s.get_executor()) - , impl_(s.impl_) - , pg0_(impl_->read.pending) - , pg1_(impl_->write.pending) - { - if(state().timer.expiry() != stream_base::never()) - impl_->write.timer.async_wait( - net::bind_executor( - this->get_executor(), - timeout_handler{ - state(), - impl_, - state().tick})); - - impl_->socket.async_connect( - ep, std::move(*this)); - // *this is now moved-from - } - - template< - class Endpoints, class Condition, - class Handler_> - basic_stream_connect_op( - Handler_&& h, - stream_type& s, - Endpoints const& eps, - Condition const& cond) - : async_op_base( - std::forward(h), s.get_executor()) - , impl_(s.impl_) - , pg0_(impl_->read.pending) - , pg1_(impl_->write.pending) - { - if(state().timer.expiry() != stream_base::never()) - impl_->write.timer.async_wait( - net::bind_executor( - this->get_executor(), - timeout_handler{ - state(), - impl_, - state().tick})); - - net::async_connect(impl_->socket, - eps, cond, std::move(*this)); - // *this is now moved-from - } - - template< - class Iterator, class Condition, - class Handler_> - basic_stream_connect_op( - Handler_&& h, - stream_type& s, - Iterator begin, Iterator end, - Condition const& cond) - : async_op_base( - std::forward(h), s.get_executor()) - , impl_(s.impl_) - , pg0_(impl_->read.pending) - , pg1_(impl_->write.pending) - { - if(state().timer.expiry() != stream_base::never()) - impl_->write.timer.async_wait( - net::bind_executor( - this->get_executor(), - timeout_handler{ - state(), - impl_, - state().tick})); - - net::async_connect(impl_->socket, - begin, end, cond, std::move(*this)); - // *this is now moved-from - } - - template - void - operator()(error_code ec, Args&&... args) - { - if(state().timer.expiry() != stream_base::never()) - { - ++state().tick; - - // try cancelling timer - auto const n = - impl_->write.timer.cancel(); - if(n == 0) - { - // timeout handler invoked? - if(state().timeout) - { - // yes, socket already closed - ec = beast::error::timeout; - state().timeout = false; - } - } - else - { - BOOST_ASSERT(n == 1); - BOOST_ASSERT(! state().timeout); - } - } - - pg0_.reset(); - pg1_.reset(); - this->invoke_now(ec, std::forward(args)...); - } -}; - -} // detail - -//------------------------------------------------------------------------------ - template struct basic_stream::ops { @@ -530,6 +385,136 @@ public: } }; +template +class connect_op + : public async_op_base +{ + boost::shared_ptr impl_; + pending_guard pg0_; + pending_guard pg1_; + + op_state& + state() noexcept + { + return impl_->write; + } + +public: + template + connect_op( + Handler_&& h, + basic_stream& s, + endpoint_type ep) + : async_op_base( + std::forward(h), s.get_executor()) + , impl_(s.impl_) + , pg0_(impl_->read.pending) + , pg1_(impl_->write.pending) + { + if(state().timer.expiry() != stream_base::never()) + impl_->write.timer.async_wait( + net::bind_executor( + this->get_executor(), + timeout_handler{ + state(), + impl_, + state().tick})); + + impl_->socket.async_connect( + ep, std::move(*this)); + // *this is now moved-from + } + + template< + class Endpoints, class Condition, + class Handler_> + connect_op( + Handler_&& h, + basic_stream& s, + Endpoints const& eps, + Condition const& cond) + : async_op_base( + std::forward(h), s.get_executor()) + , impl_(s.impl_) + , pg0_(impl_->read.pending) + , pg1_(impl_->write.pending) + { + if(state().timer.expiry() != stream_base::never()) + impl_->write.timer.async_wait( + net::bind_executor( + this->get_executor(), + timeout_handler{ + state(), + impl_, + state().tick})); + + net::async_connect(impl_->socket, + eps, cond, std::move(*this)); + // *this is now moved-from + } + + template< + class Iterator, class Condition, + class Handler_> + connect_op( + Handler_&& h, + basic_stream& s, + Iterator begin, Iterator end, + Condition const& cond) + : async_op_base( + std::forward(h), s.get_executor()) + , impl_(s.impl_) + , pg0_(impl_->read.pending) + , pg1_(impl_->write.pending) + { + if(state().timer.expiry() != stream_base::never()) + impl_->write.timer.async_wait( + net::bind_executor( + this->get_executor(), + timeout_handler{ + state(), + impl_, + state().tick})); + + net::async_connect(impl_->socket, + begin, end, cond, std::move(*this)); + // *this is now moved-from + } + + template + void + operator()(error_code ec, Args&&... args) + { + if(state().timer.expiry() != stream_base::never()) + { + ++state().tick; + + // try cancelling timer + auto const n = + impl_->write.timer.cancel(); + if(n == 0) + { + // timeout handler invoked? + if(state().timeout) + { + // yes, socket already closed + ec = beast::error::timeout; + state().timeout = false; + } + } + else + { + BOOST_ASSERT(n == 1); + BOOST_ASSERT(! state().timeout); + } + } + + pg0_.reset(); + pg1_.reset(); + this->invoke_now(ec, std::forward(args)...); + } +}; + struct run_read_op { template @@ -700,6 +685,8 @@ close() impl_->close(); } +//------------------------------------------------------------------------------ + template template BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler, @@ -711,8 +698,7 @@ async_connect( { BOOST_BEAST_HANDLER_INIT( ConnectHandler, void(error_code)); - detail::basic_stream_connect_op< - Protocol, Executor, RatePolicy, + ops::template connect_op< BOOST_ASIO_HANDLER_TYPE( ConnectHandler, void(error_code))>( std::forward(handler), @@ -720,6 +706,98 @@ async_connect( return init.result.get(); } +template +template< + class EndpointSequence, + class RangeConnectHandler, + class> +BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void(error_code, typename Protocol::endpoint)) +basic_stream:: +async_connect( + EndpointSequence const& endpoints, + RangeConnectHandler&& handler) +{ + BOOST_BEAST_HANDLER_INIT(RangeConnectHandler, + void(error_code, typename Protocol::endpoint)); + ops::template connect_op< + BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler, + void(error_code, typename Protocol::endpoint))>( + std::move(init.completion_handler), *this, + endpoints, detail::any_endpoint{}); + return init.result.get(); +} + +template +template< + class EndpointSequence, + class ConnectCondition, + class RangeConnectHandler, + class> +BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (error_code, typename Protocol::endpoint)) +basic_stream:: +async_connect( + EndpointSequence const& endpoints, + ConnectCondition connect_condition, + RangeConnectHandler&& handler) +{ + BOOST_BEAST_HANDLER_INIT(RangeConnectHandler, + void(error_code, typename Protocol::endpoint)); + ops::template connect_op< + BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler, + void(error_code, typename Protocol::endpoint))>( + std::move(init.completion_handler), *this, + endpoints, connect_condition); + return init.result.get(); +} + +template +template< + class Iterator, + class IteratorConnectHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (error_code, Iterator)) +basic_stream:: +async_connect( + Iterator begin, Iterator end, + IteratorConnectHandler&& handler) +{ + BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler, + void(error_code, Iterator)); + ops::template connect_op< + BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler, + void(error_code, Iterator))>( + std::move(init.completion_handler), *this, + begin, end, detail::any_endpoint{}); + return init.result.get(); +} + +template +template< + class Iterator, + class ConnectCondition, + class IteratorConnectHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (error_code, Iterator)) +basic_stream:: +async_connect( + Iterator begin, Iterator end, + ConnectCondition connect_condition, + IteratorConnectHandler&& handler) +{ + BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler, + void(error_code, Iterator)); + ops::template connect_op< + BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler, + void(error_code, Iterator))>( + std::move(init.completion_handler), *this, + begin, end, connect_condition); + return init.result.get(); +} + +//------------------------------------------------------------------------------ + template template BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, @@ -764,100 +842,6 @@ async_write_some( //------------------------------------------------------------------------------ -template< - class Protocol, class Executor, class RatePolicy, - class EndpointSequence, - class RangeConnectHandler, - class> -BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, - void(error_code, typename Protocol::endpoint)) -async_connect( - basic_stream& stream, - EndpointSequence const& endpoints, - RangeConnectHandler&& handler) -{ - BOOST_BEAST_HANDLER_INIT(RangeConnectHandler, - void(error_code, typename Protocol::endpoint)); - detail::basic_stream_connect_op< - Protocol, Executor, RatePolicy, - BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler, - void(error_code, typename Protocol::endpoint))>( - std::move(init.completion_handler), stream, - endpoints, detail::any_endpoint{}); - return init.result.get(); -} - -template< - class Protocol, class Executor, class RatePolicy, - class EndpointSequence, - class ConnectCondition, - class RangeConnectHandler, - class> -BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, - void (error_code, typename Protocol::endpoint)) -async_connect( - basic_stream& stream, - EndpointSequence const& endpoints, - ConnectCondition connect_condition, - RangeConnectHandler&& handler) -{ - BOOST_BEAST_HANDLER_INIT(RangeConnectHandler, - void(error_code, typename Protocol::endpoint)); - detail::basic_stream_connect_op< - Protocol, Executor, RatePolicy, - BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler, - void(error_code, typename Protocol::endpoint))>( - std::move(init.completion_handler), stream, - endpoints, connect_condition); - return init.result.get(); -} - -template< - class Protocol, class Executor, class RatePolicy, - class Iterator, - class IteratorConnectHandler> -BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (error_code, Iterator)) -async_connect( - basic_stream& stream, - Iterator begin, Iterator end, - IteratorConnectHandler&& handler) -{ - BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler, - void(error_code, Iterator)); - detail::basic_stream_connect_op< - Protocol, Executor, RatePolicy, - BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler, - void(error_code, Iterator))>( - std::move(init.completion_handler), stream, - begin, end, detail::any_endpoint{}); - return init.result.get(); -} - -template< - class Protocol, class Executor, class RatePolicy, - class Iterator, - class ConnectCondition, - class IteratorConnectHandler> -BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (error_code, Iterator)) -async_connect( - basic_stream& stream, - Iterator begin, Iterator end, - ConnectCondition connect_condition, - IteratorConnectHandler&& handler) -{ - BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler, - void(error_code, Iterator)); - detail::basic_stream_connect_op< - Protocol, Executor, RatePolicy, - BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler, - void(error_code, Iterator))>( - std::move(init.completion_handler), stream, - begin, end, connect_condition); - return init.result.get(); -} - //------------------------------------------------------------------------------ // // Customization points diff --git a/test/beast/core/basic_stream.cpp b/test/beast/core/basic_stream.cpp index 4410ba0e..cddb0caa 100644 --- a/test/beast/core/basic_stream.cpp +++ b/test/beast/core/basic_stream.cpp @@ -819,9 +819,9 @@ public: stream_type s(ioc); error_code ec; r.ep = a.ep; - connect(s, r); + s.connect(r); s.socket().close(); - connect(s, r, ec); + s.connect(r, ec); BEAST_EXPECTS(! ec, ec.message()); } @@ -830,9 +830,9 @@ public: stream_type s(ioc); error_code ec; r.ep = a.ep; - connect(s, r, cond); + s.connect(r, cond); s.socket().close(); - connect(s, r, cond, ec); + s.connect(r, cond, ec); BEAST_EXPECTS(! ec, ec.message()); } @@ -841,9 +841,9 @@ public: stream_type s(ioc); error_code ec; r.ep = a.ep; - connect(s, r.begin(), r.end()); + s.connect(r.begin(), r.end()); s.socket().close(); - connect(s, r.begin(), r.end(), ec); + s.connect(r.begin(), r.end(), ec); BEAST_EXPECTS(! ec, ec.message()); } @@ -852,9 +852,9 @@ public: stream_type s(ioc); error_code ec; r.ep = a.ep; - connect(s, r.begin(), r.end(), cond); + s.connect(r.begin(), r.end(), cond); s.socket().close(); - connect(s, r.begin(), r.end(), cond, ec); + s.connect(r.begin(), r.end(), cond, ec); BEAST_EXPECTS(! ec, ec.message()); } @@ -881,12 +881,12 @@ public: stream_type s(ioc); r.ep = a.ep; s.expires_never(); - async_connect(s, r, range_handler{}); + s.async_connect(r, range_handler{}); ioc.run(); ioc.restart(); s.socket().close(); s.expires_after(std::chrono::seconds(30)); - async_connect(s, r, range_handler{}); + s.async_connect(r, range_handler{}); ioc.run(); ioc.restart(); } @@ -896,12 +896,12 @@ public: stream_type s(ioc); r.ep = a.ep; s.expires_never(); - async_connect(s, r, cond, range_handler{}); + s.async_connect(r, cond, range_handler{}); ioc.run(); ioc.restart(); s.socket().close(); s.expires_after(std::chrono::seconds(30)); - async_connect(s, r, cond, range_handler{}); + s.async_connect(r, cond, range_handler{}); ioc.run(); ioc.restart(); } @@ -911,13 +911,13 @@ public: stream_type s(ioc); r.ep = a.ep; s.expires_never(); - async_connect(s, r.begin(), r.end(), + s.async_connect(r.begin(), r.end(), iterator_handler{}); ioc.run(); ioc.restart(); s.socket().close(); s.expires_after(std::chrono::seconds(30)); - async_connect(s, r.begin(), r.end(), + s.async_connect(r.begin(), r.end(), iterator_handler{}); ioc.run(); ioc.restart(); @@ -928,18 +928,18 @@ public: stream_type s(ioc); r.ep = a.ep; s.expires_never(); - async_connect(s, r.begin(), r.end(), cond, + s.async_connect(r.begin(), r.end(), cond, iterator_handler{}); ioc.run(); ioc.restart(); s.socket().close(); s.expires_after(std::chrono::seconds(30)); - async_connect(s, r.begin(), r.end(), cond, + s.async_connect(r.begin(), r.end(), cond, iterator_handler{}); ioc.run(); ioc.restart(); } - +#if 0 // use_future BEAST_EXPECT(static_cast( &beast::async_connect)); +#endif // // async_connect timeout diff --git a/test/doc/websocket_snippets.cpp b/test/doc/websocket_snippets.cpp index d29eabae..483e96a0 100644 --- a/test/doc/websocket_snippets.cpp +++ b/test/doc/websocket_snippets.cpp @@ -62,7 +62,7 @@ boost::ignore_unused(ec); net::ip::tcp::resolver r(ioc); stream ws(ioc); auto const results = r.resolve(host, "ws"); - connect(get_lowest_layer(ws), results.begin(), results.end()); + get_lowest_layer(ws).connect(results.begin(), results.end()); //] }