]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // detail/reactive_socket_service_base.ipp | |
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_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>(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 | impl.reactor_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 | impl.reactor_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(impl.socket_, impl.reactor_data_, | |
88 | (impl.state_ & socket_ops::possible_dup) == 0); | |
89 | ||
90 | boost::system::error_code ignored_ec; | |
91 | socket_ops::close(impl.socket_, impl.state_, true, 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(impl.socket_, impl.reactor_data_, | |
104 | (impl.state_ & socket_ops::possible_dup) == 0); | |
105 | } | |
106 | ||
107 | socket_ops::close(impl.socket_, impl.state_, 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_, 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(sock.get(), 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 | native_socket, 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 | impl.socket_, impl.state_, true, op->ec_)) | |
212 | { | |
213 | reactor_.start_op(op_type, impl.socket_, | |
214 | impl.reactor_data_, op, is_continuation, 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, reactor::read_op, op, true, is_continuation, 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 | impl.socket_, impl.state_, true, op->ec_)) | |
243 | { | |
244 | if (socket_ops::connect(impl.socket_, addr, addrlen, 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(reactor::connect_op, impl.socket_, | |
251 | impl.reactor_data_, op, is_continuation, 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 |