]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // detail/win_iocp_socket_accept_op.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
f67539c2 | 5 | // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
7c673cae FG |
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_WIN_IOCP_SOCKET_ACCEPT_OP_HPP | |
12 | #define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_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 | ||
7c673cae | 22 | #include <boost/asio/detail/bind_handler.hpp> |
7c673cae FG |
23 | #include <boost/asio/detail/fenced_block.hpp> |
24 | #include <boost/asio/detail/handler_alloc_helpers.hpp> | |
25 | #include <boost/asio/detail/handler_invoke_helpers.hpp> | |
20effc67 | 26 | #include <boost/asio/detail/handler_work.hpp> |
b32b8144 | 27 | #include <boost/asio/detail/memory.hpp> |
7c673cae FG |
28 | #include <boost/asio/detail/operation.hpp> |
29 | #include <boost/asio/detail/socket_ops.hpp> | |
30 | #include <boost/asio/detail/win_iocp_socket_service_base.hpp> | |
31 | #include <boost/asio/error.hpp> | |
32 | ||
33 | #include <boost/asio/detail/push_options.hpp> | |
34 | ||
35 | namespace boost { | |
36 | namespace asio { | |
37 | namespace detail { | |
38 | ||
92f5a8d4 TL |
39 | template <typename Socket, typename Protocol, |
40 | typename Handler, typename IoExecutor> | |
7c673cae FG |
41 | class win_iocp_socket_accept_op : public operation |
42 | { | |
43 | public: | |
44 | BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op); | |
45 | ||
46 | win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service, | |
47 | socket_type socket, Socket& peer, const Protocol& protocol, | |
48 | typename Protocol::endpoint* peer_endpoint, | |
92f5a8d4 | 49 | bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex) |
7c673cae FG |
50 | : operation(&win_iocp_socket_accept_op::do_complete), |
51 | socket_service_(socket_service), | |
52 | socket_(socket), | |
53 | peer_(peer), | |
54 | protocol_(protocol), | |
55 | peer_endpoint_(peer_endpoint), | |
56 | enable_connection_aborted_(enable_connection_aborted), | |
92f5a8d4 | 57 | handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), |
20effc67 | 58 | work_(handler_, io_ex) |
7c673cae FG |
59 | { |
60 | } | |
61 | ||
62 | socket_holder& new_socket() | |
63 | { | |
64 | return new_socket_; | |
65 | } | |
66 | ||
67 | void* output_buffer() | |
68 | { | |
69 | return output_buffer_; | |
70 | } | |
71 | ||
72 | DWORD address_length() | |
73 | { | |
74 | return sizeof(sockaddr_storage_type) + 16; | |
75 | } | |
76 | ||
b32b8144 | 77 | static void do_complete(void* owner, operation* base, |
7c673cae FG |
78 | const boost::system::error_code& result_ec, |
79 | std::size_t /*bytes_transferred*/) | |
80 | { | |
81 | boost::system::error_code ec(result_ec); | |
82 | ||
83 | // Take ownership of the operation object. | |
84 | win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base)); | |
85 | ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; | |
86 | ||
87 | if (owner) | |
88 | { | |
89 | typename Protocol::endpoint peer_endpoint; | |
90 | std::size_t addr_len = peer_endpoint.capacity(); | |
91 | socket_ops::complete_iocp_accept(o->socket_, | |
92 | o->output_buffer(), o->address_length(), | |
93 | peer_endpoint.data(), &addr_len, | |
94 | o->new_socket_.get(), ec); | |
95 | ||
96 | // Restart the accept operation if we got the connection_aborted error | |
97 | // and the enable_connection_aborted socket option is not set. | |
98 | if (ec == boost::asio::error::connection_aborted | |
99 | && !o->enable_connection_aborted_) | |
100 | { | |
101 | o->reset(); | |
102 | o->socket_service_.restart_accept_op(o->socket_, | |
103 | o->new_socket_, o->protocol_.family(), | |
104 | o->protocol_.type(), o->protocol_.protocol(), | |
105 | o->output_buffer(), o->address_length(), o); | |
106 | p.v = p.p = 0; | |
107 | return; | |
108 | } | |
109 | ||
110 | // If the socket was successfully accepted, transfer ownership of the | |
111 | // socket to the peer object. | |
112 | if (!ec) | |
113 | { | |
114 | o->peer_.assign(o->protocol_, | |
115 | typename Socket::native_handle_type( | |
116 | o->new_socket_.get(), peer_endpoint), ec); | |
117 | if (!ec) | |
118 | o->new_socket_.release(); | |
119 | } | |
120 | ||
121 | // Pass endpoint back to caller. | |
122 | if (o->peer_endpoint_) | |
123 | *o->peer_endpoint_ = peer_endpoint; | |
124 | } | |
125 | ||
b32b8144 | 126 | BOOST_ASIO_HANDLER_COMPLETION((*o)); |
7c673cae | 127 | |
20effc67 TL |
128 | // Take ownership of the operation's outstanding work. |
129 | handler_work<Handler, IoExecutor> w( | |
130 | BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( | |
131 | o->work_)); | |
132 | ||
7c673cae FG |
133 | // Make a copy of the handler so that the memory can be deallocated before |
134 | // the upcall is made. Even if we're not about to make an upcall, a | |
135 | // sub-object of the handler may be the true owner of the memory associated | |
136 | // with the handler. Consequently, a local copy of the handler is required | |
137 | // to ensure that any owning sub-object remains valid until after we have | |
138 | // deallocated the memory here. | |
139 | detail::binder1<Handler, boost::system::error_code> | |
140 | handler(o->handler_, ec); | |
141 | p.h = boost::asio::detail::addressof(handler.handler_); | |
142 | p.reset(); | |
143 | ||
144 | // Make the upcall if required. | |
145 | if (owner) | |
146 | { | |
147 | fenced_block b(fenced_block::half); | |
148 | BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); | |
b32b8144 | 149 | w.complete(handler, handler.handler_); |
7c673cae FG |
150 | BOOST_ASIO_HANDLER_INVOCATION_END; |
151 | } | |
152 | } | |
153 | ||
154 | private: | |
155 | win_iocp_socket_service_base& socket_service_; | |
156 | socket_type socket_; | |
157 | socket_holder new_socket_; | |
158 | Socket& peer_; | |
159 | Protocol protocol_; | |
160 | typename Protocol::endpoint* peer_endpoint_; | |
161 | unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; | |
162 | bool enable_connection_aborted_; | |
163 | Handler handler_; | |
20effc67 | 164 | handler_work<Handler, IoExecutor> work_; |
7c673cae FG |
165 | }; |
166 | ||
b32b8144 FG |
167 | #if defined(BOOST_ASIO_HAS_MOVE) |
168 | ||
92f5a8d4 TL |
169 | template <typename Protocol, typename PeerIoExecutor, |
170 | typename Handler, typename IoExecutor> | |
b32b8144 FG |
171 | class win_iocp_socket_move_accept_op : public operation |
172 | { | |
173 | public: | |
174 | BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op); | |
175 | ||
176 | win_iocp_socket_move_accept_op( | |
177 | win_iocp_socket_service_base& socket_service, socket_type socket, | |
92f5a8d4 | 178 | const Protocol& protocol, const PeerIoExecutor& peer_io_ex, |
b32b8144 | 179 | typename Protocol::endpoint* peer_endpoint, |
92f5a8d4 | 180 | bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex) |
b32b8144 FG |
181 | : operation(&win_iocp_socket_move_accept_op::do_complete), |
182 | socket_service_(socket_service), | |
183 | socket_(socket), | |
92f5a8d4 | 184 | peer_(peer_io_ex), |
b32b8144 FG |
185 | protocol_(protocol), |
186 | peer_endpoint_(peer_endpoint), | |
187 | enable_connection_aborted_(enable_connection_aborted), | |
92f5a8d4 | 188 | handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), |
20effc67 | 189 | work_(handler_, io_ex) |
b32b8144 | 190 | { |
b32b8144 FG |
191 | } |
192 | ||
193 | socket_holder& new_socket() | |
194 | { | |
195 | return new_socket_; | |
196 | } | |
197 | ||
198 | void* output_buffer() | |
199 | { | |
200 | return output_buffer_; | |
201 | } | |
202 | ||
203 | DWORD address_length() | |
204 | { | |
205 | return sizeof(sockaddr_storage_type) + 16; | |
206 | } | |
207 | ||
208 | static void do_complete(void* owner, operation* base, | |
209 | const boost::system::error_code& result_ec, | |
210 | std::size_t /*bytes_transferred*/) | |
211 | { | |
212 | boost::system::error_code ec(result_ec); | |
213 | ||
214 | // Take ownership of the operation object. | |
215 | win_iocp_socket_move_accept_op* o( | |
216 | static_cast<win_iocp_socket_move_accept_op*>(base)); | |
217 | ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; | |
b32b8144 FG |
218 | |
219 | if (owner) | |
220 | { | |
221 | typename Protocol::endpoint peer_endpoint; | |
222 | std::size_t addr_len = peer_endpoint.capacity(); | |
223 | socket_ops::complete_iocp_accept(o->socket_, | |
224 | o->output_buffer(), o->address_length(), | |
225 | peer_endpoint.data(), &addr_len, | |
226 | o->new_socket_.get(), ec); | |
227 | ||
228 | // Restart the accept operation if we got the connection_aborted error | |
229 | // and the enable_connection_aborted socket option is not set. | |
230 | if (ec == boost::asio::error::connection_aborted | |
231 | && !o->enable_connection_aborted_) | |
232 | { | |
233 | o->reset(); | |
234 | o->socket_service_.restart_accept_op(o->socket_, | |
235 | o->new_socket_, o->protocol_.family(), | |
236 | o->protocol_.type(), o->protocol_.protocol(), | |
237 | o->output_buffer(), o->address_length(), o); | |
238 | p.v = p.p = 0; | |
239 | return; | |
240 | } | |
241 | ||
242 | // If the socket was successfully accepted, transfer ownership of the | |
243 | // socket to the peer object. | |
244 | if (!ec) | |
245 | { | |
246 | o->peer_.assign(o->protocol_, | |
247 | typename Protocol::socket::native_handle_type( | |
248 | o->new_socket_.get(), peer_endpoint), ec); | |
249 | if (!ec) | |
250 | o->new_socket_.release(); | |
251 | } | |
252 | ||
253 | // Pass endpoint back to caller. | |
254 | if (o->peer_endpoint_) | |
255 | *o->peer_endpoint_ = peer_endpoint; | |
256 | } | |
257 | ||
258 | BOOST_ASIO_HANDLER_COMPLETION((*o)); | |
259 | ||
20effc67 TL |
260 | // Take ownership of the operation's outstanding work. |
261 | handler_work<Handler, IoExecutor> w( | |
262 | BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( | |
263 | o->work_)); | |
264 | ||
b32b8144 FG |
265 | // Make a copy of the handler so that the memory can be deallocated before |
266 | // the upcall is made. Even if we're not about to make an upcall, a | |
267 | // sub-object of the handler may be the true owner of the memory associated | |
268 | // with the handler. Consequently, a local copy of the handler is required | |
269 | // to ensure that any owning sub-object remains valid until after we have | |
270 | // deallocated the memory here. | |
271 | detail::move_binder2<Handler, | |
92f5a8d4 | 272 | boost::system::error_code, peer_socket_type> |
b32b8144 | 273 | handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), ec, |
92f5a8d4 | 274 | BOOST_ASIO_MOVE_CAST(peer_socket_type)(o->peer_)); |
b32b8144 FG |
275 | p.h = boost::asio::detail::addressof(handler.handler_); |
276 | p.reset(); | |
277 | ||
278 | // Make the upcall if required. | |
279 | if (owner) | |
280 | { | |
281 | fenced_block b(fenced_block::half); | |
282 | BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); | |
283 | w.complete(handler, handler.handler_); | |
284 | BOOST_ASIO_HANDLER_INVOCATION_END; | |
285 | } | |
286 | } | |
287 | ||
288 | private: | |
92f5a8d4 TL |
289 | typedef typename Protocol::socket::template |
290 | rebind_executor<PeerIoExecutor>::other peer_socket_type; | |
291 | ||
b32b8144 FG |
292 | win_iocp_socket_service_base& socket_service_; |
293 | socket_type socket_; | |
294 | socket_holder new_socket_; | |
92f5a8d4 | 295 | peer_socket_type peer_; |
b32b8144 FG |
296 | Protocol protocol_; |
297 | typename Protocol::endpoint* peer_endpoint_; | |
298 | unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; | |
299 | bool enable_connection_aborted_; | |
300 | Handler handler_; | |
20effc67 | 301 | handler_work<Handler, IoExecutor> work_; |
b32b8144 FG |
302 | }; |
303 | ||
304 | #endif // defined(BOOST_ASIO_HAS_MOVE) | |
305 | ||
7c673cae FG |
306 | } // namespace detail |
307 | } // namespace asio | |
308 | } // namespace boost | |
309 | ||
310 | #include <boost/asio/detail/pop_options.hpp> | |
311 | ||
312 | #endif // defined(BOOST_ASIO_HAS_IOCP) | |
313 | ||
314 | #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP |