File indexing completed on 2025-07-12 08:08:50
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_WEBSOCKET_IMPL_TEARDOWN_HPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_TEARDOWN_HPP
0012
0013 #include <boost/beast/core/async_base.hpp>
0014 #include <boost/beast/core/stream_traits.hpp>
0015 #include <boost/beast/core/detail/bind_continuation.hpp>
0016 #include <boost/beast/core/detail/is_invocable.hpp>
0017 #include <boost/asio/append.hpp>
0018 #include <boost/asio/coroutine.hpp>
0019 #include <boost/asio/dispatch.hpp>
0020 #include <memory>
0021
0022 namespace boost {
0023 namespace beast {
0024 namespace websocket {
0025
0026 namespace detail {
0027
0028 template<
0029 class Protocol, class Executor,
0030 class Handler>
0031 class teardown_tcp_op
0032 : public beast::async_base<
0033 Handler, beast::executor_type<
0034 net::basic_stream_socket<
0035 Protocol, Executor>>>
0036 , public asio::coroutine
0037 {
0038 using socket_type =
0039 net::basic_stream_socket<Protocol, Executor>;
0040
0041 socket_type& s_;
0042 role_type role_;
0043 bool nb_;
0044
0045 public:
0046 template<class Handler_>
0047 teardown_tcp_op(
0048 Handler_&& h,
0049 socket_type& s,
0050 role_type role)
0051 : async_base<Handler,
0052 beast::executor_type<
0053 net::basic_stream_socket<
0054 Protocol, Executor>>>(
0055 std::forward<Handler_>(h),
0056 s.get_executor())
0057 , s_(s)
0058 , role_(role)
0059 , nb_(false)
0060 {
0061 (*this)({}, 0, false);
0062 this->set_allowed_cancellation(net::cancellation_type::all);
0063 }
0064
0065 void
0066 operator()(
0067 error_code ec = {},
0068 std::size_t bytes_transferred = 0,
0069 bool cont = true)
0070 {
0071 BOOST_ASIO_CORO_REENTER(*this)
0072 {
0073 nb_ = s_.non_blocking();
0074 s_.non_blocking(true, ec);
0075 if(ec)
0076 goto upcall;
0077 if(role_ == role_type::server)
0078 s_.shutdown(net::socket_base::shutdown_send, ec);
0079 if(ec)
0080 goto upcall;
0081 for(;;)
0082 {
0083 {
0084 char buf[2048];
0085 s_.read_some(net::buffer(buf), ec);
0086 }
0087 if(ec == net::error::would_block)
0088 {
0089 BOOST_ASIO_CORO_YIELD
0090 {
0091 BOOST_ASIO_HANDLER_LOCATION((
0092 __FILE__, __LINE__,
0093 "websocket::tcp::async_teardown"
0094 ));
0095
0096 s_.async_wait(
0097 net::socket_base::wait_read,
0098 beast::detail::bind_continuation(std::move(*this)));
0099 }
0100 continue;
0101 }
0102 if(ec)
0103 {
0104 if(ec != net::error::eof)
0105 goto upcall;
0106 ec = {};
0107 break;
0108 }
0109 if(bytes_transferred == 0)
0110 {
0111
0112
0113 break;
0114 }
0115 }
0116 if(role_ == role_type::client)
0117 s_.shutdown(net::socket_base::shutdown_send, ec);
0118 if(ec)
0119 goto upcall;
0120 s_.close(ec);
0121 upcall:
0122 if(! cont)
0123 {
0124 BOOST_ASIO_CORO_YIELD
0125 {
0126 BOOST_ASIO_HANDLER_LOCATION((
0127 __FILE__, __LINE__,
0128 "websocket::tcp::async_teardown"
0129 ));
0130
0131 const auto ex = this->get_immediate_executor();
0132 net::dispatch(ex, net::append(std::move(*this), ec));
0133 }
0134 }
0135 {
0136 error_code ignored;
0137 s_.non_blocking(nb_, ignored);
0138 }
0139 this->complete_now(ec);
0140 }
0141 }
0142 };
0143
0144 }
0145
0146
0147
0148 template<class Protocol, class Executor>
0149 void
0150 teardown(
0151 role_type role,
0152 net::basic_stream_socket<
0153 Protocol, Executor>& socket,
0154 error_code& ec)
0155 {
0156 if(role == role_type::server)
0157 socket.shutdown(
0158 net::socket_base::shutdown_send, ec);
0159 if(ec)
0160 return;
0161 for(;;)
0162 {
0163 char buf[2048];
0164 auto const bytes_transferred =
0165 socket.read_some(net::buffer(buf), ec);
0166 if(ec)
0167 {
0168 if(ec != net::error::eof)
0169 return;
0170 ec = {};
0171 break;
0172 }
0173 if(bytes_transferred == 0)
0174 {
0175
0176
0177 break;
0178 }
0179 }
0180 if(role == role_type::client)
0181 socket.shutdown(
0182 net::socket_base::shutdown_send, ec);
0183 if(ec)
0184 return;
0185 socket.close(ec);
0186 }
0187
0188 template<
0189 class Protocol, class Executor,
0190 class TeardownHandler>
0191 void
0192 async_teardown(
0193 role_type role,
0194 net::basic_stream_socket<
0195 Protocol, Executor>& socket,
0196 TeardownHandler&& handler)
0197 {
0198 static_assert(beast::detail::is_invocable<
0199 TeardownHandler, void(error_code)>::value,
0200 "TeardownHandler type requirements not met");
0201 detail::teardown_tcp_op<
0202 Protocol,
0203 Executor,
0204 typename std::decay<TeardownHandler>::type>(
0205 std::forward<TeardownHandler>(handler),
0206 socket,
0207 role);
0208 }
0209
0210 }
0211 }
0212 }
0213
0214 #endif