1 | // |
2 | // detail/reactive_socket_service_base.ipp |
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_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP |
12 | #define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP |
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/detail/reactive_socket_service_base.hpp> |
24 | |
25 | #include <boost/asio/detail/push_options.hpp> |
26 | |
27 | namespace boost { |
28 | namespace asio { |
29 | namespace detail { |
30 | |
31 | reactive_socket_service_base::reactive_socket_service_base( |
32 | boost::asio::io_service& io_service) |
33 | : reactor_(use_service<reactor>(ios&: io_service)) |
34 | { |
35 | reactor_.init_task(); |
36 | } |
37 | |
38 | void reactive_socket_service_base::shutdown_service() |
39 | { |
40 | } |
41 | |
42 | void reactive_socket_service_base::construct( |
43 | reactive_socket_service_base::base_implementation_type& impl) |
44 | { |
45 | impl.socket_ = invalid_socket; |
46 | impl.state_ = 0; |
47 | } |
48 | |
49 | void reactive_socket_service_base::base_move_construct( |
50 | reactive_socket_service_base::base_implementation_type& impl, |
51 | reactive_socket_service_base::base_implementation_type& other_impl) |
52 | { |
53 | impl.socket_ = other_impl.socket_; |
54 | other_impl.socket_ = invalid_socket; |
55 | |
56 | impl.state_ = other_impl.state_; |
57 | other_impl.state_ = 0; |
58 | |
59 | reactor_.move_descriptor(impl.socket_, |
60 | target_descriptor_data&: impl.reactor_data_, source_descriptor_data&: other_impl.reactor_data_); |
61 | } |
62 | |
63 | void reactive_socket_service_base::base_move_assign( |
64 | reactive_socket_service_base::base_implementation_type& impl, |
65 | reactive_socket_service_base& other_service, |
66 | reactive_socket_service_base::base_implementation_type& other_impl) |
67 | { |
68 | destroy(impl); |
69 | |
70 | impl.socket_ = other_impl.socket_; |
71 | other_impl.socket_ = invalid_socket; |
72 | |
73 | impl.state_ = other_impl.state_; |
74 | other_impl.state_ = 0; |
75 | |
76 | other_service.reactor_.move_descriptor(impl.socket_, |
77 | target_descriptor_data&: impl.reactor_data_, source_descriptor_data&: other_impl.reactor_data_); |
78 | } |
79 | |
80 | void reactive_socket_service_base::destroy( |
81 | reactive_socket_service_base::base_implementation_type& impl) |
82 | { |
83 | if (impl.socket_ != invalid_socket) |
84 | { |
85 | BOOST_ASIO_HANDLER_OPERATION(("socket" , &impl, "close" )); |
86 | |
87 | reactor_.deregister_descriptor(descriptor: impl.socket_, descriptor_data&: impl.reactor_data_, |
88 | closing: (impl.state_ & socket_ops::possible_dup) == 0); |
89 | |
90 | boost::system::error_code ignored_ec; |
91 | socket_ops::close(s: impl.socket_, state&: impl.state_, destruction: true, ec&: ignored_ec); |
92 | } |
93 | } |
94 | |
95 | boost::system::error_code reactive_socket_service_base::close( |
96 | reactive_socket_service_base::base_implementation_type& impl, |
97 | boost::system::error_code& ec) |
98 | { |
99 | if (is_open(impl)) |
100 | { |
101 | BOOST_ASIO_HANDLER_OPERATION(("socket" , &impl, "close" )); |
102 | |
103 | reactor_.deregister_descriptor(descriptor: impl.socket_, descriptor_data&: impl.reactor_data_, |
104 | closing: (impl.state_ & socket_ops::possible_dup) == 0); |
105 | } |
106 | |
107 | socket_ops::close(s: impl.socket_, state&: impl.state_, destruction: false, ec); |
108 | |
109 | // The descriptor is closed by the OS even if close() returns an error. |
110 | // |
111 | // (Actually, POSIX says the state of the descriptor is unspecified. On |
112 | // Linux the descriptor is apparently closed anyway; e.g. see |
113 | // http://lkml.org/lkml/2005/9/10/129 |
114 | // We'll just have to assume that other OSes follow the same behaviour. The |
115 | // known exception is when Windows's closesocket() function fails with |
116 | // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close(). |
117 | construct(impl); |
118 | |
119 | return ec; |
120 | } |
121 | |
122 | boost::system::error_code reactive_socket_service_base::cancel( |
123 | reactive_socket_service_base::base_implementation_type& impl, |
124 | boost::system::error_code& ec) |
125 | { |
126 | if (!is_open(impl)) |
127 | { |
128 | ec = boost::asio::error::bad_descriptor; |
129 | return ec; |
130 | } |
131 | |
132 | BOOST_ASIO_HANDLER_OPERATION(("socket" , &impl, "cancel" )); |
133 | |
134 | reactor_.cancel_ops(impl.socket_, descriptor_data&: impl.reactor_data_); |
135 | ec = boost::system::error_code(); |
136 | return ec; |
137 | } |
138 | |
139 | boost::system::error_code reactive_socket_service_base::do_open( |
140 | reactive_socket_service_base::base_implementation_type& impl, |
141 | int af, int type, int protocol, boost::system::error_code& ec) |
142 | { |
143 | if (is_open(impl)) |
144 | { |
145 | ec = boost::asio::error::already_open; |
146 | return ec; |
147 | } |
148 | |
149 | socket_holder sock(socket_ops::socket(af, type, protocol, ec)); |
150 | if (sock.get() == invalid_socket) |
151 | return ec; |
152 | |
153 | if (int err = reactor_.register_descriptor(descriptor: sock.get(), descriptor_data&: impl.reactor_data_)) |
154 | { |
155 | ec = boost::system::error_code(err, |
156 | boost::asio::error::get_system_category()); |
157 | return ec; |
158 | } |
159 | |
160 | impl.socket_ = sock.release(); |
161 | switch (type) |
162 | { |
163 | case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; |
164 | case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; |
165 | default: impl.state_ = 0; break; |
166 | } |
167 | ec = boost::system::error_code(); |
168 | return ec; |
169 | } |
170 | |
171 | boost::system::error_code reactive_socket_service_base::do_assign( |
172 | reactive_socket_service_base::base_implementation_type& impl, int type, |
173 | const reactive_socket_service_base::native_handle_type& native_socket, |
174 | boost::system::error_code& ec) |
175 | { |
176 | if (is_open(impl)) |
177 | { |
178 | ec = boost::asio::error::already_open; |
179 | return ec; |
180 | } |
181 | |
182 | if (int err = reactor_.register_descriptor( |
183 | descriptor: native_socket, descriptor_data&: impl.reactor_data_)) |
184 | { |
185 | ec = boost::system::error_code(err, |
186 | boost::asio::error::get_system_category()); |
187 | return ec; |
188 | } |
189 | |
190 | impl.socket_ = native_socket; |
191 | switch (type) |
192 | { |
193 | case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; |
194 | case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; |
195 | default: impl.state_ = 0; break; |
196 | } |
197 | impl.state_ |= socket_ops::possible_dup; |
198 | ec = boost::system::error_code(); |
199 | return ec; |
200 | } |
201 | |
202 | void reactive_socket_service_base::start_op( |
203 | reactive_socket_service_base::base_implementation_type& impl, |
204 | int op_type, reactor_op* op, bool is_continuation, |
205 | bool is_non_blocking, bool noop) |
206 | { |
207 | if (!noop) |
208 | { |
209 | if ((impl.state_ & socket_ops::non_blocking) |
210 | || socket_ops::set_internal_non_blocking( |
211 | s: impl.socket_, state&: impl.state_, value: true, ec&: op->ec_)) |
212 | { |
213 | reactor_.start_op(op_type, descriptor: impl.socket_, |
214 | descriptor_data&: impl.reactor_data_, op, is_continuation, allow_speculative: is_non_blocking); |
215 | return; |
216 | } |
217 | } |
218 | |
219 | reactor_.post_immediate_completion(op, is_continuation); |
220 | } |
221 | |
222 | void reactive_socket_service_base::start_accept_op( |
223 | reactive_socket_service_base::base_implementation_type& impl, |
224 | reactor_op* op, bool is_continuation, bool peer_is_open) |
225 | { |
226 | if (!peer_is_open) |
227 | start_op(impl, op_type: reactor::read_op, op, is_continuation: true, is_non_blocking: is_continuation, noop: false); |
228 | else |
229 | { |
230 | op->ec_ = boost::asio::error::already_open; |
231 | reactor_.post_immediate_completion(op, is_continuation); |
232 | } |
233 | } |
234 | |
235 | void reactive_socket_service_base::start_connect_op( |
236 | reactive_socket_service_base::base_implementation_type& impl, |
237 | reactor_op* op, bool is_continuation, |
238 | const socket_addr_type* addr, size_t addrlen) |
239 | { |
240 | if ((impl.state_ & socket_ops::non_blocking) |
241 | || socket_ops::set_internal_non_blocking( |
242 | s: impl.socket_, state&: impl.state_, value: true, ec&: op->ec_)) |
243 | { |
244 | if (socket_ops::connect(s: impl.socket_, addr, addrlen, ec&: op->ec_) != 0) |
245 | { |
246 | if (op->ec_ == boost::asio::error::in_progress |
247 | || op->ec_ == boost::asio::error::would_block) |
248 | { |
249 | op->ec_ = boost::system::error_code(); |
250 | reactor_.start_op(op_type: reactor::connect_op, descriptor: impl.socket_, |
251 | descriptor_data&: impl.reactor_data_, op, is_continuation, allow_speculative: false); |
252 | return; |
253 | } |
254 | } |
255 | } |
256 | |
257 | reactor_.post_immediate_completion(op, is_continuation); |
258 | } |
259 | |
260 | } // namespace detail |
261 | } // namespace asio |
262 | } // namespace boost |
263 | |
264 | #include <boost/asio/detail/pop_options.hpp> |
265 | |
266 | #endif // !defined(BOOST_ASIO_HAS_IOCP) |
267 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
268 | |
269 | #endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP |
270 | |