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