teardown.hpp 5.1 KB

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