Clementine
reactive_socket_service_base.hpp
1 //
2 // detail/reactive_socket_service_base.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_BASE_HPP
12 #define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_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  && !defined(ASIO_WINDOWS_RUNTIME)
22 
23 #include "asio/buffer.hpp"
24 #include "asio/error.hpp"
25 #include "asio/execution_context.hpp"
26 #include "asio/socket_base.hpp"
27 #include "asio/detail/buffer_sequence_adapter.hpp"
28 #include "asio/detail/memory.hpp"
29 #include "asio/detail/reactive_null_buffers_op.hpp"
30 #include "asio/detail/reactive_socket_recv_op.hpp"
31 #include "asio/detail/reactive_socket_recvmsg_op.hpp"
32 #include "asio/detail/reactive_socket_send_op.hpp"
33 #include "asio/detail/reactive_wait_op.hpp"
34 #include "asio/detail/reactor.hpp"
35 #include "asio/detail/reactor_op.hpp"
36 #include "asio/detail/socket_holder.hpp"
37 #include "asio/detail/socket_ops.hpp"
38 #include "asio/detail/socket_types.hpp"
39 
40 #include "asio/detail/push_options.hpp"
41 
42 namespace asio {
43 namespace detail {
44 
46 {
47 public:
48  // The native type of a socket.
49  typedef socket_type native_handle_type;
50 
51  // The implementation type of the socket.
53  {
54  // The native socket representation.
55  socket_type socket_;
56 
57  // The current state of the socket.
58  socket_ops::state_type state_;
59 
60  // Per-descriptor data used by the reactor.
61  reactor::per_descriptor_data reactor_data_;
62  };
63 
64  // Constructor.
66 
67  // Destroy all user-defined handler objects owned by the service.
68  ASIO_DECL void base_shutdown();
69 
70  // Construct a new socket implementation.
71  ASIO_DECL void construct(base_implementation_type& impl);
72 
73  // Move-construct a new socket implementation.
74  ASIO_DECL void base_move_construct(base_implementation_type& impl,
75  base_implementation_type& other_impl) ASIO_NOEXCEPT;
76 
77  // Move-assign from another socket implementation.
78  ASIO_DECL void base_move_assign(base_implementation_type& impl,
79  reactive_socket_service_base& other_service,
80  base_implementation_type& other_impl);
81 
82  // Destroy a socket implementation.
83  ASIO_DECL void destroy(base_implementation_type& impl);
84 
85  // Determine whether the socket is open.
86  bool is_open(const base_implementation_type& impl) const
87  {
88  return impl.socket_ != invalid_socket;
89  }
90 
91  // Destroy a socket implementation.
92  ASIO_DECL asio::error_code close(
94 
95  // Release ownership of the socket.
96  ASIO_DECL socket_type release(
98 
99  // Get the native socket representation.
100  native_handle_type native_handle(base_implementation_type& impl)
101  {
102  return impl.socket_;
103  }
104 
105  // Cancel all operations associated with the socket.
106  ASIO_DECL asio::error_code cancel(
108 
109  // Determine whether the socket is at the out-of-band data mark.
110  bool at_mark(const base_implementation_type& impl,
111  asio::error_code& ec) const
112  {
113  return socket_ops::sockatmark(impl.socket_, ec);
114  }
115 
116  // Determine the number of bytes available for reading.
117  std::size_t available(const base_implementation_type& impl,
118  asio::error_code& ec) const
119  {
120  return socket_ops::available(impl.socket_, ec);
121  }
122 
123  // Place the socket into the state where it will listen for new connections.
125  int backlog, asio::error_code& ec)
126  {
127  socket_ops::listen(impl.socket_, backlog, ec);
128  return ec;
129  }
130 
131  // Perform an IO control command on the socket.
132  template <typename IO_Control_Command>
134  IO_Control_Command& command, asio::error_code& ec)
135  {
136  socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
137  static_cast<ioctl_arg_type*>(command.data()), ec);
138  return ec;
139  }
140 
141  // Gets the non-blocking mode of the socket.
142  bool non_blocking(const base_implementation_type& impl) const
143  {
144  return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
145  }
146 
147  // Sets the non-blocking mode of the socket.
148  asio::error_code non_blocking(base_implementation_type& impl,
149  bool mode, asio::error_code& ec)
150  {
151  socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
152  return ec;
153  }
154 
155  // Gets the non-blocking mode of the native socket implementation.
156  bool native_non_blocking(const base_implementation_type& impl) const
157  {
158  return (impl.state_ & socket_ops::internal_non_blocking) != 0;
159  }
160 
161  // Sets the non-blocking mode of the native socket implementation.
162  asio::error_code native_non_blocking(base_implementation_type& impl,
163  bool mode, asio::error_code& ec)
164  {
165  socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
166  return ec;
167  }
168 
169  // Wait for the socket to become ready to read, ready to write, or to have
170  // pending error conditions.
173  {
174  switch (w)
175  {
177  socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
178  break;
180  socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
181  break;
183  socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);
184  break;
185  default:
186  ec = asio::error::invalid_argument;
187  break;
188  }
189 
190  return ec;
191  }
192 
193  // Asynchronously wait for the socket to become ready to read, ready to
194  // write, or to have pending error conditions.
195  template <typename Handler, typename IoExecutor>
196  void async_wait(base_implementation_type& impl,
197  socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)
198  {
199  bool is_continuation =
200  asio_handler_cont_helpers::is_continuation(handler);
201 
202  // Allocate and construct an operation to wrap the handler.
204  typename op::ptr p = { asio::detail::addressof(handler),
205  op::ptr::allocate(handler), 0 };
206  p.p = new (p.v) op(success_ec_, handler, io_ex);
207 
208  ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
209  &impl, impl.socket_, "async_wait"));
210 
211  int op_type;
212  switch (w)
213  {
215  op_type = reactor::read_op;
216  break;
218  op_type = reactor::write_op;
219  break;
221  op_type = reactor::except_op;
222  break;
223  default:
224  p.p->ec_ = asio::error::invalid_argument;
225  reactor_.post_immediate_completion(p.p, is_continuation);
226  p.v = p.p = 0;
227  return;
228  }
229 
230  start_op(impl, op_type, p.p, is_continuation, false, false);
231  p.v = p.p = 0;
232  }
233 
234  // Send the given data to the peer.
235  template <typename ConstBufferSequence>
236  size_t send(base_implementation_type& impl,
237  const ConstBufferSequence& buffers,
239  {
241  ConstBufferSequence> bufs_type;
242 
243  if (bufs_type::is_single_buffer)
244  {
245  return socket_ops::sync_send1(impl.socket_,
246  impl.state_, bufs_type::first(buffers).data(),
247  bufs_type::first(buffers).size(), flags, ec);
248  }
249  else
250  {
251  bufs_type bufs(buffers);
252  return socket_ops::sync_send(impl.socket_, impl.state_,
253  bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
254  }
255  }
256 
257  // Wait until data can be sent without blocking.
258  size_t send(base_implementation_type& impl, const null_buffers&,
260  {
261  // Wait for socket to become ready.
262  socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
263 
264  return 0;
265  }
266 
267  // Start an asynchronous send. The data being sent must be valid for the
268  // lifetime of the asynchronous operation.
269  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
270  void async_send(base_implementation_type& impl,
271  const ConstBufferSequence& buffers, socket_base::message_flags flags,
272  Handler& handler, const IoExecutor& io_ex)
273  {
274  bool is_continuation =
275  asio_handler_cont_helpers::is_continuation(handler);
276 
277  // Allocate and construct an operation to wrap the handler.
278  typedef reactive_socket_send_op<
279  ConstBufferSequence, Handler, IoExecutor> op;
280  typename op::ptr p = { asio::detail::addressof(handler),
281  op::ptr::allocate(handler), 0 };
282  p.p = new (p.v) op(success_ec_, impl.socket_,
283  impl.state_, buffers, flags, handler, io_ex);
284 
285  ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
286  &impl, impl.socket_, "async_send"));
287 
288  start_op(impl, reactor::write_op, p.p, is_continuation, true,
289  ((impl.state_ & socket_ops::stream_oriented)
291  ConstBufferSequence>::all_empty(buffers)));
292  p.v = p.p = 0;
293  }
294 
295  // Start an asynchronous wait until data can be sent without blocking.
296  template <typename Handler, typename IoExecutor>
297  void async_send(base_implementation_type& impl, const null_buffers&,
298  socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
299  {
300  bool is_continuation =
301  asio_handler_cont_helpers::is_continuation(handler);
302 
303  // Allocate and construct an operation to wrap the handler.
305  typename op::ptr p = { asio::detail::addressof(handler),
306  op::ptr::allocate(handler), 0 };
307  p.p = new (p.v) op(success_ec_, handler, io_ex);
308 
309  ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
310  &impl, impl.socket_, "async_send(null_buffers)"));
311 
312  start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
313  p.v = p.p = 0;
314  }
315 
316  // Receive some data from the peer. Returns the number of bytes received.
317  template <typename MutableBufferSequence>
318  size_t receive(base_implementation_type& impl,
319  const MutableBufferSequence& buffers,
321  {
323  MutableBufferSequence> bufs_type;
324 
325  if (bufs_type::is_single_buffer)
326  {
327  return socket_ops::sync_recv1(impl.socket_,
328  impl.state_, bufs_type::first(buffers).data(),
329  bufs_type::first(buffers).size(), flags, ec);
330  }
331  else
332  {
333  bufs_type bufs(buffers);
334  return socket_ops::sync_recv(impl.socket_, impl.state_,
335  bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
336  }
337  }
338 
339  // Wait until data can be received without blocking.
340  size_t receive(base_implementation_type& impl, const null_buffers&,
342  {
343  // Wait for socket to become ready.
344  socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
345 
346  return 0;
347  }
348 
349  // Start an asynchronous receive. The buffer for the data being received
350  // must be valid for the lifetime of the asynchronous operation.
351  template <typename MutableBufferSequence,
352  typename Handler, typename IoExecutor>
353  void async_receive(base_implementation_type& impl,
354  const MutableBufferSequence& buffers, socket_base::message_flags flags,
355  Handler& handler, const IoExecutor& io_ex)
356  {
357  bool is_continuation =
358  asio_handler_cont_helpers::is_continuation(handler);
359 
360  // Allocate and construct an operation to wrap the handler.
361  typedef reactive_socket_recv_op<
362  MutableBufferSequence, 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(success_ec_, impl.socket_,
366  impl.state_, buffers, flags, handler, io_ex);
367 
368  ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
369  &impl, impl.socket_, "async_receive"));
370 
371  start_op(impl,
372  (flags & socket_base::message_out_of_band)
373  ? reactor::except_op : reactor::read_op,
374  p.p, is_continuation,
375  (flags & socket_base::message_out_of_band) == 0,
376  ((impl.state_ & socket_ops::stream_oriented)
378  MutableBufferSequence>::all_empty(buffers)));
379  p.v = p.p = 0;
380  }
381 
382  // Wait until data can be received without blocking.
383  template <typename Handler, typename IoExecutor>
384  void async_receive(base_implementation_type& impl,
386  Handler& handler, const IoExecutor& io_ex)
387  {
388  bool is_continuation =
389  asio_handler_cont_helpers::is_continuation(handler);
390 
391  // Allocate and construct an operation to wrap the handler.
393  typename op::ptr p = { asio::detail::addressof(handler),
394  op::ptr::allocate(handler), 0 };
395  p.p = new (p.v) op(success_ec_, handler, io_ex);
396 
397  ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
398  &impl, impl.socket_, "async_receive(null_buffers)"));
399 
400  start_op(impl,
401  (flags & socket_base::message_out_of_band)
402  ? reactor::except_op : reactor::read_op,
403  p.p, is_continuation, false, false);
404  p.v = p.p = 0;
405  }
406 
407  // Receive some data with associated flags. Returns the number of bytes
408  // received.
409  template <typename MutableBufferSequence>
410  size_t receive_with_flags(base_implementation_type& impl,
411  const MutableBufferSequence& buffers,
414  {
416  MutableBufferSequence> bufs(buffers);
417 
418  return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
419  bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
420  }
421 
422  // Wait until data can be received without blocking.
423  size_t receive_with_flags(base_implementation_type& impl,
426  {
427  // Wait for socket to become ready.
428  socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
429 
430  // Clear out_flags, since we cannot give it any other sensible value when
431  // performing a null_buffers operation.
432  out_flags = 0;
433 
434  return 0;
435  }
436 
437  // Start an asynchronous receive. The buffer for the data being received
438  // must be valid for the lifetime of the asynchronous operation.
439  template <typename MutableBufferSequence,
440  typename Handler, typename IoExecutor>
441  void async_receive_with_flags(base_implementation_type& impl,
442  const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
443  socket_base::message_flags& out_flags, Handler& handler,
444  const IoExecutor& io_ex)
445  {
446  bool is_continuation =
447  asio_handler_cont_helpers::is_continuation(handler);
448 
449  // Allocate and construct an operation to wrap the handler.
451  MutableBufferSequence, Handler, IoExecutor> op;
452  typename op::ptr p = { asio::detail::addressof(handler),
453  op::ptr::allocate(handler), 0 };
454  p.p = new (p.v) op(success_ec_, impl.socket_,
455  buffers, in_flags, out_flags, handler, io_ex);
456 
457  ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
458  &impl, impl.socket_, "async_receive_with_flags"));
459 
460  start_op(impl,
461  (in_flags & socket_base::message_out_of_band)
462  ? reactor::except_op : reactor::read_op,
463  p.p, is_continuation,
464  (in_flags & socket_base::message_out_of_band) == 0, false);
465  p.v = p.p = 0;
466  }
467 
468  // Wait until data can be received without blocking.
469  template <typename Handler, typename IoExecutor>
470  void async_receive_with_flags(base_implementation_type& impl,
471  const null_buffers&, socket_base::message_flags in_flags,
472  socket_base::message_flags& out_flags, Handler& handler,
473  const IoExecutor& io_ex)
474  {
475  bool is_continuation =
476  asio_handler_cont_helpers::is_continuation(handler);
477 
478  // Allocate and construct an operation to wrap the handler.
480  typename op::ptr p = { asio::detail::addressof(handler),
481  op::ptr::allocate(handler), 0 };
482  p.p = new (p.v) op(success_ec_, handler, io_ex);
483 
484  ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
485  &impl, impl.socket_, "async_receive_with_flags(null_buffers)"));
486 
487  // Clear out_flags, since we cannot give it any other sensible value when
488  // performing a null_buffers operation.
489  out_flags = 0;
490 
491  start_op(impl,
492  (in_flags & socket_base::message_out_of_band)
493  ? reactor::except_op : reactor::read_op,
494  p.p, is_continuation, false, false);
495  p.v = p.p = 0;
496  }
497 
498 protected:
499  // Open a new socket implementation.
500  ASIO_DECL asio::error_code do_open(
501  base_implementation_type& impl, int af,
502  int type, int protocol, asio::error_code& ec);
503 
504  // Assign a native socket to a socket implementation.
505  ASIO_DECL asio::error_code do_assign(
506  base_implementation_type& impl, int type,
507  const native_handle_type& native_socket, asio::error_code& ec);
508 
509  // Start the asynchronous read or write operation.
510  ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
511  reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
512 
513  // Start the asynchronous accept operation.
514  ASIO_DECL void start_accept_op(base_implementation_type& impl,
515  reactor_op* op, bool is_continuation, bool peer_is_open);
516 
517  // Start the asynchronous connect operation.
518  ASIO_DECL void start_connect_op(base_implementation_type& impl,
519  reactor_op* op, bool is_continuation,
520  const socket_addr_type* addr, size_t addrlen);
521 
522  // The selector that performs event demultiplexing for the service.
523  reactor& reactor_;
524 
525  // Cached success value to avoid accessing category singleton.
526  const asio::error_code success_ec_;
527 };
528 
529 } // namespace detail
530 } // namespace asio
531 
532 #include "asio/detail/pop_options.hpp"
533 
534 #if defined(ASIO_HEADER_ONLY)
535 # include "asio/detail/impl/reactive_socket_service_base.ipp"
536 #endif // defined(ASIO_HEADER_ONLY)
537 
538 #endif // !defined(ASIO_HAS_IOCP)
539  // && !defined(ASIO_WINDOWS_RUNTIME)
540 
541 #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
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
wait_type
Wait types.
Definition: socket_base.hpp:82
Definition: reactive_socket_service_base.hpp:52
Definition: reactive_socket_send_op.hpp:99
Definition: reactive_wait_op.hpp:33
A context for function object execution.
Definition: execution_context.hpp:105
Wait for a socket to have error conditions pending.
Definition: socket_base.hpp:91
Definition: chrono.h:284
Definition: reactive_socket_recvmsg_op.hpp:79
Definition: buffer_sequence_adapter.hpp:103
Holds a buffer that can be modified.
Definition: buffer.hpp:92
Class to represent an error code value.
Definition: error_code.hpp:80
Wait for a socket to become ready to write.
Definition: socket_base.hpp:88
Definition: reactive_null_buffers_op.hpp:33
Wait for a socket to become ready to read.
Definition: socket_base.hpp:85
(Deprecated: Use the socket/descriptor wait() and async_wait() member functions.) An implementation o...
Definition: buffer.hpp:354
Definition: reactor_op.hpp:26
Definition: reactive_socket_service_base.hpp:45
Definition: any_io_executor.hpp:28
Definition: reactive_socket_recv_op.hpp:96