From 1fc340713cd3f75dafb8468dc787c77d95ad0c01 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Tue, 11 Oct 2022 18:01:48 +0800 Subject: [PATCH] beast support default completion & rebind. buffers_generator uses default_completion. websocket::stream has a rebinding constructor. ssl_stream has a rebind_executor member. basic_stream has rebinding constructor. --- include/boost/beast/core/basic_stream.hpp | 22 ++++++++-- .../boost/beast/core/buffers_generator.hpp | 13 +++--- .../boost/beast/core/detail/stream_base.hpp | 11 +++-- .../boost/beast/core/impl/basic_stream.hpp | 8 ++++ .../beast/core/impl/buffers_generator.hpp | 9 ++-- include/boost/beast/ssl/ssl_stream.hpp | 43 +++++++++++++------ include/boost/beast/websocket/impl/stream.hpp | 9 ++++ include/boost/beast/websocket/stream.hpp | 25 +++++++++++ test/beast/core/basic_stream.cpp | 15 +++---- 9 files changed, 112 insertions(+), 43 deletions(-) diff --git a/include/boost/beast/core/basic_stream.hpp b/include/boost/beast/core/basic_stream.hpp index 59d39de7..19e95974 100644 --- a/include/boost/beast/core/basic_stream.hpp +++ b/include/boost/beast/core/basic_stream.hpp @@ -233,6 +233,7 @@ public: using endpoint_type = typename Protocol::endpoint; private: + using op_state = basic_op_state; static_assert( net::is_executor::value || net::execution::is_executor::value, "Executor type requirements not met"); @@ -247,15 +248,12 @@ private: op_state read; op_state write; -#if 0 net::basic_waitable_timer< std::chrono::steady_clock, net::wait_traits< std::chrono::steady_clock>, Executor> timer; // rate timer; -#else - net::steady_timer timer; -#endif + int waiting = 0; impl_type(impl_type&&) = default; @@ -356,6 +354,22 @@ public: ! std::is_constructible::value>::type> explicit basic_stream(Arg0&& argo, Args&&... args); + + + /** Constructor + * + * A constructor that rebinds the executor. + * + * @tparam Executor_ The new executor + * @param other The original socket to be rebound. + */ + template + explicit + basic_stream(basic_stream && other); + + + template + friend class basic_stream; #endif /** Constructor diff --git a/include/boost/beast/core/buffers_generator.hpp b/include/boost/beast/core/buffers_generator.hpp index 498d437f..5394865e 100644 --- a/include/boost/beast/core/buffers_generator.hpp +++ b/include/boost/beast/core/buffers_generator.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -176,21 +177,19 @@ write( template< class AsyncWriteStream, class BuffersGenerator, - class CompletionToken + BOOST_BEAST_ASYNC_TPARAM2 CompletionToken + = net::default_completion_token_t> #if !BOOST_BEAST_DOXYGEN , typename std::enable_if::value>::type* = nullptr #endif > -auto +BOOST_BEAST_ASYNC_RESULT2(CompletionToken) async_write( AsyncWriteStream& stream, BuffersGenerator generator, - CompletionToken&& token) -> - typename net::async_result< - typename std::decay< - CompletionToken>::type, - void(error_code, std::size_t)>::return_type; + CompletionToken&& token + = net::default_completion_token_t>{}); } // beast } // boost diff --git a/include/boost/beast/core/detail/stream_base.hpp b/include/boost/beast/core/detail/stream_base.hpp index e6e80620..8080e949 100644 --- a/include/boost/beast/core/detail/stream_base.hpp +++ b/include/boost/beast/core/detail/stream_base.hpp @@ -39,16 +39,21 @@ struct stream_base std::chrono::steady_clock::time_point; using tick_type = std::uint64_t; - struct op_state + template + struct basic_op_state { - net::steady_timer timer; // for timing out + net::basic_waitable_timer< + std::chrono::steady_clock, + net::wait_traits< + std::chrono::steady_clock>, + Executor> timer; // for timing out tick_type tick = 0; // counts waits bool pending = false; // if op is pending bool timeout = false; // if timed out template explicit - op_state(Args&&... args) + basic_op_state(Args&&... args) : timer(std::forward(args)...) { } diff --git a/include/boost/beast/core/impl/basic_stream.hpp b/include/boost/beast/core/impl/basic_stream.hpp index 1c47c37a..4e131323 100644 --- a/include/boost/beast/core/impl/basic_stream.hpp +++ b/include/boost/beast/core/impl/basic_stream.hpp @@ -768,6 +768,14 @@ basic_stream(basic_stream&& other) // controlling its lifetime. } +template +template +basic_stream:: +basic_stream(basic_stream && other) + : impl_(boost::make_shared(std::false_type{}, std::move(other.impl_->socket))) +{ +} + //------------------------------------------------------------------------------ template diff --git a/include/boost/beast/core/impl/buffers_generator.hpp b/include/boost/beast/core/impl/buffers_generator.hpp index 602911f0..96b482fd 100644 --- a/include/boost/beast/core/impl/buffers_generator.hpp +++ b/include/boost/beast/core/impl/buffers_generator.hpp @@ -143,18 +143,15 @@ write(SyncWriteStream& stream, BuffersGenerator&& generator) template< class AsyncWriteStream, class BuffersGenerator, - class CompletionToken, + BOOST_BEAST_ASYNC_TPARAM2 CompletionToken, typename std::enable_if::value>::type* /*= nullptr*/ > -auto +BOOST_BEAST_ASYNC_RESULT2(CompletionToken) async_write( AsyncWriteStream& stream, BuffersGenerator generator, - CompletionToken&& token) -> - typename net::async_result< - typename std::decay::type, - void(error_code, std::size_t)>::return_type + CompletionToken&& token) { static_assert( beast::is_async_write_stream::value, diff --git a/include/boost/beast/ssl/ssl_stream.hpp b/include/boost/beast/ssl/ssl_stream.hpp index 2ab88816..a07d987a 100644 --- a/include/boost/beast/ssl/ssl_stream.hpp +++ b/include/boost/beast/ssl/ssl_stream.hpp @@ -92,6 +92,17 @@ public: /// The type of the executor associated with the object. using executor_type = typename stream_type::executor_type; + /// Rebinds the stream type to another executor. + template + struct rebind_executor + { + /// The stream type when rebound to the specified executor. + using other = ssl_stream< + typename stream_type::template rebind_executor::other + >; + }; + + /** Construct a stream. This constructor creates a stream and initialises the underlying stream @@ -400,10 +411,10 @@ public: const boost::system::error_code& error // Result of operation. ); @endcode */ - template + template> BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, void(boost::system::error_code)) async_handshake(handshake_type type, - BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler) + BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler = net::default_completion_token_t{}) { return p_->next_layer().async_handshake(type, BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler)); @@ -430,10 +441,12 @@ public: std::size_t bytes_transferred // Amount of buffers used in handshake. ); @endcode */ - template + template> BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, void(boost::system::error_code, std::size_t)) async_handshake(handshake_type type, ConstBufferSequence const& buffers, - BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler) + BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler + = net::default_completion_token_t{}) { return p_->next_layer().async_handshake(type, buffers, BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler)); @@ -477,9 +490,9 @@ public: const boost::system::error_code& error // Result of operation. ); @endcode */ - template + template> BOOST_ASIO_INITFN_RESULT_TYPE(ShutdownHandler, void(boost::system::error_code)) - async_shutdown(BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler) + async_shutdown(BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler = net::default_completion_token_t{}) { return p_->next_layer().async_shutdown( BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler)); @@ -555,10 +568,11 @@ public: need to ensure that all data is written before the asynchronous operation completes. */ - template + template> BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void(boost::system::error_code, std::size_t)) async_write_some(ConstBufferSequence const& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler= net::default_completion_token_t{}) { return p_->async_write_some(buffers, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); @@ -636,10 +650,12 @@ public: if you need to ensure that the requested amount of data is read before the asynchronous operation completes. */ - template + template> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void(boost::system::error_code, std::size_t)) async_read_some(MutableBufferSequence const& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + = net::default_completion_token_t{}) { return p_->async_read_some(buffers, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); @@ -657,7 +673,7 @@ public: ssl_stream& stream, boost::system::error_code& ec); - template + template friend void async_teardown( @@ -680,12 +696,13 @@ teardown( teardown(role, *stream.p_, ec); } -template +template>> void async_teardown( boost::beast::role_type role, ssl_stream& stream, - TeardownHandler&& handler) + TeardownHandler&& handler = net::default_completion_token_t>{}) { // Just forward it to the underlying ssl::stream using boost::beast::websocket::async_teardown; diff --git a/include/boost/beast/websocket/impl/stream.hpp b/include/boost/beast/websocket/impl/stream.hpp index f71c9c84..52c23d31 100644 --- a/include/boost/beast/websocket/impl/stream.hpp +++ b/include/boost/beast/websocket/impl/stream.hpp @@ -58,6 +58,15 @@ stream(Args&&... args) max_control_frame_size); } +template +template +stream:: +stream(stream && other) + : impl_(boost::make_shared(std::move(other.next_layer()))) +{ +} + + template auto stream:: diff --git a/include/boost/beast/websocket/stream.hpp b/include/boost/beast/websocket/stream.hpp index 0665dfa9..fdbf0707 100644 --- a/include/boost/beast/websocket/stream.hpp +++ b/include/boost/beast/websocket/stream.hpp @@ -162,6 +162,7 @@ class stream } public: + /// Indicates if the permessage-deflate extension is supported using is_deflate_supported = std::integral_constant; @@ -174,6 +175,16 @@ public: using executor_type = beast::executor_type; + /// Rebinds the stream type to another executor. + template + struct rebind_executor + { + /// The stream type when rebound to the specified executor. + using other = stream< + typename next_layer_type::template rebind_executor::other, + deflateSupported>; + }; + /** Destructor Destroys the stream and all associated resources. @@ -211,6 +222,20 @@ public: explicit stream(Args&&... args); + /** Rebinding constructor + * + * This constructor creates a the websocket stream from a + * websocket stream with a different executor. + * + * @throw Any exception thrown by the NextLayer rebind constructor. + * + * @param other The other websocket stream to construct from. + */ + template + explicit + stream(stream && other); + + //-------------------------------------------------------------------------- /** Get the executor associated with the object. diff --git a/test/beast/core/basic_stream.cpp b/test/beast/core/basic_stream.cpp index 8fa736a6..79406f94 100644 --- a/test/beast/core/basic_stream.cpp +++ b/test/beast/core/basic_stream.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -551,13 +552,10 @@ public: // stream destroyed test_server srv("", ep, log); { - stream_type s(ioc); + auto s = net::detached.as_default_on(stream_type(ioc)); s.socket().connect(srv.local_endpoint()); s.expires_after(std::chrono::seconds(0)); - s.async_read_some(mb, - [](error_code, std::size_t) - { - }); + s.async_read_some(mb); } ioc.run(); ioc.restart(); @@ -566,12 +564,9 @@ public: { // stale timer test_acceptor a; - stream_type s(ioc); + auto s = net::detached.as_default_on(stream_type(ioc)); s.expires_after(std::chrono::milliseconds(50)); - s.async_read_some(mb, - [](error_code, std::size_t) - { - }); + s.async_read_some(mb); std::this_thread::sleep_for( std::chrono::milliseconds(100)); ioc.run();