Home | History | Annotate | Download | only in detail
      1 //
      2 // detail/reactive_socket_service_base.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 
     11 #ifndef ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
     12 #define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
     13 
     14 
     15 #include "asio/detail/config.hpp"
     16 
     17 
     18 #include "asio/buffer.hpp"
     19 #include "asio/error.hpp"
     20 #include "asio/io_service.hpp"
     21 #include "asio/socket_base.hpp"
     22 #include "asio/detail/addressof.hpp"
     23 #include "asio/detail/buffer_sequence_adapter.hpp"
     24 #include "asio/detail/reactive_null_buffers_op.hpp"
     25 #include "asio/detail/reactive_socket_recv_op.hpp"
     26 #include "asio/detail/reactive_socket_recvmsg_op.hpp"
     27 #include "asio/detail/reactive_socket_send_op.hpp"
     28 #include "asio/detail/reactor.hpp"
     29 #include "asio/detail/reactor_op.hpp"
     30 #include "asio/detail/socket_holder.hpp"
     31 #include "asio/detail/socket_ops.hpp"
     32 #include "asio/detail/socket_types.hpp"
     33 
     34 #include "asio/detail/push_options.hpp"
     35 
     36 namespace asio {
     37 namespace detail {
     38 
     39 class reactive_socket_service_base
     40 {
     41 public:
     42   // The native type of a socket.
     43   typedef socket_type native_handle_type;
     44 
     45   // The implementation type of the socket.
     46   struct base_implementation_type
     47   {
     48     // The native socket representation.
     49     socket_type socket_;
     50 
     51     // The current state of the socket.
     52     socket_ops::state_type state_;
     53 
     54     // Per-descriptor data used by the reactor.
     55     reactor::per_descriptor_data reactor_data_;
     56   };
     57 
     58   // Constructor.
     59   ASIO_DECL reactive_socket_service_base(
     60       asio::io_service& io_service);
     61 
     62   // Destroy all user-defined handler objects owned by the service.
     63   ASIO_DECL void shutdown_service();
     64 
     65   // Construct a new socket implementation.
     66   ASIO_DECL void construct(base_implementation_type& impl);
     67 
     68   // Move-construct a new socket implementation.
     69   ASIO_DECL void base_move_construct(base_implementation_type& impl,
     70       base_implementation_type& other_impl);
     71 
     72   // Move-assign from another socket implementation.
     73   ASIO_DECL void base_move_assign(base_implementation_type& impl,
     74       reactive_socket_service_base& other_service,
     75       base_implementation_type& other_impl);
     76 
     77   // Destroy a socket implementation.
     78   ASIO_DECL void destroy(base_implementation_type& impl);
     79 
     80   // Determine whether the socket is open.
     81   bool is_open(const base_implementation_type& impl) const
     82   {
     83     return impl.socket_ != invalid_socket;
     84   }
     85 
     86   // Destroy a socket implementation.
     87   ASIO_DECL asio::error_code close(
     88       base_implementation_type& impl, asio::error_code& ec);
     89 
     90   // Get the native socket representation.
     91   native_handle_type native_handle(base_implementation_type& impl)
     92   {
     93     return impl.socket_;
     94   }
     95 
     96   // Cancel all operations associated with the socket.
     97   ASIO_DECL asio::error_code cancel(
     98       base_implementation_type& impl, asio::error_code& ec);
     99 
    100   // Determine whether the socket is at the out-of-band data mark.
    101   bool at_mark(const base_implementation_type& impl,
    102       asio::error_code& ec) const
    103   {
    104     return socket_ops::sockatmark(impl.socket_, ec);
    105   }
    106 
    107   // Determine the number of bytes available for reading.
    108   std::size_t available(const base_implementation_type& impl,
    109       asio::error_code& ec) const
    110   {
    111     return socket_ops::available(impl.socket_, ec);
    112   }
    113 
    114   // Place the socket into the state where it will listen for new connections.
    115   asio::error_code listen(base_implementation_type& impl,
    116       int backlog, asio::error_code& ec)
    117   {
    118     socket_ops::listen(impl.socket_, backlog, ec);
    119     return ec;
    120   }
    121 
    122   // Perform an IO control command on the socket.
    123   template <typename IO_Control_Command>
    124   asio::error_code io_control(base_implementation_type& impl,
    125       IO_Control_Command& command, asio::error_code& ec)
    126   {
    127     socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
    128         static_cast<ioctl_arg_type*>(command.data()), ec);
    129     return ec;
    130   }
    131 
    132   // Gets the non-blocking mode of the socket.
    133   bool non_blocking(const base_implementation_type& impl) const
    134   {
    135     return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
    136   }
    137 
    138   // Sets the non-blocking mode of the socket.
    139   asio::error_code non_blocking(base_implementation_type& impl,
    140       bool mode, asio::error_code& ec)
    141   {
    142     socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
    143     return ec;
    144   }
    145 
    146   // Gets the non-blocking mode of the native socket implementation.
    147   bool native_non_blocking(const base_implementation_type& impl) const
    148   {
    149     return (impl.state_ & socket_ops::internal_non_blocking) != 0;
    150   }
    151 
    152   // Sets the non-blocking mode of the native socket implementation.
    153   asio::error_code native_non_blocking(base_implementation_type& impl,
    154       bool mode, asio::error_code& ec)
    155   {
    156     socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
    157     return ec;
    158   }
    159 
    160   // Disable sends or receives on the socket.
    161   asio::error_code shutdown(base_implementation_type& impl,
    162       socket_base::shutdown_type what, asio::error_code& ec)
    163   {
    164     socket_ops::shutdown(impl.socket_, what, ec);
    165     return ec;
    166   }
    167 
    168   // Send the given data to the peer.
    169   template <typename ConstBufferSequence>
    170   size_t send(base_implementation_type& impl,
    171       const ConstBufferSequence& buffers,
    172       socket_base::message_flags flags, asio::error_code& ec)
    173   {
    174     buffer_sequence_adapter<asio::const_buffer,
    175         ConstBufferSequence> bufs(buffers);
    176 
    177     return socket_ops::sync_send(impl.socket_, impl.state_,
    178         bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
    179   }
    180 
    181   // Wait until data can be sent without blocking.
    182   size_t send(base_implementation_type& impl, const null_buffers&,
    183       socket_base::message_flags, asio::error_code& ec)
    184   {
    185     // Wait for socket to become ready.
    186     socket_ops::poll_write(impl.socket_, impl.state_, ec);
    187 
    188     return 0;
    189   }
    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(base_implementation_type& impl,
    195       const ConstBufferSequence& buffers,
    196       socket_base::message_flags flags, Handler& handler)
    197   {
    198     bool is_continuation =
    199       asio_handler_cont_helpers::is_continuation(handler);
    200 
    201     // Allocate and construct an operation to wrap the handler.
    202     typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
    203     typename op::ptr p = { asio::detail::addressof(handler),
    204       asio_handler_alloc_helpers::allocate(
    205         sizeof(op), handler), 0 };
    206     p.p = new (p.v) op(impl.socket_, buffers, flags, handler);
    207 
    208     ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send"));
    209 
    210     start_op(impl, reactor::write_op, p.p, is_continuation, true,
    211         ((impl.state_ & socket_ops::stream_oriented)
    212           && buffer_sequence_adapter<asio::const_buffer,
    213             ConstBufferSequence>::all_empty(buffers)));
    214     p.v = p.p = 0;
    215   }
    216 
    217   // Start an asynchronous wait until data can be sent without blocking.
    218   template <typename Handler>
    219   void async_send(base_implementation_type& impl, const null_buffers&,
    220       socket_base::message_flags, Handler& handler)
    221   {
    222     bool is_continuation =
    223       asio_handler_cont_helpers::is_continuation(handler);
    224 
    225     // Allocate and construct an operation to wrap the handler.
    226     typedef reactive_null_buffers_op<Handler> op;
    227     typename op::ptr p = { asio::detail::addressof(handler),
    228       asio_handler_alloc_helpers::allocate(
    229         sizeof(op), handler), 0 };
    230     p.p = new (p.v) op(handler);
    231 
    232     ASIO_HANDLER_CREATION((p.p, "socket",
    233           &impl, "async_send(null_buffers)"));
    234 
    235     start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
    236     p.v = p.p = 0;
    237   }
    238 
    239   // Receive some data from the peer. Returns the number of bytes received.
    240   template <typename MutableBufferSequence>
    241   size_t receive(base_implementation_type& impl,
    242       const MutableBufferSequence& buffers,
    243       socket_base::message_flags flags, asio::error_code& ec)
    244   {
    245     buffer_sequence_adapter<asio::mutable_buffer,
    246         MutableBufferSequence> bufs(buffers);
    247 
    248     return socket_ops::sync_recv(impl.socket_, impl.state_,
    249         bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
    250   }
    251 
    252   // Wait until data can be received without blocking.
    253   size_t receive(base_implementation_type& impl, const null_buffers&,
    254       socket_base::message_flags, asio::error_code& ec)
    255   {
    256     // Wait for socket to become ready.
    257     socket_ops::poll_read(impl.socket_, impl.state_, ec);
    258 
    259     return 0;
    260   }
    261 
    262   // Start an asynchronous receive. The buffer for the data being received
    263   // must be valid for the lifetime of the asynchronous operation.
    264   template <typename MutableBufferSequence, typename Handler>
    265   void async_receive(base_implementation_type& impl,
    266       const MutableBufferSequence& buffers,
    267       socket_base::message_flags flags, Handler& handler)
    268   {
    269     bool is_continuation =
    270       asio_handler_cont_helpers::is_continuation(handler);
    271 
    272     // Allocate and construct an operation to wrap the handler.
    273     typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op;
    274     typename op::ptr p = { asio::detail::addressof(handler),
    275       asio_handler_alloc_helpers::allocate(
    276         sizeof(op), handler), 0 };
    277     p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
    278 
    279     ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive"));
    280 
    281     start_op(impl,
    282         (flags & socket_base::message_out_of_band)
    283           ? reactor::except_op : reactor::read_op,
    284         p.p, is_continuation,
    285         (flags & socket_base::message_out_of_band) == 0,
    286         ((impl.state_ & socket_ops::stream_oriented)
    287           && buffer_sequence_adapter<asio::mutable_buffer,
    288             MutableBufferSequence>::all_empty(buffers)));
    289     p.v = p.p = 0;
    290   }
    291 
    292   // Wait until data can be received without blocking.
    293   template <typename Handler>
    294   void async_receive(base_implementation_type& impl, const null_buffers&,
    295       socket_base::message_flags flags, Handler& handler)
    296   {
    297     bool is_continuation =
    298       asio_handler_cont_helpers::is_continuation(handler);
    299 
    300     // Allocate and construct an operation to wrap the handler.
    301     typedef reactive_null_buffers_op<Handler> op;
    302     typename op::ptr p = { asio::detail::addressof(handler),
    303       asio_handler_alloc_helpers::allocate(
    304         sizeof(op), handler), 0 };
    305     p.p = new (p.v) op(handler);
    306 
    307     ASIO_HANDLER_CREATION((p.p, "socket",
    308           &impl, "async_receive(null_buffers)"));
    309 
    310     start_op(impl,
    311         (flags & socket_base::message_out_of_band)
    312           ? reactor::except_op : reactor::read_op,
    313         p.p, is_continuation, false, false);
    314     p.v = p.p = 0;
    315   }
    316 
    317   // Receive some data with associated flags. Returns the number of bytes
    318   // received.
    319   template <typename MutableBufferSequence>
    320   size_t receive_with_flags(base_implementation_type& impl,
    321       const MutableBufferSequence& buffers,
    322       socket_base::message_flags in_flags,
    323       socket_base::message_flags& out_flags, asio::error_code& ec)
    324   {
    325     buffer_sequence_adapter<asio::mutable_buffer,
    326         MutableBufferSequence> bufs(buffers);
    327 
    328     return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
    329         bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
    330   }
    331 
    332   // Wait until data can be received without blocking.
    333   size_t receive_with_flags(base_implementation_type& impl,
    334       const null_buffers&, socket_base::message_flags,
    335       socket_base::message_flags& out_flags, asio::error_code& ec)
    336   {
    337     // Wait for socket to become ready.
    338     socket_ops::poll_read(impl.socket_, impl.state_, ec);
    339 
    340     // Clear out_flags, since we cannot give it any other sensible value when
    341     // performing a null_buffers operation.
    342     out_flags = 0;
    343 
    344     return 0;
    345   }
    346 
    347   // Start an asynchronous receive. The buffer for the data being received
    348   // must be valid for the lifetime of the asynchronous operation.
    349   template <typename MutableBufferSequence, typename Handler>
    350   void async_receive_with_flags(base_implementation_type& impl,
    351       const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
    352       socket_base::message_flags& out_flags, Handler& handler)
    353   {
    354     bool is_continuation =
    355       asio_handler_cont_helpers::is_continuation(handler);
    356 
    357     // Allocate and construct an operation to wrap the handler.
    358     typedef reactive_socket_recvmsg_op<MutableBufferSequence, Handler> op;
    359     typename op::ptr p = { asio::detail::addressof(handler),
    360       asio_handler_alloc_helpers::allocate(
    361         sizeof(op), handler), 0 };
    362     p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler);
    363 
    364     ASIO_HANDLER_CREATION((p.p, "socket",
    365           &impl, "async_receive_with_flags"));
    366 
    367     start_op(impl,
    368         (in_flags & socket_base::message_out_of_band)
    369           ? reactor::except_op : reactor::read_op,
    370         p.p, is_continuation,
    371         (in_flags & socket_base::message_out_of_band) == 0, false);
    372     p.v = p.p = 0;
    373   }
    374 
    375   // Wait until data can be received without blocking.
    376   template <typename Handler>
    377   void async_receive_with_flags(base_implementation_type& impl,
    378       const null_buffers&, socket_base::message_flags in_flags,
    379       socket_base::message_flags& out_flags, Handler& handler)
    380   {
    381     bool is_continuation =
    382       asio_handler_cont_helpers::is_continuation(handler);
    383 
    384     // Allocate and construct an operation to wrap the handler.
    385     typedef reactive_null_buffers_op<Handler> op;
    386     typename op::ptr p = { asio::detail::addressof(handler),
    387       asio_handler_alloc_helpers::allocate(
    388         sizeof(op), handler), 0 };
    389     p.p = new (p.v) op(handler);
    390 
    391     ASIO_HANDLER_CREATION((p.p, "socket", &impl,
    392           "async_receive_with_flags(null_buffers)"));
    393 
    394     // Clear out_flags, since we cannot give it any other sensible value when
    395     // performing a null_buffers operation.
    396     out_flags = 0;
    397 
    398     start_op(impl,
    399         (in_flags & socket_base::message_out_of_band)
    400           ? reactor::except_op : reactor::read_op,
    401         p.p, is_continuation, false, false);
    402     p.v = p.p = 0;
    403   }
    404 
    405 protected:
    406   // Open a new socket implementation.
    407   ASIO_DECL asio::error_code do_open(
    408       base_implementation_type& impl, int af,
    409       int type, int protocol, asio::error_code& ec);
    410 
    411   // Assign a native socket to a socket implementation.
    412   ASIO_DECL asio::error_code do_assign(
    413       base_implementation_type& impl, int type,
    414       const native_handle_type& native_socket, asio::error_code& ec);
    415 
    416   // Start the asynchronous read or write operation.
    417   ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
    418       reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
    419 
    420   // Start the asynchronous accept operation.
    421   ASIO_DECL void start_accept_op(base_implementation_type& impl,
    422       reactor_op* op, bool is_continuation, bool peer_is_open);
    423 
    424   // Start the asynchronous connect operation.
    425   ASIO_DECL void start_connect_op(base_implementation_type& impl,
    426       reactor_op* op, bool is_continuation,
    427       const socket_addr_type* addr, size_t addrlen);
    428 
    429   // The selector that performs event demultiplexing for the service.
    430   reactor& reactor_;
    431 };
    432 
    433 } // namespace detail
    434 } // namespace asio
    435 
    436 #include "asio/detail/pop_options.hpp"
    437 
    438 # include "asio/detail/impl/reactive_socket_service_base.ipp"
    439 
    440        //   && !defined(ASIO_WINDOWS_RUNTIME)
    441 
    442 #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
    443