File indexing completed on 2025-01-18 09:29:35
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/bind_handler.hpp>
0015 #include <boost/beast/core/stream_traits.hpp>
0016 #include <boost/beast/core/detail/bind_continuation.hpp>
0017 #include <boost/beast/core/detail/is_invocable.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, bind_front_handler(
0133 std::move(*this), ec));
0134 }
0135 }
0136 {
0137 error_code ignored;
0138 s_.non_blocking(nb_, ignored);
0139 }
0140 this->complete_now(ec);
0141 }
0142 }
0143 };
0144
0145 }
0146
0147
0148
0149 template<class Protocol, class Executor>
0150 void
0151 teardown(
0152 role_type role,
0153 net::basic_stream_socket<
0154 Protocol, Executor>& socket,
0155 error_code& ec)
0156 {
0157 if(role == role_type::server)
0158 socket.shutdown(
0159 net::socket_base::shutdown_send, ec);
0160 if(ec)
0161 return;
0162 for(;;)
0163 {
0164 char buf[2048];
0165 auto const bytes_transferred =
0166 socket.read_some(net::buffer(buf), ec);
0167 if(ec)
0168 {
0169 if(ec != net::error::eof)
0170 return;
0171 ec = {};
0172 break;
0173 }
0174 if(bytes_transferred == 0)
0175 {
0176
0177
0178 break;
0179 }
0180 }
0181 if(role == role_type::client)
0182 socket.shutdown(
0183 net::socket_base::shutdown_send, ec);
0184 if(ec)
0185 return;
0186 socket.close(ec);
0187 }
0188
0189 template<
0190 class Protocol, class Executor,
0191 class TeardownHandler>
0192 void
0193 async_teardown(
0194 role_type role,
0195 net::basic_stream_socket<
0196 Protocol, Executor>& socket,
0197 TeardownHandler&& handler)
0198 {
0199 static_assert(beast::detail::is_invocable<
0200 TeardownHandler, void(error_code)>::value,
0201 "TeardownHandler type requirements not met");
0202 detail::teardown_tcp_op<
0203 Protocol,
0204 Executor,
0205 typename std::decay<TeardownHandler>::type>(
0206 std::forward<TeardownHandler>(handler),
0207 socket,
0208 role);
0209 }
0210
0211 }
0212 }
0213 }
0214
0215 #endif