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