diff --git a/CHANGELOG.md b/CHANGELOG.md index 6451d3e8..12f312fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Version 157: + +* Fix teardown for TIME_WAIT + +-------------------------------------------------------------------------------- + Version 156: * Don't use typeid diff --git a/doc/qbk/09_releases.qbk b/doc/qbk/09_releases.qbk index 36e07ae8..08767be9 100644 --- a/doc/qbk/09_releases.qbk +++ b/doc/qbk/09_releases.qbk @@ -103,9 +103,11 @@ to update to the latest Boost release. * [issue 1019] Fix fallthrough warnings +* [issue 1024] Fix teardown for TIME_WAIT + [*API Changes] -* [issue 1029] Remove unintended public members of +* Remove unintended public members of [link beast.ref.boost__beast__handler_ptr `handler_ptr`]. Actions required: don't call non-public members. @@ -115,7 +117,7 @@ to update to the latest Boost release. to manage state can only be moved, not copied. * [link beast.ref.boost__beast__handler_ptr `handler_ptr`] - gives the strong exception guarantee. The signature + gives the strong exception guarantee. The constructor signature for managed objects constructed by `handler_ptr` now receives a `const` reference to the handler. Actions required: Change the constructor signature for state objects used with `handler_ptr` 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 c6337ae6..9c4dfc35 100644 --- a/example/websocket/client/async-ssl/websocket_client_async_ssl.cpp +++ b/example/websocket/client/async-ssl/websocket_client_async_ssl.cpp @@ -225,7 +225,7 @@ int main(int argc, char** argv) std::make_shared(ioc, ctx)->run(host, port, text); // Run the I/O service. The call will return when - // the get operation is complete. + // the socket is closed. ioc.run(); return EXIT_SUCCESS; diff --git a/example/websocket/client/async/websocket_client_async.cpp b/example/websocket/client/async/websocket_client_async.cpp index e09f6a5b..98505dd1 100644 --- a/example/websocket/client/async/websocket_client_async.cpp +++ b/example/websocket/client/async/websocket_client_async.cpp @@ -199,7 +199,7 @@ int main(int argc, char** argv) std::make_shared(ioc)->run(host, port, text); // Run the I/O service. The call will return when - // the get operation is complete. + // the socket is closed. ioc.run(); return EXIT_SUCCESS; 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 6fed0d05..c5c5cb94 100644 --- a/example/websocket/client/coro-ssl/websocket_client_coro_ssl.cpp +++ b/example/websocket/client/coro-ssl/websocket_client_coro_ssl.cpp @@ -137,7 +137,7 @@ int main(int argc, char** argv) std::placeholders::_1)); // Run the I/O service. The call will return when - // the get operation is complete. + // the socket is closed. ioc.run(); return EXIT_SUCCESS; diff --git a/example/websocket/client/coro/websocket_client_coro.cpp b/example/websocket/client/coro/websocket_client_coro.cpp index 5aa4c755..d88d8259 100644 --- a/example/websocket/client/coro/websocket_client_coro.cpp +++ b/example/websocket/client/coro/websocket_client_coro.cpp @@ -119,7 +119,7 @@ int main(int argc, char** argv) std::placeholders::_1)); // Run the I/O service. The call will return when - // the get operation is complete. + // the socket is closed. ioc.run(); return EXIT_SUCCESS; diff --git a/include/boost/beast/websocket/impl/teardown.ipp b/include/boost/beast/websocket/impl/teardown.ipp index d81c6064..f5b572e4 100644 --- a/include/boost/beast/websocket/impl/teardown.ipp +++ b/include/boost/beast/websocket/impl/teardown.ipp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,7 @@ namespace websocket { namespace detail { template -class teardown_tcp_op +class teardown_tcp_op : public boost::asio::coroutine { using socket_type = boost::asio::ip::tcp::socket; @@ -33,7 +34,7 @@ class teardown_tcp_op Handler h_; socket_type& s_; role_type role_; - int step_ = 0; + bool nb_; public: teardown_tcp_op(teardown_tcp_op&& other) = default; @@ -73,65 +74,72 @@ public: operator()( error_code ec = {}, std::size_t bytes_transferred = 0); - - friend - bool asio_handler_is_continuation(teardown_tcp_op* op) - { - using boost::asio::asio_handler_is_continuation; - return op->step_ >= 3 || - asio_handler_is_continuation(std::addressof(op->h_)); - } }; template void teardown_tcp_op:: -operator()(error_code ec, std::size_t) +operator()(error_code ec, std::size_t bytes_transferred) { using boost::asio::buffer; using tcp = boost::asio::ip::tcp; - switch(step_) + BOOST_ASIO_CORO_REENTER(*this) { - case 0: + nb_ = s_.non_blocking(); s_.non_blocking(true, ec); + if(! ec) + { + if(role_ == role_type::server) + s_.shutdown(tcp::socket::shutdown_send, ec); + } if(ec) { - step_ = 1; - return boost::asio::post( + BOOST_ASIO_CORO_YIELD + boost::asio::post( s_.get_executor(), bind_handler(std::move(*this), ec, 0)); + goto upcall; } - step_ = 2; - if(role_ == role_type::server) - s_.shutdown(tcp::socket::shutdown_send, ec); - goto do_read; - - case 1: - break; - - case 2: - step_ = 3; BOOST_FALLTHROUGH; - - case 3: - if(ec != boost::asio::error::would_block) - break; + for(;;) { - char buf[2048]; - s_.read_some( - boost::asio::buffer(buf), ec); + { + char buf[2048]; + s_.read_some( + boost::asio::buffer(buf), ec); + } + if(ec == boost::asio::error::would_block) + { + BOOST_ASIO_CORO_YIELD + s_.async_wait( + boost::asio::ip::tcp::socket::wait_read, + std::move(*this)); + continue; + } if(ec) + { + if(ec != boost::asio::error::eof) + goto upcall; + ec = {}; break; + } + if(bytes_transferred == 0) + { + // happens sometimes + break; + } } - - do_read: - return s_.async_wait( - boost::asio::ip::tcp::socket::wait_read, - std::move(*this)); + if(role_ == role_type::client) + s_.shutdown(tcp::socket::shutdown_send, ec); + if(ec) + goto upcall; + s_.close(ec); + upcall: + { + error_code ignored; + s_.non_blocking(nb_, ignored); + } + h_(ec); } - if(role_ == role_type::client) - s_.shutdown(tcp::socket::shutdown_send, ec); - s_.close(ec); - h_(ec); } } // detail @@ -149,17 +157,31 @@ teardown( if(role == role_type::server) socket.shutdown( boost::asio::ip::tcp::socket::shutdown_send, ec); - while(! ec) + if(ec) + return; + for(;;) { - char buf[8192]; - auto const n = socket.read_some( - buffer(buf), ec); - if(! n) + char buf[2048]; + auto const bytes_transferred = + socket.read_some(buffer(buf), ec); + if(ec) + { + if(ec != boost::asio::error::eof) + return; + ec = {}; break; + } + if(bytes_transferred == 0) + { + // happens sometimes + break; + } } if(role == role_type::client) socket.shutdown( boost::asio::ip::tcp::socket::shutdown_send, ec); + if(ec) + return; socket.close(ec); }