• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
implementation_typeasio::detail::reactive_socket_service::implementation_type61     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.
reactive_socket_service(asio::io_service & io_service)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.
move_construct(implementation_type & impl,implementation_type & other_impl)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.
move_assign(implementation_type & impl,reactive_socket_service_base & other_service,implementation_type & other_impl)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>
converting_move_construct(implementation_type & impl,typename reactive_socket_service<Protocol1>::implementation_type & other_impl)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.
open(implementation_type & impl,const protocol_type & protocol,asio::error_code & ec)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.
assign(implementation_type & impl,const protocol_type & protocol,const native_handle_type & native_socket,asio::error_code & ec)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.
native_handle(implementation_type & impl)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.
bind(implementation_type & impl,const endpoint_type & endpoint,asio::error_code & ec)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>
set_option(implementation_type & impl,const Option & option,asio::error_code & ec)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>
get_option(const implementation_type & impl,Option & option,asio::error_code & ec) const156   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.
local_endpoint(const implementation_type & impl,asio::error_code & ec) const169   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.
remote_endpoint(const implementation_type & impl,asio::error_code & ec) const181   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>
send_to(implementation_type & impl,const ConstBufferSequence & buffers,const endpoint_type & destination,socket_base::message_flags flags,asio::error_code & ec)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.
send_to(implementation_type & impl,const null_buffers &,const endpoint_type &,socket_base::message_flags,asio::error_code & ec)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>
async_send_to(implementation_type & impl,const ConstBufferSequence & buffers,const endpoint_type & destination,socket_base::message_flags flags,Handler & 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>
async_send_to(implementation_type & impl,const null_buffers &,const endpoint_type &,socket_base::message_flags,Handler & 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>
receive_from(implementation_type & impl,const MutableBufferSequence & buffers,endpoint_type & sender_endpoint,socket_base::message_flags flags,asio::error_code & ec)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.
receive_from(implementation_type & impl,const null_buffers &,endpoint_type & sender_endpoint,socket_base::message_flags,asio::error_code & ec)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>
async_receive_from(implementation_type & impl,const MutableBufferSequence & buffers,endpoint_type & sender_endpoint,socket_base::message_flags flags,Handler & 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>
async_receive_from(implementation_type & impl,const null_buffers &,endpoint_type & sender_endpoint,socket_base::message_flags flags,Handler & 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>
accept(implementation_type & impl,Socket & peer,endpoint_type * peer_endpoint,asio::error_code & ec)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>
async_accept(implementation_type & impl,Socket & peer,endpoint_type * peer_endpoint,Handler & 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.
connect(implementation_type & impl,const endpoint_type & peer_endpoint,asio::error_code & ec)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>
async_connect(implementation_type & impl,const endpoint_type & peer_endpoint,Handler & 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