]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // detail/reactive_socket_service.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
5 | // Copyright (c) 2003-2016 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 | ||
43 | namespace boost { | |
44 | namespace asio { | |
45 | namespace detail { | |
46 | ||
47 | template <typename Protocol> | |
48 | class reactive_socket_service : | |
49 | public reactive_socket_service_base | |
50 | { | |
51 | public: | |
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 |