teardown.hpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_WEBSOCKET_IMPL_TEARDOWN_HPP
  10. #define BOOST_BEAST_WEBSOCKET_IMPL_TEARDOWN_HPP
  11. #include <boost/beast/core/async_base.hpp>
  12. #include <boost/beast/core/stream_traits.hpp>
  13. #include <boost/beast/core/detail/bind_continuation.hpp>
  14. #include <boost/beast/core/detail/is_invocable.hpp>
  15. #include <boost/asio/append.hpp>
  16. #include <boost/asio/coroutine.hpp>
  17. #include <boost/asio/dispatch.hpp>
  18. #include <memory>
  19. namespace boost {
  20. namespace beast {
  21. namespace websocket {
  22. namespace detail {
  23. template<
  24. class Protocol, class Executor,
  25. class Handler>
  26. class teardown_tcp_op
  27. : public beast::async_base<
  28. Handler, beast::executor_type<
  29. net::basic_stream_socket<
  30. Protocol, Executor>>>
  31. , public asio::coroutine
  32. {
  33. using socket_type =
  34. net::basic_stream_socket<Protocol, Executor>;
  35. socket_type& s_;
  36. role_type role_;
  37. bool nb_;
  38. public:
  39. template<class Handler_>
  40. teardown_tcp_op(
  41. Handler_&& h,
  42. socket_type& s,
  43. role_type role)
  44. : async_base<Handler,
  45. beast::executor_type<
  46. net::basic_stream_socket<
  47. Protocol, Executor>>>(
  48. std::forward<Handler_>(h),
  49. s.get_executor())
  50. , s_(s)
  51. , role_(role)
  52. , nb_(false)
  53. {
  54. (*this)({}, 0, false);
  55. this->set_allowed_cancellation(net::cancellation_type::all);
  56. }
  57. void
  58. operator()(
  59. error_code ec = {},
  60. std::size_t bytes_transferred = 0,
  61. bool cont = true)
  62. {
  63. BOOST_ASIO_CORO_REENTER(*this)
  64. {
  65. nb_ = s_.non_blocking();
  66. s_.non_blocking(true, ec);
  67. if(ec)
  68. goto upcall;
  69. if(role_ == role_type::server)
  70. s_.shutdown(net::socket_base::shutdown_send, ec);
  71. if(ec)
  72. goto upcall;
  73. for(;;)
  74. {
  75. {
  76. char buf[2048];
  77. s_.read_some(net::buffer(buf), ec);
  78. }
  79. if(ec == net::error::would_block)
  80. {
  81. BOOST_ASIO_CORO_YIELD
  82. {
  83. BOOST_ASIO_HANDLER_LOCATION((
  84. __FILE__, __LINE__,
  85. "websocket::tcp::async_teardown"
  86. ));
  87. s_.async_wait(
  88. net::socket_base::wait_read,
  89. beast::detail::bind_continuation(std::move(*this)));
  90. }
  91. continue;
  92. }
  93. if(ec)
  94. {
  95. if(ec != net::error::eof)
  96. goto upcall;
  97. ec = {};
  98. break;
  99. }
  100. if(bytes_transferred == 0)
  101. {
  102. // happens sometimes
  103. // https://github.com/boostorg/beast/issues/1373
  104. break;
  105. }
  106. }
  107. if(role_ == role_type::client)
  108. s_.shutdown(net::socket_base::shutdown_send, ec);
  109. if(ec)
  110. goto upcall;
  111. s_.close(ec);
  112. upcall:
  113. if(! cont)
  114. {
  115. BOOST_ASIO_CORO_YIELD
  116. {
  117. BOOST_ASIO_HANDLER_LOCATION((
  118. __FILE__, __LINE__,
  119. "websocket::tcp::async_teardown"
  120. ));
  121. const auto ex = this->get_immediate_executor();
  122. net::dispatch(ex, net::append(std::move(*this), ec));
  123. }
  124. }
  125. {
  126. error_code ignored;
  127. s_.non_blocking(nb_, ignored);
  128. }
  129. this->complete_now(ec);
  130. }
  131. }
  132. };
  133. } // detail
  134. //------------------------------------------------------------------------------
  135. template<class Protocol, class Executor>
  136. void
  137. teardown(
  138. role_type role,
  139. net::basic_stream_socket<
  140. Protocol, Executor>& socket,
  141. error_code& ec)
  142. {
  143. if(role == role_type::server)
  144. socket.shutdown(
  145. net::socket_base::shutdown_send, ec);
  146. if(ec)
  147. return;
  148. for(;;)
  149. {
  150. char buf[2048];
  151. auto const bytes_transferred =
  152. socket.read_some(net::buffer(buf), ec);
  153. if(ec)
  154. {
  155. if(ec != net::error::eof)
  156. return;
  157. ec = {};
  158. break;
  159. }
  160. if(bytes_transferred == 0)
  161. {
  162. // happens sometimes
  163. // https://github.com/boostorg/beast/issues/1373
  164. break;
  165. }
  166. }
  167. if(role == role_type::client)
  168. socket.shutdown(
  169. net::socket_base::shutdown_send, ec);
  170. if(ec)
  171. return;
  172. socket.close(ec);
  173. }
  174. template<
  175. class Protocol, class Executor,
  176. class TeardownHandler>
  177. void
  178. async_teardown(
  179. role_type role,
  180. net::basic_stream_socket<
  181. Protocol, Executor>& socket,
  182. TeardownHandler&& handler)
  183. {
  184. static_assert(beast::detail::is_invocable<
  185. TeardownHandler, void(error_code)>::value,
  186. "TeardownHandler type requirements not met");
  187. detail::teardown_tcp_op<
  188. Protocol,
  189. Executor,
  190. typename std::decay<TeardownHandler>::type>(
  191. std::forward<TeardownHandler>(handler),
  192. socket,
  193. role);
  194. }
  195. } // websocket
  196. } // beast
  197. } // boost
  198. #endif