reactive_socket_service_base.ipp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. //
  2. // detail/reactive_socket_service_base.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
  11. #define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #if !defined(BOOST_ASIO_HAS_IOCP) \
  17. && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
  18. #include <boost/asio/detail/reactive_socket_service_base.hpp>
  19. #include <boost/asio/detail/push_options.hpp>
  20. namespace boost {
  21. namespace asio {
  22. namespace detail {
  23. reactive_socket_service_base::reactive_socket_service_base(
  24. boost::asio::io_context& io_context)
  25. : io_context_(io_context),
  26. reactor_(use_service<reactor>(io_context))
  27. {
  28. reactor_.init_task();
  29. }
  30. void reactive_socket_service_base::base_shutdown()
  31. {
  32. }
  33. void reactive_socket_service_base::construct(
  34. reactive_socket_service_base::base_implementation_type& impl)
  35. {
  36. impl.socket_ = invalid_socket;
  37. impl.state_ = 0;
  38. }
  39. void reactive_socket_service_base::base_move_construct(
  40. reactive_socket_service_base::base_implementation_type& impl,
  41. reactive_socket_service_base::base_implementation_type& other_impl)
  42. {
  43. impl.socket_ = other_impl.socket_;
  44. other_impl.socket_ = invalid_socket;
  45. impl.state_ = other_impl.state_;
  46. other_impl.state_ = 0;
  47. reactor_.move_descriptor(impl.socket_,
  48. impl.reactor_data_, other_impl.reactor_data_);
  49. }
  50. void reactive_socket_service_base::base_move_assign(
  51. reactive_socket_service_base::base_implementation_type& impl,
  52. reactive_socket_service_base& other_service,
  53. reactive_socket_service_base::base_implementation_type& other_impl)
  54. {
  55. destroy(impl);
  56. impl.socket_ = other_impl.socket_;
  57. other_impl.socket_ = invalid_socket;
  58. impl.state_ = other_impl.state_;
  59. other_impl.state_ = 0;
  60. other_service.reactor_.move_descriptor(impl.socket_,
  61. impl.reactor_data_, other_impl.reactor_data_);
  62. }
  63. void reactive_socket_service_base::destroy(
  64. reactive_socket_service_base::base_implementation_type& impl)
  65. {
  66. if (impl.socket_ != invalid_socket)
  67. {
  68. BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
  69. "socket", &impl, impl.socket_, "close"));
  70. reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
  71. (impl.state_ & socket_ops::possible_dup) == 0);
  72. boost::system::error_code ignored_ec;
  73. socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
  74. reactor_.cleanup_descriptor_data(impl.reactor_data_);
  75. }
  76. }
  77. boost::system::error_code reactive_socket_service_base::close(
  78. reactive_socket_service_base::base_implementation_type& impl,
  79. boost::system::error_code& ec)
  80. {
  81. if (is_open(impl))
  82. {
  83. BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
  84. "socket", &impl, impl.socket_, "close"));
  85. reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
  86. (impl.state_ & socket_ops::possible_dup) == 0);
  87. socket_ops::close(impl.socket_, impl.state_, false, ec);
  88. reactor_.cleanup_descriptor_data(impl.reactor_data_);
  89. }
  90. else
  91. {
  92. ec = boost::system::error_code();
  93. }
  94. // The descriptor is closed by the OS even if close() returns an error.
  95. //
  96. // (Actually, POSIX says the state of the descriptor is unspecified. On
  97. // Linux the descriptor is apparently closed anyway; e.g. see
  98. // http://lkml.org/lkml/2005/9/10/129
  99. // We'll just have to assume that other OSes follow the same behaviour. The
  100. // known exception is when Windows's closesocket() function fails with
  101. // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().
  102. construct(impl);
  103. return ec;
  104. }
  105. socket_type reactive_socket_service_base::release(
  106. reactive_socket_service_base::base_implementation_type& impl,
  107. boost::system::error_code& ec)
  108. {
  109. if (!is_open(impl))
  110. {
  111. ec = boost::asio::error::bad_descriptor;
  112. return invalid_socket;
  113. }
  114. BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
  115. "socket", &impl, impl.socket_, "release"));
  116. reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false);
  117. reactor_.cleanup_descriptor_data(impl.reactor_data_);
  118. socket_type sock = impl.socket_;
  119. construct(impl);
  120. ec = boost::system::error_code();
  121. return sock;
  122. }
  123. boost::system::error_code reactive_socket_service_base::cancel(
  124. reactive_socket_service_base::base_implementation_type& impl,
  125. boost::system::error_code& ec)
  126. {
  127. if (!is_open(impl))
  128. {
  129. ec = boost::asio::error::bad_descriptor;
  130. return ec;
  131. }
  132. BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
  133. "socket", &impl, impl.socket_, "cancel"));
  134. reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
  135. ec = boost::system::error_code();
  136. return ec;
  137. }
  138. boost::system::error_code reactive_socket_service_base::do_open(
  139. reactive_socket_service_base::base_implementation_type& impl,
  140. int af, int type, int protocol, boost::system::error_code& ec)
  141. {
  142. if (is_open(impl))
  143. {
  144. ec = boost::asio::error::already_open;
  145. return ec;
  146. }
  147. socket_holder sock(socket_ops::socket(af, type, protocol, ec));
  148. if (sock.get() == invalid_socket)
  149. return ec;
  150. if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
  151. {
  152. ec = boost::system::error_code(err,
  153. boost::asio::error::get_system_category());
  154. return ec;
  155. }
  156. impl.socket_ = sock.release();
  157. switch (type)
  158. {
  159. case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
  160. case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
  161. default: impl.state_ = 0; break;
  162. }
  163. ec = boost::system::error_code();
  164. return ec;
  165. }
  166. boost::system::error_code reactive_socket_service_base::do_assign(
  167. reactive_socket_service_base::base_implementation_type& impl, int type,
  168. const reactive_socket_service_base::native_handle_type& native_socket,
  169. boost::system::error_code& ec)
  170. {
  171. if (is_open(impl))
  172. {
  173. ec = boost::asio::error::already_open;
  174. return ec;
  175. }
  176. if (int err = reactor_.register_descriptor(
  177. native_socket, impl.reactor_data_))
  178. {
  179. ec = boost::system::error_code(err,
  180. boost::asio::error::get_system_category());
  181. return ec;
  182. }
  183. impl.socket_ = native_socket;
  184. switch (type)
  185. {
  186. case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
  187. case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
  188. default: impl.state_ = 0; break;
  189. }
  190. impl.state_ |= socket_ops::possible_dup;
  191. ec = boost::system::error_code();
  192. return ec;
  193. }
  194. void reactive_socket_service_base::start_op(
  195. reactive_socket_service_base::base_implementation_type& impl,
  196. int op_type, reactor_op* op, bool is_continuation,
  197. bool is_non_blocking, bool noop)
  198. {
  199. if (!noop)
  200. {
  201. if ((impl.state_ & socket_ops::non_blocking)
  202. || socket_ops::set_internal_non_blocking(
  203. impl.socket_, impl.state_, true, op->ec_))
  204. {
  205. reactor_.start_op(op_type, impl.socket_,
  206. impl.reactor_data_, op, is_continuation, is_non_blocking);
  207. return;
  208. }
  209. }
  210. reactor_.post_immediate_completion(op, is_continuation);
  211. }
  212. void reactive_socket_service_base::start_accept_op(
  213. reactive_socket_service_base::base_implementation_type& impl,
  214. reactor_op* op, bool is_continuation, bool peer_is_open)
  215. {
  216. if (!peer_is_open)
  217. start_op(impl, reactor::read_op, op, is_continuation, true, false);
  218. else
  219. {
  220. op->ec_ = boost::asio::error::already_open;
  221. reactor_.post_immediate_completion(op, is_continuation);
  222. }
  223. }
  224. void reactive_socket_service_base::start_connect_op(
  225. reactive_socket_service_base::base_implementation_type& impl,
  226. reactor_op* op, bool is_continuation,
  227. const socket_addr_type* addr, size_t addrlen)
  228. {
  229. if ((impl.state_ & socket_ops::non_blocking)
  230. || socket_ops::set_internal_non_blocking(
  231. impl.socket_, impl.state_, true, op->ec_))
  232. {
  233. if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
  234. {
  235. if (op->ec_ == boost::asio::error::in_progress
  236. || op->ec_ == boost::asio::error::would_block)
  237. {
  238. op->ec_ = boost::system::error_code();
  239. reactor_.start_op(reactor::connect_op, impl.socket_,
  240. impl.reactor_data_, op, is_continuation, false);
  241. return;
  242. }
  243. }
  244. }
  245. reactor_.post_immediate_completion(op, is_continuation);
  246. }
  247. } // namespace detail
  248. } // namespace asio
  249. } // namespace boost
  250. #include <boost/asio/detail/pop_options.hpp>
  251. #endif // !defined(BOOST_ASIO_HAS_IOCP)
  252. // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
  253. #endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP