2 // detail/win_iocp_socket_accept_op.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
12 #define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/config.hpp>
20 #if defined(BOOST_ASIO_HAS_IOCP)
22 #include <boost/asio/detail/bind_handler.hpp>
23 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
24 #include <boost/asio/detail/fenced_block.hpp>
25 #include <boost/asio/detail/handler_alloc_helpers.hpp>
26 #include <boost/asio/detail/handler_invoke_helpers.hpp>
27 #include <boost/asio/detail/memory.hpp>
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>
33 #include <boost/asio/detail/push_options.hpp>
39 template <typename Socket, typename Protocol,
40 typename Handler, typename IoExecutor>
41 class win_iocp_socket_accept_op : public operation
44 BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op);
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,
49 bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)
50 : operation(&win_iocp_socket_accept_op::do_complete),
51 socket_service_(socket_service),
55 peer_endpoint_(peer_endpoint),
56 enable_connection_aborted_(enable_connection_aborted),
57 handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
60 handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
63 socket_holder& new_socket()
70 return output_buffer_;
73 DWORD address_length()
75 return sizeof(sockaddr_storage_type) + 16;
78 static void do_complete(void* owner, operation* base,
79 const boost::system::error_code& result_ec,
80 std::size_t /*bytes_transferred*/)
82 boost::system::error_code ec(result_ec);
84 // Take ownership of the operation object.
85 win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base));
86 ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
87 handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
91 typename Protocol::endpoint peer_endpoint;
92 std::size_t addr_len = peer_endpoint.capacity();
93 socket_ops::complete_iocp_accept(o->socket_,
94 o->output_buffer(), o->address_length(),
95 peer_endpoint.data(), &addr_len,
96 o->new_socket_.get(), ec);
98 // Restart the accept operation if we got the connection_aborted error
99 // and the enable_connection_aborted socket option is not set.
100 if (ec == boost::asio::error::connection_aborted
101 && !o->enable_connection_aborted_)
104 o->socket_service_.restart_accept_op(o->socket_,
105 o->new_socket_, o->protocol_.family(),
106 o->protocol_.type(), o->protocol_.protocol(),
107 o->output_buffer(), o->address_length(), o);
112 // If the socket was successfully accepted, transfer ownership of the
113 // socket to the peer object.
116 o->peer_.assign(o->protocol_,
117 typename Socket::native_handle_type(
118 o->new_socket_.get(), peer_endpoint), ec);
120 o->new_socket_.release();
123 // Pass endpoint back to caller.
124 if (o->peer_endpoint_)
125 *o->peer_endpoint_ = peer_endpoint;
128 BOOST_ASIO_HANDLER_COMPLETION((*o));
130 // Make a copy of the handler so that the memory can be deallocated before
131 // the upcall is made. Even if we're not about to make an upcall, a
132 // sub-object of the handler may be the true owner of the memory associated
133 // with the handler. Consequently, a local copy of the handler is required
134 // to ensure that any owning sub-object remains valid until after we have
135 // deallocated the memory here.
136 detail::binder1<Handler, boost::system::error_code>
137 handler(o->handler_, ec);
138 p.h = boost::asio::detail::addressof(handler.handler_);
141 // Make the upcall if required.
144 fenced_block b(fenced_block::half);
145 BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
146 w.complete(handler, handler.handler_);
147 BOOST_ASIO_HANDLER_INVOCATION_END;
152 win_iocp_socket_service_base& socket_service_;
154 socket_holder new_socket_;
157 typename Protocol::endpoint* peer_endpoint_;
158 unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
159 bool enable_connection_aborted_;
161 IoExecutor io_executor_;
164 #if defined(BOOST_ASIO_HAS_MOVE)
166 template <typename Protocol, typename PeerIoExecutor,
167 typename Handler, typename IoExecutor>
168 class win_iocp_socket_move_accept_op : public operation
171 BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op);
173 win_iocp_socket_move_accept_op(
174 win_iocp_socket_service_base& socket_service, socket_type socket,
175 const Protocol& protocol, const PeerIoExecutor& peer_io_ex,
176 typename Protocol::endpoint* peer_endpoint,
177 bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)
178 : operation(&win_iocp_socket_move_accept_op::do_complete),
179 socket_service_(socket_service),
183 peer_endpoint_(peer_endpoint),
184 enable_connection_aborted_(enable_connection_aborted),
185 handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
188 handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
191 socket_holder& new_socket()
196 void* output_buffer()
198 return output_buffer_;
201 DWORD address_length()
203 return sizeof(sockaddr_storage_type) + 16;
206 static void do_complete(void* owner, operation* base,
207 const boost::system::error_code& result_ec,
208 std::size_t /*bytes_transferred*/)
210 boost::system::error_code ec(result_ec);
212 // Take ownership of the operation object.
213 win_iocp_socket_move_accept_op* o(
214 static_cast<win_iocp_socket_move_accept_op*>(base));
215 ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
216 handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
220 typename Protocol::endpoint peer_endpoint;
221 std::size_t addr_len = peer_endpoint.capacity();
222 socket_ops::complete_iocp_accept(o->socket_,
223 o->output_buffer(), o->address_length(),
224 peer_endpoint.data(), &addr_len,
225 o->new_socket_.get(), ec);
227 // Restart the accept operation if we got the connection_aborted error
228 // and the enable_connection_aborted socket option is not set.
229 if (ec == boost::asio::error::connection_aborted
230 && !o->enable_connection_aborted_)
233 o->socket_service_.restart_accept_op(o->socket_,
234 o->new_socket_, o->protocol_.family(),
235 o->protocol_.type(), o->protocol_.protocol(),
236 o->output_buffer(), o->address_length(), o);
241 // If the socket was successfully accepted, transfer ownership of the
242 // socket to the peer object.
245 o->peer_.assign(o->protocol_,
246 typename Protocol::socket::native_handle_type(
247 o->new_socket_.get(), peer_endpoint), ec);
249 o->new_socket_.release();
252 // Pass endpoint back to caller.
253 if (o->peer_endpoint_)
254 *o->peer_endpoint_ = peer_endpoint;
257 BOOST_ASIO_HANDLER_COMPLETION((*o));
259 // Make a copy of the handler so that the memory can be deallocated before
260 // the upcall is made. Even if we're not about to make an upcall, a
261 // sub-object of the handler may be the true owner of the memory associated
262 // with the handler. Consequently, a local copy of the handler is required
263 // to ensure that any owning sub-object remains valid until after we have
264 // deallocated the memory here.
265 detail::move_binder2<Handler,
266 boost::system::error_code, peer_socket_type>
267 handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), ec,
268 BOOST_ASIO_MOVE_CAST(peer_socket_type)(o->peer_));
269 p.h = boost::asio::detail::addressof(handler.handler_);
272 // Make the upcall if required.
275 fenced_block b(fenced_block::half);
276 BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
277 w.complete(handler, handler.handler_);
278 BOOST_ASIO_HANDLER_INVOCATION_END;
283 typedef typename Protocol::socket::template
284 rebind_executor<PeerIoExecutor>::other peer_socket_type;
286 win_iocp_socket_service_base& socket_service_;
288 socket_holder new_socket_;
289 peer_socket_type peer_;
291 typename Protocol::endpoint* peer_endpoint_;
292 unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
293 bool enable_connection_aborted_;
295 IoExecutor io_executor_;
298 #endif // defined(BOOST_ASIO_HAS_MOVE)
300 } // namespace detail
304 #include <boost/asio/detail/pop_options.hpp>
306 #endif // defined(BOOST_ASIO_HAS_IOCP)
308 #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP