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