diff --git a/CHANGELOG.md b/CHANGELOG.md index 23a4602a..518768be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ API Changes: * drain_buffer is removed +* role_type replaces teardown_tag + Actions Required: * Remove calling code which drains the connection after @@ -32,6 +34,12 @@ Actions Required: it is no longer necessary to manually drain the connection after closing. +* Modify signatures of teardown and async_teardown to use + role_type instead of teardown_tag + +* Change calls to teardown and async_teardown to pass the + correct role_type, client or server, depending on context. + -------------------------------------------------------------------------------- Version 99: diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml index 2e06a23d..10d0be23 100644 --- a/doc/qbk/quickref.xml +++ b/doc/qbk/quickref.xml @@ -147,6 +147,7 @@ close_code error frame_type + role_type diff --git a/example/common/ssl_stream.hpp b/example/common/ssl_stream.hpp index 35e847df..2abbf06e 100644 --- a/example/common/ssl_stream.hpp +++ b/example/common/ssl_stream.hpp @@ -294,14 +294,14 @@ public: template friend void - teardown(boost::beast::websocket::teardown_tag, + teardown(boost::beast::websocket::role_type, ssl_stream& stream, boost::system::error_code& ec); template friend void - async_teardown(boost::beast::websocket::teardown_tag, + async_teardown(boost::beast::websocket::role_type, ssl_stream& stream, TeardownHandler&& handler); }; @@ -312,24 +312,27 @@ public: template inline void -teardown(boost::beast::websocket::teardown_tag, +teardown( + boost::beast::websocket::role_type role, ssl_stream& stream, - boost::system::error_code& ec) + boost::system::error_code& ec) { // Just forward it to the wrapped ssl::stream using boost::beast::websocket::teardown; - teardown(boost::beast::websocket::teardown_tag{}, *stream.p_, ec); + teardown(role, *stream.p_, ec); } template inline void -async_teardown(boost::beast::websocket::teardown_tag, - ssl_stream& stream, TeardownHandler&& handler) +async_teardown( + boost::beast::websocket::role_type role, + ssl_stream& stream, + TeardownHandler&& handler) { // Just forward it to the wrapped ssl::stream using boost::beast::websocket::async_teardown; - async_teardown(boost::beast::websocket::teardown_tag{}, + async_teardown(role, *stream.p_, std::forward(handler)); } diff --git a/include/boost/beast/websocket/impl/fail.ipp b/include/boost/beast/websocket/impl/fail.ipp index 06ff2e08..7b91d1c9 100644 --- a/include/boost/beast/websocket/impl/fail.ipp +++ b/include/boost/beast/websocket/impl/fail.ipp @@ -180,7 +180,8 @@ operator()(error_code ec, std::size_t) go_teardown: BOOST_ASSERT(ws_.wr_block_ == tok_); step_ = do_teardown + 1; - websocket_helpers::call_async_teardown( + using beast::websocket::async_teardown; + async_teardown(ws_.role_, ws_.stream_, std::move(*this)); return; @@ -234,7 +235,8 @@ do_fail( if(failed_) return; } - websocket_helpers::call_teardown(stream_, ec); + using beast::websocket::teardown; + teardown(role_, stream_, ec); if(ec == boost::asio::error::eof) { // Rationale: diff --git a/include/boost/beast/websocket/impl/ssl.ipp b/include/boost/beast/websocket/impl/ssl.ipp index 582c7432..442b4508 100644 --- a/include/boost/beast/websocket/impl/ssl.ipp +++ b/include/boost/beast/websocket/impl/ssl.ipp @@ -33,20 +33,25 @@ Behavior of ssl::stream regarding close_ template void -teardown(teardown_tag, +teardown( + role_type, boost::asio::ssl::stream& stream, - error_code& ec) + error_code& ec) { stream.shutdown(ec); } -template +template< + class AsyncStream, + class TeardownHandler> void -async_teardown(teardown_tag, +async_teardown( + role_type, boost::asio::ssl::stream& stream, - TeardownHandler&& handler) + TeardownHandler&& handler) { - stream.async_shutdown(std::forward(handler)); + stream.async_shutdown( + std::forward(handler)); } } // websocket diff --git a/include/boost/beast/websocket/impl/teardown.ipp b/include/boost/beast/websocket/impl/teardown.ipp index e96eef8c..71622256 100644 --- a/include/boost/beast/websocket/impl/teardown.ipp +++ b/include/boost/beast/websocket/impl/teardown.ipp @@ -10,8 +10,7 @@ #ifndef BOOST_BEAST_WEBSOCKET_IMPL_TEARDOWN_IPP #define BOOST_BEAST_WEBSOCKET_IMPL_TEARDOWN_IPP -#include -#include +#include #include #include #include @@ -30,35 +29,30 @@ class teardown_tcp_op using socket_type = boost::asio::ip::tcp::socket; - struct data - { - bool cont; - socket_type& socket; - char buf[2048]; - int state = 0; - - data(Handler& handler, socket_type& socket_) - : socket(socket_) - { - using boost::asio::asio_handler_is_continuation; - cont = asio_handler_is_continuation(std::addressof(handler)); - } - }; - - handler_ptr d_; + Handler h_; + socket_type& s_; + role_type role_; + int step_ = 0; public: + teardown_tcp_op(teardown_tcp_op&& other) = default; + teardown_tcp_op(teardown_tcp_op const& other) = default; + template teardown_tcp_op( DeducedHandler&& h, - socket_type& socket) - : d_(std::forward(h), socket) + socket_type& s, + role_type role) + : h_(std::forward(h)) + , s_(s) + , role_(role) { - (*this)(error_code{}, 0, false); } void - operator()(error_code ec, std::size_t, bool again = true); + operator()( + error_code ec = {}, + std::size_t bytes_transferred = 0); friend void* asio_handler_allocate(std::size_t size, @@ -66,7 +60,7 @@ public: { using boost::asio::asio_handler_allocate; return asio_handler_allocate( - size, std::addressof(op->d_.handler())); + size, std::addressof(op->h_)); } friend @@ -75,13 +69,15 @@ public: { using boost::asio::asio_handler_deallocate; asio_handler_deallocate( - p, size, std::addressof(op->d_.handler())); + p, size, std::addressof(op->h_)); } friend bool asio_handler_is_continuation(teardown_tcp_op* op) { - return op->d_->cont; + using boost::asio::asio_handler_is_continuation; + return op->step_ >= 3 || + asio_handler_is_continuation(std::addressof(op->h_)); } template @@ -91,40 +87,58 @@ public: { using boost::asio::asio_handler_invoke; asio_handler_invoke( - f, std::addressof(op->d_.handler())); + f, std::addressof(op->h_)); } }; template void teardown_tcp_op:: -operator()(error_code ec, std::size_t, bool again) +operator()(error_code ec, std::size_t) { using boost::asio::buffer; - auto& d = *d_; - d.cont = d.cont || again; - while(! ec) + using tcp = boost::asio::ip::tcp; + switch(step_) { - switch(d.state) + case 0: + s_.non_blocking(true, ec); + if(ec) { - case 0: - d.state = 1; - d.socket.shutdown( - boost::asio::ip::tcp::socket::shutdown_send, ec); - break; - - case 1: - d.socket.async_read_some( - buffer(d.buf), std::move(*this)); - return; + step_ = 1; + return s_.get_io_service().post( + bind_handler(std::move(*this), ec, 0)); } + step_ = 2; + if(role_ == role_type::server) + s_.shutdown(tcp::socket::shutdown_send, ec); + goto do_read; + + case 1: + break; + + case 2: + step_ = 3; + + case 3: + if(ec != boost::asio::error::would_block) + break; + { + char buf[2048]; + s_.read_some( + boost::asio::buffer(buf), ec); + if(ec) + break; + } + + do_read: + return s_.async_read_some( + boost::asio::null_buffers{}, + std::move(*this)); } - if(ec == boost::asio::error::eof) - { - d.socket.close(ec); - ec = error_code{}; - } - d_.invoke(ec); + if(role_ == role_type::client) + s_.shutdown(tcp::socket::shutdown_send, ec); + s_.close(ec); + h_(ec); } } // detail @@ -133,13 +147,15 @@ operator()(error_code ec, std::size_t, bool again) inline void -teardown(teardown_tag, +teardown( + role_type role, boost::asio::ip::tcp::socket& socket, - error_code& ec) + error_code& ec) { using boost::asio::buffer; - socket.shutdown( - boost::asio::ip::tcp::socket::shutdown_send, ec); + if(role == role_type::server) + socket.shutdown( + boost::asio::ip::tcp::socket::shutdown_send, ec); while(! ec) { char buf[8192]; @@ -148,24 +164,27 @@ teardown(teardown_tag, if(! n) break; } - if(ec == boost::asio::error::eof) - ec = error_code{}; + if(role == role_type::client) + socket.shutdown( + boost::asio::ip::tcp::socket::shutdown_send, ec); socket.close(ec); } template inline void -async_teardown(teardown_tag, +async_teardown( + role_type role, boost::asio::ip::tcp::socket& socket, - TeardownHandler&& handler) + TeardownHandler&& handler) { static_assert(beast::is_completion_handler< TeardownHandler, void(error_code)>::value, "TeardownHandler requirements not met"); detail::teardown_tcp_op::type>{std::forward< - TeardownHandler>(handler), socket}; + TeardownHandler>(handler), socket, + role}(); } } // websocket diff --git a/include/boost/beast/websocket/role.hpp b/include/boost/beast/websocket/role.hpp new file mode 100644 index 00000000..54fa1411 --- /dev/null +++ b/include/boost/beast/websocket/role.hpp @@ -0,0 +1,59 @@ +// +// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_WEBSOCKET_ROLE_HPP +#define BOOST_BEAST_WEBSOCKET_ROLE_HPP + +#include + +namespace boost { +namespace beast { +namespace websocket { + +/** The role of the websocket stream endpoint. + + Whether the endpoint is a client or server affects the + behavior of the Close the WebSocket Connection + operation described in rfc6455 section 7.1.1. + The shutdown behavior depends on the type of the next + layer template parameter used to construct the @ref stream. + Other next layer types including user-defined types + may implement different role-based behavior when + performing the close operation. + + The default implementation for @ref stream when the next + layer type is a `boost::asio::ip::tcp::socket` behaves + as follows: + + @li In the client role, a TCP/IP shutdown is sent after + reading all remaining data on the connection. + + @li In the server role, a TCP/IP shutdown is sent before + reading all remaining data on the connection. + + When the next layer type is a `boost::asio::ssl::stream`, + the connection is closed by performing the SSL closing + handshake corresponding to the role type, client or server. + + @see https://tools.ietf.org/html/rfc6455#section-7.1.1 +*/ +enum class role_type +{ + /// The stream is operating as a client. + client, + + /// The stream is operating as a server. + server +}; + +} // websocket +} // beast +} // boost + +#endif diff --git a/include/boost/beast/websocket/ssl.hpp b/include/boost/beast/websocket/ssl.hpp index bddac49f..1314954b 100644 --- a/include/boost/beast/websocket/ssl.hpp +++ b/include/boost/beast/websocket/ssl.hpp @@ -28,15 +28,18 @@ namespace websocket { `boost::asio::ssl::stream`, callers are responsible for providing a suitable overload of this function. + @param role The role of the local endpoint + @param stream The stream to tear down. @param ec Set to the error if any occurred. */ template void -teardown(teardown_tag, +teardown( + role_type role, boost::asio::ssl::stream& stream, - error_code& ec); + error_code& ec); /** Start tearing down a `boost::asio::ssl::stream`. @@ -48,6 +51,8 @@ teardown(teardown_tag, callers are responsible for providing a suitable overload of this function. + @param role The role of the local endpoint + @param stream The stream to tear down. @param handler The handler to be called when the request completes. @@ -65,9 +70,10 @@ teardown(teardown_tag, template inline void -async_teardown(teardown_tag, +async_teardown( + role_type role, boost::asio::ssl::stream& stream, - TeardownHandler&& handler); + TeardownHandler&& handler); } // websocket } // beast diff --git a/include/boost/beast/websocket/stream.hpp b/include/boost/beast/websocket/stream.hpp index a7ccff73..0c8ae6a9 100644 --- a/include/boost/beast/websocket/stream.hpp +++ b/include/boost/beast/websocket/stream.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -145,16 +146,6 @@ class stream using control_cb_type = std::function; - /// Identifies the role of a WebSockets stream. - enum class role_type - { - /// Stream is operating as a client. - client, - - /// Stream is operating as a server. - server - }; - // State information for the message being received // struct rd_t diff --git a/include/boost/beast/websocket/teardown.hpp b/include/boost/beast/websocket/teardown.hpp index ffd71857..4889287c 100644 --- a/include/boost/beast/websocket/teardown.hpp +++ b/include/boost/beast/websocket/teardown.hpp @@ -11,7 +11,8 @@ #define BOOST_BEAST_WEBSOCKET_TEARDOWN_HPP #include -#include +#include +#include #include #include @@ -19,15 +20,6 @@ namespace boost { namespace beast { namespace websocket { -/** Tag type used to find @ref beast::websocket::teardown and @ref beast::websocket::async_teardown overloads - - Overloads of @ref beast::websocket::teardown and - @ref beast::websocket::async_teardown for user defined types - must take a value of type @ref teardown_tag in the first - argument in order to be found by the implementation. -*/ -struct teardown_tag {}; - /** Tear down a connection. This tears down a connection. The implementation will call @@ -37,13 +29,18 @@ struct teardown_tag {}; `boost::asio::ssl::stream`, callers are responsible for providing a suitable overload of this function. + @param role The role of the local endpoint + @param socket The socket to tear down. @param ec Set to the error if any occurred. */ template void -teardown(teardown_tag, Socket& socket, error_code& ec) +teardown( + role_type role, + Socket& socket, + error_code& ec) { /* If you are trying to use OpenSSL and this goes off, you need to @@ -51,7 +48,7 @@ teardown(teardown_tag, Socket& socket, error_code& ec) If you are creating an instance of beast::websocket::stream with your own user defined type, you must provide an overload of teardown with - the corresponding signature (including the teardown_tag). + the corresponding signature (including the role_type). */ static_assert(sizeof(Socket)==-1, "Unknown Socket type in teardown."); @@ -67,6 +64,8 @@ teardown(teardown_tag, Socket& socket, error_code& ec) callers are responsible for providing a suitable overload of this function. + @param role The role of the local endpoint + @param socket The socket to tear down. @param handler The handler to be called when the request completes. @@ -82,9 +81,14 @@ teardown(teardown_tag, Socket& socket, error_code& ec) manner equivalent to using boost::asio::io_service::post(). */ -template +template< + class Socket, + class TeardownHandler> void -async_teardown(teardown_tag, Socket& socket, TeardownHandler&& handler) +async_teardown( + role_type role, + Socket& socket, + TeardownHandler&& handler) { /* If you are trying to use OpenSSL and this goes off, you need to @@ -92,7 +96,7 @@ async_teardown(teardown_tag, Socket& socket, TeardownHandler&& handler) If you are creating an instance of beast::websocket::stream with your own user defined type, you must provide an overload of teardown with - the corresponding signature (including the teardown_tag). + the corresponding signature (including the role_type). */ static_assert(sizeof(Socket)==-1, "Unknown Socket type in async_teardown."); @@ -102,36 +106,6 @@ async_teardown(teardown_tag, Socket& socket, TeardownHandler&& handler) //------------------------------------------------------------------------------ -namespace websocket_helpers { - -// Calls to teardown and async_teardown must be made from -// a namespace that does not contain any overloads of these -// functions. The websocket_helpers namespace is defined here -// for that purpose. - -template -inline -void -call_teardown(Socket& socket, error_code& ec) -{ - using websocket::teardown; - teardown(websocket::teardown_tag{}, socket, ec); -} - -template -inline -void -call_async_teardown(Socket& socket, TeardownHandler&& handler) -{ - using websocket::async_teardown; - async_teardown(websocket::teardown_tag{}, socket, - std::forward(handler)); -} - -} // websocket_helpers - -//------------------------------------------------------------------------------ - namespace websocket { /** Tear down a `boost::asio::ip::tcp::socket`. @@ -143,13 +117,17 @@ namespace websocket { `boost::asio::ssl::stream`, callers are responsible for providing a suitable overload of this function. + @param role The role of the local endpoint + @param socket The socket to tear down. @param ec Set to the error if any occurred. */ void -teardown(teardown_tag, - boost::asio::ip::tcp::socket& socket, error_code& ec); +teardown( + role_type role, + boost::asio::ip::tcp::socket& socket, + error_code& ec); /** Start tearing down a `boost::asio::ip::tcp::socket`. @@ -161,6 +139,8 @@ teardown(teardown_tag, callers are responsible for providing a suitable overload of this function. + @param role The role of the local endpoint + @param socket The socket to tear down. @param handler The handler to be called when the request completes. @@ -178,8 +158,10 @@ teardown(teardown_tag, */ template void -async_teardown(teardown_tag, - boost::asio::ip::tcp::socket& socket, TeardownHandler&& handler); +async_teardown( + role_type role, + boost::asio::ip::tcp::socket& socket, + TeardownHandler&& handler); } // websocket } // beast diff --git a/test/beast/websocket/CMakeLists.txt b/test/beast/websocket/CMakeLists.txt index 3a32eba7..1374a7de 100644 --- a/test/beast/websocket/CMakeLists.txt +++ b/test/beast/websocket/CMakeLists.txt @@ -21,6 +21,7 @@ add_executable (tests-beast-websocket error.cpp option.cpp rfc6455.cpp + role.cpp stream.cpp teardown.cpp frame.cpp diff --git a/test/beast/websocket/Jamfile b/test/beast/websocket/Jamfile index 877041fc..e9e424a0 100644 --- a/test/beast/websocket/Jamfile +++ b/test/beast/websocket/Jamfile @@ -15,6 +15,7 @@ local SOURCES = teardown.cpp frame.cpp mask.cpp + role.cpp utf8_checker.cpp ; diff --git a/test/beast/websocket/role.cpp b/test/beast/websocket/role.cpp new file mode 100644 index 00000000..a6c96c9d --- /dev/null +++ b/test/beast/websocket/role.cpp @@ -0,0 +1,11 @@ +// +// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +// Test that header file is self-contained. +#include diff --git a/test/extras/include/boost/beast/test/fail_stream.hpp b/test/extras/include/boost/beast/test/fail_stream.hpp index b32a9f83..48568781 100644 --- a/test/extras/include/boost/beast/test/fail_stream.hpp +++ b/test/extras/include/boost/beast/test/fail_stream.hpp @@ -161,21 +161,24 @@ public: friend void - teardown(websocket::teardown_tag, + teardown( + websocket::role_type role, fail_stream& stream, - boost::system::error_code& ec) + boost::system::error_code& ec) { if(stream.pfc_->fail(ec)) return; - beast::websocket_helpers::call_teardown(stream.next_layer(), ec); + using beast::websocket::teardown; + teardown(role, stream.next_layer(), ec); } template friend void - async_teardown(websocket::teardown_tag, + async_teardown( + websocket::role_type role, fail_stream& stream, - TeardownHandler&& handler) + TeardownHandler&& handler) { error_code ec; if(stream.pfc_->fail(ec)) @@ -184,8 +187,9 @@ public: bind_handler(std::move(handler), ec)); return; } - beast::websocket_helpers::call_async_teardown( - stream.next_layer(), std::forward(handler)); + using beast::websocket::async_teardown; + async_teardown(role, stream.next_layer(), + std::forward(handler)); } }; diff --git a/test/extras/include/boost/beast/test/pipe_stream.hpp b/test/extras/include/boost/beast/test/pipe_stream.hpp index e58b53d9..852b2576 100644 --- a/test/extras/include/boost/beast/test/pipe_stream.hpp +++ b/test/extras/include/boost/beast/test/pipe_stream.hpp @@ -197,13 +197,15 @@ public: friend void - teardown(websocket::teardown_tag, + teardown( + websocket::role_type role, stream& s, boost::system::error_code& ec); template friend void - async_teardown(websocket::teardown_tag, + async_teardown( + websocket::role_type, stream& s, TeardownHandler&& handler); }; @@ -229,8 +231,10 @@ public: inline void -teardown(websocket::teardown_tag, - pipe::stream& s, boost::system::error_code& ec) +teardown( + websocket::role_type, + pipe::stream& s, + boost::system::error_code& ec) { if(s.fc_) { @@ -247,7 +251,7 @@ teardown(websocket::teardown_tag, template inline void -async_teardown(websocket::teardown_tag, +async_teardown(websocket::role_type, pipe::stream& s, TeardownHandler&& handler) { error_code ec; diff --git a/test/extras/include/boost/beast/test/stream.hpp b/test/extras/include/boost/beast/test/stream.hpp index b938cc0d..772c0c76 100644 --- a/test/extras/include/boost/beast/test/stream.hpp +++ b/test/extras/include/boost/beast/test/stream.hpp @@ -440,13 +440,13 @@ public: friend void - teardown(websocket::teardown_tag, + teardown(websocket::role_type, stream& s, boost::system::error_code& ec); template friend void - async_teardown(websocket::teardown_tag, + async_teardown(websocket::role_type role, stream& s, TeardownHandler&& handler); }; @@ -654,7 +654,7 @@ async_write_some(ConstBufferSequence const& buffers, inline void -teardown(websocket::teardown_tag, +teardown(websocket::role_type, stream& s, boost::system::error_code& ec) { if(s.in_.fc) @@ -672,7 +672,7 @@ teardown(websocket::teardown_tag, template inline void -async_teardown(websocket::teardown_tag, +async_teardown(websocket::role_type, stream& s, TeardownHandler&& handler) { error_code ec; diff --git a/test/extras/include/boost/beast/test/string_iostream.hpp b/test/extras/include/boost/beast/test/string_iostream.hpp index ce62d0c7..6d9454ae 100644 --- a/test/extras/include/boost/beast/test/string_iostream.hpp +++ b/test/extras/include/boost/beast/test/string_iostream.hpp @@ -150,7 +150,7 @@ public: friend void - teardown(websocket::teardown_tag, + teardown(websocket::role_type, string_iostream&, boost::system::error_code& ec) { @@ -160,7 +160,7 @@ public: template friend void - async_teardown(websocket::teardown_tag, + async_teardown(websocket::role_type, string_iostream& stream, TeardownHandler&& handler) { diff --git a/test/extras/include/boost/beast/test/string_istream.hpp b/test/extras/include/boost/beast/test/string_istream.hpp index 5587a3dc..b11a91e8 100644 --- a/test/extras/include/boost/beast/test/string_istream.hpp +++ b/test/extras/include/boost/beast/test/string_istream.hpp @@ -138,7 +138,7 @@ public: friend void - teardown(websocket::teardown_tag, + teardown(websocket::role_type, string_istream&, boost::system::error_code& ec) { @@ -148,7 +148,7 @@ public: template friend void - async_teardown(websocket::teardown_tag, + async_teardown(websocket::role_type, string_istream& stream, TeardownHandler&& handler) { diff --git a/test/extras/include/boost/beast/test/string_ostream.hpp b/test/extras/include/boost/beast/test/string_ostream.hpp index 239885cf..182bc0ed 100644 --- a/test/extras/include/boost/beast/test/string_ostream.hpp +++ b/test/extras/include/boost/beast/test/string_ostream.hpp @@ -126,7 +126,7 @@ public: friend void - teardown(websocket::teardown_tag, + teardown(websocket::role_type, string_ostream&, boost::system::error_code& ec) { @@ -136,7 +136,7 @@ public: template friend void - async_teardown(websocket::teardown_tag, + async_teardown(websocket::role_type, string_ostream& stream, TeardownHandler&& handler) {