teardown.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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/bind_handler.hpp>
  13. #include <boost/beast/core/stream_traits.hpp>
  14. #include <boost/beast/core/detail/bind_continuation.hpp>
  15. #include <boost/beast/core/detail/is_invocable.hpp>
  16. #include <boost/asio/coroutine.hpp>
  17. #include <boost/asio/post.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. }
  56. void
  57. operator()(
  58. error_code ec = {},
  59. std::size_t bytes_transferred = 0,
  60. bool cont = true)
  61. {
  62. BOOST_ASIO_CORO_REENTER(*this)
  63. {
  64. nb_ = s_.non_blocking();
  65. s_.non_blocking(true, ec);
  66. if(ec)
  67. goto upcall;
  68. if(role_ == role_type::server)
  69. s_.shutdown(net::socket_base::shutdown_send, ec);
  70. if(ec)
  71. goto upcall;
  72. for(;;)
  73. {
  74. {
  75. char buf[2048];
  76. s_.read_some(net::buffer(buf), ec);
  77. }
  78. if(ec == net::error::would_block)
  79. {
  80. BOOST_ASIO_CORO_YIELD
  81. {
  82. BOOST_ASIO_HANDLER_LOCATION((
  83. __FILE__, __LINE__,
  84. "websocket::tcp::async_teardown"
  85. ));
  86. s_.async_wait(
  87. net::socket_base::wait_read,
  88. beast::detail::bind_continuation(std::move(*this)));
  89. }
  90. continue;
  91. }
  92. if(ec)
  93. {
  94. if(ec != net::error::eof)
  95. goto upcall;
  96. ec = {};
  97. break;
  98. }
  99. if(bytes_transferred == 0)
  100. {
  101. // happens sometimes
  102. // https://github.com/boostorg/beast/issues/1373
  103. break;
  104. }
  105. }
  106. if(role_ == role_type::client)
  107. s_.shutdown(net::socket_base::shutdown_send, ec);
  108. if(ec)
  109. goto upcall;
  110. s_.close(ec);
  111. upcall:
  112. if(! cont)
  113. {
  114. BOOST_ASIO_CORO_YIELD
  115. {
  116. BOOST_ASIO_HANDLER_LOCATION((
  117. __FILE__, __LINE__,
  118. "websocket::tcp::async_teardown"
  119. ));
  120. net::post(bind_front_handler(
  121. std::move(*this), ec));
  122. }
  123. }
  124. {
  125. error_code ignored;
  126. s_.non_blocking(nb_, ignored);
  127. }
  128. this->complete_now(ec);
  129. }
  130. }
  131. };
  132. } // detail
  133. //------------------------------------------------------------------------------
  134. template<class Protocol, class Executor>
  135. void
  136. teardown(
  137. role_type role,
  138. net::basic_stream_socket<
  139. Protocol, Executor>& socket,
  140. error_code& ec)
  141. {
  142. if(role == role_type::server)
  143. socket.shutdown(
  144. net::socket_base::shutdown_send, ec);
  145. if(ec)
  146. return;
  147. for(;;)
  148. {
  149. char buf[2048];
  150. auto const bytes_transferred =
  151. socket.read_some(net::buffer(buf), ec);
  152. if(ec)
  153. {
  154. if(ec != net::error::eof)
  155. return;
  156. ec = {};
  157. break;
  158. }
  159. if(bytes_transferred == 0)
  160. {
  161. // happens sometimes
  162. // https://github.com/boostorg/beast/issues/1373
  163. break;
  164. }
  165. }
  166. if(role == role_type::client)
  167. socket.shutdown(
  168. net::socket_base::shutdown_send, ec);
  169. if(ec)
  170. return;
  171. socket.close(ec);
  172. }
  173. template<
  174. class Protocol, class Executor,
  175. class TeardownHandler>
  176. void
  177. async_teardown(
  178. role_type role,
  179. net::basic_stream_socket<
  180. Protocol, Executor>& socket,
  181. TeardownHandler&& handler)
  182. {
  183. static_assert(beast::detail::is_invocable<
  184. TeardownHandler, void(error_code)>::value,
  185. "TeardownHandler type requirements not met");
  186. detail::teardown_tcp_op<
  187. Protocol,
  188. Executor,
  189. typename std::decay<TeardownHandler>::type>(
  190. std::forward<TeardownHandler>(handler),
  191. socket,
  192. role);
  193. }
  194. } // websocket
  195. } // beast
  196. } // boost
  197. #endif