teardown.hpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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 BHO_BEAST_WEBSOCKET_IMPL_TEARDOWN_HPP
  10. #define BHO_BEAST_WEBSOCKET_IMPL_TEARDOWN_HPP
  11. #include <asio2/bho/beast/core/async_base.hpp>
  12. #include <asio2/bho/beast/core/bind_handler.hpp>
  13. #include <asio2/bho/beast/core/stream_traits.hpp>
  14. #include <asio2/bho/beast/core/detail/bind_continuation.hpp>
  15. #include <asio2/bho/beast/core/detail/is_invocable.hpp>
  16. #include <asio/coroutine.hpp>
  17. #include <asio/dispatch.hpp>
  18. #include <memory>
  19. namespace bho {
  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. 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. ASIO_CORO_YIELD
  82. {
  83. 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. ASIO_CORO_YIELD
  116. {
  117. ASIO_HANDLER_LOCATION((
  118. __FILE__, __LINE__,
  119. "websocket::tcp::async_teardown"
  120. ));
  121. const auto ex = this->get_immediate_executor();
  122. net::dispatch(ex, bind_front_handler(
  123. std::move(*this), ec));
  124. }
  125. }
  126. {
  127. error_code ignored;
  128. s_.non_blocking(nb_, ignored);
  129. }
  130. this->complete_now(ec);
  131. }
  132. }
  133. };
  134. } // detail
  135. //------------------------------------------------------------------------------
  136. template<class Protocol, class Executor>
  137. void
  138. teardown(
  139. role_type role,
  140. net::basic_stream_socket<
  141. Protocol, Executor>& socket,
  142. error_code& ec)
  143. {
  144. if(role == role_type::server)
  145. socket.shutdown(
  146. net::socket_base::shutdown_send, ec);
  147. if(ec)
  148. return;
  149. for(;;)
  150. {
  151. char buf[2048];
  152. auto const bytes_transferred =
  153. socket.read_some(net::buffer(buf), ec);
  154. if(ec)
  155. {
  156. if(ec != net::error::eof)
  157. return;
  158. ec = {};
  159. break;
  160. }
  161. if(bytes_transferred == 0)
  162. {
  163. // happens sometimes
  164. // https://github.com/boostorg/beast/issues/1373
  165. break;
  166. }
  167. }
  168. if(role == role_type::client)
  169. socket.shutdown(
  170. net::socket_base::shutdown_send, ec);
  171. if(ec)
  172. return;
  173. socket.close(ec);
  174. }
  175. template<
  176. class Protocol, class Executor,
  177. class TeardownHandler>
  178. void
  179. async_teardown(
  180. role_type role,
  181. net::basic_stream_socket<
  182. Protocol, Executor>& socket,
  183. TeardownHandler&& handler)
  184. {
  185. static_assert(beast::detail::is_invocable<
  186. TeardownHandler, void(error_code)>::value,
  187. "TeardownHandler type requirements not met");
  188. detail::teardown_tcp_op<
  189. Protocol,
  190. Executor,
  191. typename std::decay<TeardownHandler>::type>(
  192. std::forward<TeardownHandler>(handler),
  193. socket,
  194. role);
  195. }
  196. } // websocket
  197. } // beast
  198. } // bho
  199. #endif