reactive_descriptor_service.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. //
  2. // detail/reactive_descriptor_service.hpp
  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_REACTIVE_DESCRIPTOR_SERVICE_HPP
  11. #define BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
  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_WINDOWS) \
  17. && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
  18. && !defined(__CYGWIN__)
  19. #include <boost/asio/buffer.hpp>
  20. #include <boost/asio/io_context.hpp>
  21. #include <boost/asio/detail/bind_handler.hpp>
  22. #include <boost/asio/detail/buffer_sequence_adapter.hpp>
  23. #include <boost/asio/detail/descriptor_ops.hpp>
  24. #include <boost/asio/detail/descriptor_read_op.hpp>
  25. #include <boost/asio/detail/descriptor_write_op.hpp>
  26. #include <boost/asio/detail/fenced_block.hpp>
  27. #include <boost/asio/detail/memory.hpp>
  28. #include <boost/asio/detail/noncopyable.hpp>
  29. #include <boost/asio/detail/reactive_null_buffers_op.hpp>
  30. #include <boost/asio/detail/reactive_wait_op.hpp>
  31. #include <boost/asio/detail/reactor.hpp>
  32. #include <boost/asio/posix/descriptor_base.hpp>
  33. #include <boost/asio/detail/push_options.hpp>
  34. namespace boost {
  35. namespace asio {
  36. namespace detail {
  37. class reactive_descriptor_service :
  38. public service_base<reactive_descriptor_service>
  39. {
  40. public:
  41. // The native type of a descriptor.
  42. typedef int native_handle_type;
  43. // The implementation type of the descriptor.
  44. class implementation_type
  45. : private boost::asio::detail::noncopyable
  46. {
  47. public:
  48. // Default constructor.
  49. implementation_type()
  50. : descriptor_(-1),
  51. state_(0)
  52. {
  53. }
  54. private:
  55. // Only this service will have access to the internal values.
  56. friend class reactive_descriptor_service;
  57. // The native descriptor representation.
  58. int descriptor_;
  59. // The current state of the descriptor.
  60. descriptor_ops::state_type state_;
  61. // Per-descriptor data used by the reactor.
  62. reactor::per_descriptor_data reactor_data_;
  63. };
  64. // Constructor.
  65. BOOST_ASIO_DECL reactive_descriptor_service(
  66. boost::asio::io_context& io_context);
  67. // Destroy all user-defined handler objects owned by the service.
  68. BOOST_ASIO_DECL void shutdown();
  69. // Construct a new descriptor implementation.
  70. BOOST_ASIO_DECL void construct(implementation_type& impl);
  71. // Move-construct a new descriptor implementation.
  72. BOOST_ASIO_DECL void move_construct(implementation_type& impl,
  73. implementation_type& other_impl);
  74. // Move-assign from another descriptor implementation.
  75. BOOST_ASIO_DECL void move_assign(implementation_type& impl,
  76. reactive_descriptor_service& other_service,
  77. implementation_type& other_impl);
  78. // Destroy a descriptor implementation.
  79. BOOST_ASIO_DECL void destroy(implementation_type& impl);
  80. // Assign a native descriptor to a descriptor implementation.
  81. BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl,
  82. const native_handle_type& native_descriptor,
  83. boost::system::error_code& ec);
  84. // Determine whether the descriptor is open.
  85. bool is_open(const implementation_type& impl) const
  86. {
  87. return impl.descriptor_ != -1;
  88. }
  89. // Destroy a descriptor implementation.
  90. BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl,
  91. boost::system::error_code& ec);
  92. // Get the native descriptor representation.
  93. native_handle_type native_handle(const implementation_type& impl) const
  94. {
  95. return impl.descriptor_;
  96. }
  97. // Release ownership of the native descriptor representation.
  98. BOOST_ASIO_DECL native_handle_type release(implementation_type& impl);
  99. // Cancel all operations associated with the descriptor.
  100. BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl,
  101. boost::system::error_code& ec);
  102. // Perform an IO control command on the descriptor.
  103. template <typename IO_Control_Command>
  104. boost::system::error_code io_control(implementation_type& impl,
  105. IO_Control_Command& command, boost::system::error_code& ec)
  106. {
  107. descriptor_ops::ioctl(impl.descriptor_, impl.state_,
  108. command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);
  109. return ec;
  110. }
  111. // Gets the non-blocking mode of the descriptor.
  112. bool non_blocking(const implementation_type& impl) const
  113. {
  114. return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0;
  115. }
  116. // Sets the non-blocking mode of the descriptor.
  117. boost::system::error_code non_blocking(implementation_type& impl,
  118. bool mode, boost::system::error_code& ec)
  119. {
  120. descriptor_ops::set_user_non_blocking(
  121. impl.descriptor_, impl.state_, mode, ec);
  122. return ec;
  123. }
  124. // Gets the non-blocking mode of the native descriptor implementation.
  125. bool native_non_blocking(const implementation_type& impl) const
  126. {
  127. return (impl.state_ & descriptor_ops::internal_non_blocking) != 0;
  128. }
  129. // Sets the non-blocking mode of the native descriptor implementation.
  130. boost::system::error_code native_non_blocking(implementation_type& impl,
  131. bool mode, boost::system::error_code& ec)
  132. {
  133. descriptor_ops::set_internal_non_blocking(
  134. impl.descriptor_, impl.state_, mode, ec);
  135. return ec;
  136. }
  137. // Wait for the descriptor to become ready to read, ready to write, or to have
  138. // pending error conditions.
  139. boost::system::error_code wait(implementation_type& impl,
  140. posix::descriptor_base::wait_type w, boost::system::error_code& ec)
  141. {
  142. switch (w)
  143. {
  144. case posix::descriptor_base::wait_read:
  145. descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
  146. break;
  147. case posix::descriptor_base::wait_write:
  148. descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
  149. break;
  150. case posix::descriptor_base::wait_error:
  151. descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec);
  152. break;
  153. default:
  154. ec = boost::asio::error::invalid_argument;
  155. break;
  156. }
  157. return ec;
  158. }
  159. // Asynchronously wait for the descriptor to become ready to read, ready to
  160. // write, or to have pending error conditions.
  161. template <typename Handler>
  162. void async_wait(implementation_type& impl,
  163. posix::descriptor_base::wait_type w, Handler& handler)
  164. {
  165. bool is_continuation =
  166. boost_asio_handler_cont_helpers::is_continuation(handler);
  167. // Allocate and construct an operation to wrap the handler.
  168. typedef reactive_wait_op<Handler> op;
  169. typename op::ptr p = { boost::asio::detail::addressof(handler),
  170. op::ptr::allocate(handler), 0 };
  171. p.p = new (p.v) op(handler);
  172. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  173. &impl, impl.descriptor_, "async_wait"));
  174. int op_type;
  175. switch (w)
  176. {
  177. case posix::descriptor_base::wait_read:
  178. op_type = reactor::read_op;
  179. break;
  180. case posix::descriptor_base::wait_write:
  181. op_type = reactor::write_op;
  182. break;
  183. case posix::descriptor_base::wait_error:
  184. op_type = reactor::except_op;
  185. break;
  186. default:
  187. p.p->ec_ = boost::asio::error::invalid_argument;
  188. reactor_.post_immediate_completion(p.p, is_continuation);
  189. p.v = p.p = 0;
  190. return;
  191. }
  192. start_op(impl, op_type, p.p, is_continuation, false, false);
  193. p.v = p.p = 0;
  194. }
  195. // Write some data to the descriptor.
  196. template <typename ConstBufferSequence>
  197. size_t write_some(implementation_type& impl,
  198. const ConstBufferSequence& buffers, boost::system::error_code& ec)
  199. {
  200. buffer_sequence_adapter<boost::asio::const_buffer,
  201. ConstBufferSequence> bufs(buffers);
  202. return descriptor_ops::sync_write(impl.descriptor_, impl.state_,
  203. bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
  204. }
  205. // Wait until data can be written without blocking.
  206. size_t write_some(implementation_type& impl,
  207. const null_buffers&, boost::system::error_code& ec)
  208. {
  209. // Wait for descriptor to become ready.
  210. descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
  211. return 0;
  212. }
  213. // Start an asynchronous write. The data being sent must be valid for the
  214. // lifetime of the asynchronous operation.
  215. template <typename ConstBufferSequence, typename Handler>
  216. void async_write_some(implementation_type& impl,
  217. const ConstBufferSequence& buffers, Handler& handler)
  218. {
  219. bool is_continuation =
  220. boost_asio_handler_cont_helpers::is_continuation(handler);
  221. // Allocate and construct an operation to wrap the handler.
  222. typedef descriptor_write_op<ConstBufferSequence, Handler> op;
  223. typename op::ptr p = { boost::asio::detail::addressof(handler),
  224. op::ptr::allocate(handler), 0 };
  225. p.p = new (p.v) op(impl.descriptor_, buffers, handler);
  226. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  227. &impl, impl.descriptor_, "async_write_some"));
  228. start_op(impl, reactor::write_op, p.p, is_continuation, true,
  229. buffer_sequence_adapter<boost::asio::const_buffer,
  230. ConstBufferSequence>::all_empty(buffers));
  231. p.v = p.p = 0;
  232. }
  233. // Start an asynchronous wait until data can be written without blocking.
  234. template <typename Handler>
  235. void async_write_some(implementation_type& impl,
  236. const null_buffers&, Handler& handler)
  237. {
  238. bool is_continuation =
  239. boost_asio_handler_cont_helpers::is_continuation(handler);
  240. // Allocate and construct an operation to wrap the handler.
  241. typedef reactive_null_buffers_op<Handler> op;
  242. typename op::ptr p = { boost::asio::detail::addressof(handler),
  243. op::ptr::allocate(handler), 0 };
  244. p.p = new (p.v) op(handler);
  245. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  246. &impl, impl.descriptor_, "async_write_some(null_buffers)"));
  247. start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
  248. p.v = p.p = 0;
  249. }
  250. // Read some data from the stream. Returns the number of bytes read.
  251. template <typename MutableBufferSequence>
  252. size_t read_some(implementation_type& impl,
  253. const MutableBufferSequence& buffers, boost::system::error_code& ec)
  254. {
  255. buffer_sequence_adapter<boost::asio::mutable_buffer,
  256. MutableBufferSequence> bufs(buffers);
  257. return descriptor_ops::sync_read(impl.descriptor_, impl.state_,
  258. bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
  259. }
  260. // Wait until data can be read without blocking.
  261. size_t read_some(implementation_type& impl,
  262. const null_buffers&, boost::system::error_code& ec)
  263. {
  264. // Wait for descriptor to become ready.
  265. descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
  266. return 0;
  267. }
  268. // Start an asynchronous read. The buffer for the data being read must be
  269. // valid for the lifetime of the asynchronous operation.
  270. template <typename MutableBufferSequence, typename Handler>
  271. void async_read_some(implementation_type& impl,
  272. const MutableBufferSequence& buffers, Handler& handler)
  273. {
  274. bool is_continuation =
  275. boost_asio_handler_cont_helpers::is_continuation(handler);
  276. // Allocate and construct an operation to wrap the handler.
  277. typedef descriptor_read_op<MutableBufferSequence, Handler> op;
  278. typename op::ptr p = { boost::asio::detail::addressof(handler),
  279. op::ptr::allocate(handler), 0 };
  280. p.p = new (p.v) op(impl.descriptor_, buffers, handler);
  281. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  282. &impl, impl.descriptor_, "async_read_some"));
  283. start_op(impl, reactor::read_op, p.p, is_continuation, true,
  284. buffer_sequence_adapter<boost::asio::mutable_buffer,
  285. MutableBufferSequence>::all_empty(buffers));
  286. p.v = p.p = 0;
  287. }
  288. // Wait until data can be read without blocking.
  289. template <typename Handler>
  290. void async_read_some(implementation_type& impl,
  291. const null_buffers&, Handler& handler)
  292. {
  293. bool is_continuation =
  294. boost_asio_handler_cont_helpers::is_continuation(handler);
  295. // Allocate and construct an operation to wrap the handler.
  296. typedef reactive_null_buffers_op<Handler> op;
  297. typename op::ptr p = { boost::asio::detail::addressof(handler),
  298. op::ptr::allocate(handler), 0 };
  299. p.p = new (p.v) op(handler);
  300. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  301. &impl, impl.descriptor_, "async_read_some(null_buffers)"));
  302. start_op(impl, reactor::read_op, p.p, is_continuation, false, false);
  303. p.v = p.p = 0;
  304. }
  305. private:
  306. // Start the asynchronous operation.
  307. BOOST_ASIO_DECL void start_op(implementation_type& impl, int op_type,
  308. reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
  309. // The selector that performs event demultiplexing for the service.
  310. reactor& reactor_;
  311. };
  312. } // namespace detail
  313. } // namespace asio
  314. } // namespace boost
  315. #include <boost/asio/detail/pop_options.hpp>
  316. #if defined(BOOST_ASIO_HEADER_ONLY)
  317. # include <boost/asio/detail/impl/reactive_descriptor_service.ipp>
  318. #endif // defined(BOOST_ASIO_HEADER_ONLY)
  319. #endif // !defined(BOOST_ASIO_WINDOWS)
  320. // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
  321. // && !defined(__CYGWIN__)
  322. #endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP