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