Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

506 lines
17KB

  1. //
  2. // detail/reactive_socket_service.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 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 ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
  11. #define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include "asio/detail/config.hpp"
  16. #if !defined(ASIO_HAS_IOCP)
  17. #include "asio/buffer.hpp"
  18. #include "asio/error.hpp"
  19. #include "asio/execution_context.hpp"
  20. #include "asio/socket_base.hpp"
  21. #include "asio/detail/buffer_sequence_adapter.hpp"
  22. #include "asio/detail/memory.hpp"
  23. #include "asio/detail/noncopyable.hpp"
  24. #include "asio/detail/reactive_null_buffers_op.hpp"
  25. #include "asio/detail/reactive_socket_accept_op.hpp"
  26. #include "asio/detail/reactive_socket_connect_op.hpp"
  27. #include "asio/detail/reactive_socket_recvfrom_op.hpp"
  28. #include "asio/detail/reactive_socket_sendto_op.hpp"
  29. #include "asio/detail/reactive_socket_service_base.hpp"
  30. #include "asio/detail/reactor.hpp"
  31. #include "asio/detail/reactor_op.hpp"
  32. #include "asio/detail/socket_holder.hpp"
  33. #include "asio/detail/socket_ops.hpp"
  34. #include "asio/detail/socket_types.hpp"
  35. #include "asio/detail/push_options.hpp"
  36. namespace asio {
  37. namespace detail {
  38. template <typename Protocol>
  39. class reactive_socket_service :
  40. public execution_context_service_base<reactive_socket_service<Protocol> >,
  41. public reactive_socket_service_base
  42. {
  43. public:
  44. // The protocol type.
  45. typedef Protocol protocol_type;
  46. // The endpoint type.
  47. typedef typename Protocol::endpoint endpoint_type;
  48. // The native type of a socket.
  49. typedef socket_type native_handle_type;
  50. // The implementation type of the socket.
  51. struct implementation_type :
  52. reactive_socket_service_base::base_implementation_type
  53. {
  54. // Default constructor.
  55. implementation_type()
  56. : protocol_(endpoint_type().protocol())
  57. {
  58. }
  59. // The protocol associated with the socket.
  60. protocol_type protocol_;
  61. };
  62. // Constructor.
  63. reactive_socket_service(execution_context& context)
  64. : execution_context_service_base<
  65. reactive_socket_service<Protocol> >(context),
  66. reactive_socket_service_base(context)
  67. {
  68. }
  69. // Destroy all user-defined handler objects owned by the service.
  70. void shutdown()
  71. {
  72. this->base_shutdown();
  73. }
  74. // Move-construct a new socket implementation.
  75. void move_construct(implementation_type& impl,
  76. implementation_type& other_impl)
  77. {
  78. this->base_move_construct(impl, other_impl);
  79. impl.protocol_ = other_impl.protocol_;
  80. other_impl.protocol_ = endpoint_type().protocol();
  81. }
  82. // Move-assign from another socket implementation.
  83. void move_assign(implementation_type& impl,
  84. reactive_socket_service_base& other_service,
  85. implementation_type& other_impl)
  86. {
  87. this->base_move_assign(impl, other_service, other_impl);
  88. impl.protocol_ = other_impl.protocol_;
  89. other_impl.protocol_ = endpoint_type().protocol();
  90. }
  91. // Move-construct a new socket implementation from another protocol type.
  92. template <typename Protocol1>
  93. void converting_move_construct(implementation_type& impl,
  94. reactive_socket_service<Protocol1>&,
  95. typename reactive_socket_service<
  96. Protocol1>::implementation_type& other_impl)
  97. {
  98. this->base_move_construct(impl, other_impl);
  99. impl.protocol_ = protocol_type(other_impl.protocol_);
  100. other_impl.protocol_ = typename Protocol1::endpoint().protocol();
  101. }
  102. // Open a new socket implementation.
  103. asio::error_code open(implementation_type& impl,
  104. const protocol_type& protocol, asio::error_code& ec)
  105. {
  106. if (!do_open(impl, protocol.family(),
  107. protocol.type(), protocol.protocol(), ec))
  108. impl.protocol_ = protocol;
  109. return ec;
  110. }
  111. // Assign a native socket to a socket implementation.
  112. asio::error_code assign(implementation_type& impl,
  113. const protocol_type& protocol, const native_handle_type& native_socket,
  114. asio::error_code& ec)
  115. {
  116. if (!do_assign(impl, protocol.type(), native_socket, ec))
  117. impl.protocol_ = protocol;
  118. return ec;
  119. }
  120. // Get the native socket representation.
  121. native_handle_type native_handle(implementation_type& impl)
  122. {
  123. return impl.socket_;
  124. }
  125. // Bind the socket to the specified local endpoint.
  126. asio::error_code bind(implementation_type& impl,
  127. const endpoint_type& endpoint, asio::error_code& ec)
  128. {
  129. socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
  130. return ec;
  131. }
  132. // Set a socket option.
  133. template <typename Option>
  134. asio::error_code set_option(implementation_type& impl,
  135. const Option& option, asio::error_code& ec)
  136. {
  137. socket_ops::setsockopt(impl.socket_, impl.state_,
  138. option.level(impl.protocol_), option.name(impl.protocol_),
  139. option.data(impl.protocol_), option.size(impl.protocol_), ec);
  140. return ec;
  141. }
  142. // Set a socket option.
  143. template <typename Option>
  144. asio::error_code get_option(const implementation_type& impl,
  145. Option& option, asio::error_code& ec) const
  146. {
  147. std::size_t size = option.size(impl.protocol_);
  148. socket_ops::getsockopt(impl.socket_, impl.state_,
  149. option.level(impl.protocol_), option.name(impl.protocol_),
  150. option.data(impl.protocol_), &size, ec);
  151. if (!ec)
  152. option.resize(impl.protocol_, size);
  153. return ec;
  154. }
  155. // Get the local endpoint.
  156. endpoint_type local_endpoint(const implementation_type& impl,
  157. asio::error_code& ec) const
  158. {
  159. endpoint_type endpoint;
  160. std::size_t addr_len = endpoint.capacity();
  161. if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
  162. return endpoint_type();
  163. endpoint.resize(addr_len);
  164. return endpoint;
  165. }
  166. // Get the remote endpoint.
  167. endpoint_type remote_endpoint(const implementation_type& impl,
  168. asio::error_code& ec) const
  169. {
  170. endpoint_type endpoint;
  171. std::size_t addr_len = endpoint.capacity();
  172. if (socket_ops::getpeername(impl.socket_,
  173. endpoint.data(), &addr_len, false, ec))
  174. return endpoint_type();
  175. endpoint.resize(addr_len);
  176. return endpoint;
  177. }
  178. // Disable sends or receives on the socket.
  179. asio::error_code shutdown(base_implementation_type& impl,
  180. socket_base::shutdown_type what, asio::error_code& ec)
  181. {
  182. socket_ops::shutdown(impl.socket_, what, ec);
  183. return ec;
  184. }
  185. // Send a datagram to the specified endpoint. Returns the number of bytes
  186. // sent.
  187. template <typename ConstBufferSequence>
  188. size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
  189. const endpoint_type& destination, socket_base::message_flags flags,
  190. asio::error_code& ec)
  191. {
  192. buffer_sequence_adapter<asio::const_buffer,
  193. ConstBufferSequence> bufs(buffers);
  194. return socket_ops::sync_sendto(impl.socket_, impl.state_,
  195. bufs.buffers(), bufs.count(), flags,
  196. destination.data(), destination.size(), ec);
  197. }
  198. // Wait until data can be sent without blocking.
  199. size_t send_to(implementation_type& impl, const null_buffers&,
  200. const endpoint_type&, socket_base::message_flags,
  201. asio::error_code& ec)
  202. {
  203. // Wait for socket to become ready.
  204. socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
  205. return 0;
  206. }
  207. // Start an asynchronous send. The data being sent must be valid for the
  208. // lifetime of the asynchronous operation.
  209. template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
  210. void async_send_to(implementation_type& impl,
  211. const ConstBufferSequence& buffers,
  212. const endpoint_type& destination, socket_base::message_flags flags,
  213. Handler& handler, const IoExecutor& io_ex)
  214. {
  215. bool is_continuation =
  216. asio_handler_cont_helpers::is_continuation(handler);
  217. // Allocate and construct an operation to wrap the handler.
  218. typedef reactive_socket_sendto_op<ConstBufferSequence,
  219. endpoint_type, Handler, IoExecutor> op;
  220. typename op::ptr p = { asio::detail::addressof(handler),
  221. op::ptr::allocate(handler), 0 };
  222. p.p = new (p.v) op(impl.socket_, buffers,
  223. destination, flags, handler, io_ex);
  224. ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
  225. &impl, impl.socket_, "async_send_to"));
  226. start_op(impl, reactor::write_op, p.p, is_continuation, true, false);
  227. p.v = p.p = 0;
  228. }
  229. // Start an asynchronous wait until data can be sent without blocking.
  230. template <typename Handler, typename IoExecutor>
  231. void async_send_to(implementation_type& impl, const null_buffers&,
  232. const endpoint_type&, socket_base::message_flags,
  233. Handler& handler, const IoExecutor& io_ex)
  234. {
  235. bool is_continuation =
  236. asio_handler_cont_helpers::is_continuation(handler);
  237. // Allocate and construct an operation to wrap the handler.
  238. typedef reactive_null_buffers_op<Handler, IoExecutor> op;
  239. typename op::ptr p = { asio::detail::addressof(handler),
  240. op::ptr::allocate(handler), 0 };
  241. p.p = new (p.v) op(handler, io_ex);
  242. ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
  243. &impl, impl.socket_, "async_send_to(null_buffers)"));
  244. start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
  245. p.v = p.p = 0;
  246. }
  247. // Receive a datagram with the endpoint of the sender. Returns the number of
  248. // bytes received.
  249. template <typename MutableBufferSequence>
  250. size_t receive_from(implementation_type& impl,
  251. const MutableBufferSequence& buffers,
  252. endpoint_type& sender_endpoint, socket_base::message_flags flags,
  253. asio::error_code& ec)
  254. {
  255. buffer_sequence_adapter<asio::mutable_buffer,
  256. MutableBufferSequence> bufs(buffers);
  257. std::size_t addr_len = sender_endpoint.capacity();
  258. std::size_t bytes_recvd = socket_ops::sync_recvfrom(
  259. impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
  260. flags, sender_endpoint.data(), &addr_len, ec);
  261. if (!ec)
  262. sender_endpoint.resize(addr_len);
  263. return bytes_recvd;
  264. }
  265. // Wait until data can be received without blocking.
  266. size_t receive_from(implementation_type& impl, const null_buffers&,
  267. endpoint_type& sender_endpoint, socket_base::message_flags,
  268. asio::error_code& ec)
  269. {
  270. // Wait for socket to become ready.
  271. socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
  272. // Reset endpoint since it can be given no sensible value at this time.
  273. sender_endpoint = endpoint_type();
  274. return 0;
  275. }
  276. // Start an asynchronous receive. The buffer for the data being received and
  277. // the sender_endpoint object must both be valid for the lifetime of the
  278. // asynchronous operation.
  279. template <typename MutableBufferSequence,
  280. typename Handler, typename IoExecutor>
  281. void async_receive_from(implementation_type& impl,
  282. const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
  283. socket_base::message_flags flags, Handler& handler,
  284. const IoExecutor& io_ex)
  285. {
  286. bool is_continuation =
  287. asio_handler_cont_helpers::is_continuation(handler);
  288. // Allocate and construct an operation to wrap the handler.
  289. typedef reactive_socket_recvfrom_op<MutableBufferSequence,
  290. endpoint_type, Handler, IoExecutor> op;
  291. typename op::ptr p = { asio::detail::addressof(handler),
  292. op::ptr::allocate(handler), 0 };
  293. int protocol = impl.protocol_.type();
  294. p.p = new (p.v) op(impl.socket_, protocol, buffers,
  295. sender_endpoint, flags, handler, io_ex);
  296. ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
  297. &impl, impl.socket_, "async_receive_from"));
  298. start_op(impl,
  299. (flags & socket_base::message_out_of_band)
  300. ? reactor::except_op : reactor::read_op,
  301. p.p, is_continuation, true, false);
  302. p.v = p.p = 0;
  303. }
  304. // Wait until data can be received without blocking.
  305. template <typename Handler, typename IoExecutor>
  306. void async_receive_from(implementation_type& impl, const null_buffers&,
  307. endpoint_type& sender_endpoint, socket_base::message_flags flags,
  308. Handler& handler, const IoExecutor& io_ex)
  309. {
  310. bool is_continuation =
  311. asio_handler_cont_helpers::is_continuation(handler);
  312. // Allocate and construct an operation to wrap the handler.
  313. typedef reactive_null_buffers_op<Handler, IoExecutor> op;
  314. typename op::ptr p = { asio::detail::addressof(handler),
  315. op::ptr::allocate(handler), 0 };
  316. p.p = new (p.v) op(handler, io_ex);
  317. ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
  318. &impl, impl.socket_, "async_receive_from(null_buffers)"));
  319. // Reset endpoint since it can be given no sensible value at this time.
  320. sender_endpoint = endpoint_type();
  321. start_op(impl,
  322. (flags & socket_base::message_out_of_band)
  323. ? reactor::except_op : reactor::read_op,
  324. p.p, is_continuation, false, false);
  325. p.v = p.p = 0;
  326. }
  327. // Accept a new connection.
  328. template <typename Socket>
  329. asio::error_code accept(implementation_type& impl,
  330. Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec)
  331. {
  332. // We cannot accept a socket that is already open.
  333. if (peer.is_open())
  334. {
  335. ec = asio::error::already_open;
  336. return ec;
  337. }
  338. std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
  339. socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
  340. impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
  341. peer_endpoint ? &addr_len : 0, ec));
  342. // On success, assign new connection to peer socket object.
  343. if (new_socket.get() != invalid_socket)
  344. {
  345. if (peer_endpoint)
  346. peer_endpoint->resize(addr_len);
  347. peer.assign(impl.protocol_, new_socket.get(), ec);
  348. if (!ec)
  349. new_socket.release();
  350. }
  351. return ec;
  352. }
  353. // Start an asynchronous accept. The peer and peer_endpoint objects must be
  354. // valid until the accept's handler is invoked.
  355. template <typename Socket, typename Handler, typename IoExecutor>
  356. void async_accept(implementation_type& impl, Socket& peer,
  357. endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)
  358. {
  359. bool is_continuation =
  360. asio_handler_cont_helpers::is_continuation(handler);
  361. // Allocate and construct an operation to wrap the handler.
  362. typedef reactive_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op;
  363. typename op::ptr p = { asio::detail::addressof(handler),
  364. op::ptr::allocate(handler), 0 };
  365. p.p = new (p.v) op(impl.socket_, impl.state_, peer,
  366. impl.protocol_, peer_endpoint, handler, io_ex);
  367. ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
  368. &impl, impl.socket_, "async_accept"));
  369. start_accept_op(impl, p.p, is_continuation, peer.is_open());
  370. p.v = p.p = 0;
  371. }
  372. #if defined(ASIO_HAS_MOVE)
  373. // Start an asynchronous accept. The peer_endpoint object must be valid until
  374. // the accept's handler is invoked.
  375. template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
  376. void async_move_accept(implementation_type& impl,
  377. const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
  378. Handler& handler, const IoExecutor& io_ex)
  379. {
  380. bool is_continuation =
  381. asio_handler_cont_helpers::is_continuation(handler);
  382. // Allocate and construct an operation to wrap the handler.
  383. typedef reactive_socket_move_accept_op<Protocol,
  384. PeerIoExecutor, Handler, IoExecutor> op;
  385. typename op::ptr p = { asio::detail::addressof(handler),
  386. op::ptr::allocate(handler), 0 };
  387. p.p = new (p.v) op(peer_io_ex, impl.socket_, impl.state_,
  388. impl.protocol_, peer_endpoint, handler, io_ex);
  389. ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
  390. &impl, impl.socket_, "async_accept"));
  391. start_accept_op(impl, p.p, is_continuation, false);
  392. p.v = p.p = 0;
  393. }
  394. #endif // defined(ASIO_HAS_MOVE)
  395. // Connect the socket to the specified endpoint.
  396. asio::error_code connect(implementation_type& impl,
  397. const endpoint_type& peer_endpoint, asio::error_code& ec)
  398. {
  399. socket_ops::sync_connect(impl.socket_,
  400. peer_endpoint.data(), peer_endpoint.size(), ec);
  401. return ec;
  402. }
  403. // Start an asynchronous connect.
  404. template <typename Handler, typename IoExecutor>
  405. void async_connect(implementation_type& impl,
  406. const endpoint_type& peer_endpoint,
  407. Handler& handler, const IoExecutor& io_ex)
  408. {
  409. bool is_continuation =
  410. asio_handler_cont_helpers::is_continuation(handler);
  411. // Allocate and construct an operation to wrap the handler.
  412. typedef reactive_socket_connect_op<Handler, IoExecutor> op;
  413. typename op::ptr p = { asio::detail::addressof(handler),
  414. op::ptr::allocate(handler), 0 };
  415. p.p = new (p.v) op(impl.socket_, handler, io_ex);
  416. ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
  417. &impl, impl.socket_, "async_connect"));
  418. start_connect_op(impl, p.p, is_continuation,
  419. peer_endpoint.data(), peer_endpoint.size());
  420. p.v = p.p = 0;
  421. }
  422. };
  423. } // namespace detail
  424. } // namespace asio
  425. #include "asio/detail/pop_options.hpp"
  426. #endif // !defined(ASIO_HAS_IOCP)
  427. #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP