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.

508 lines
17KB

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