1 //
2 // detail/win_iocp_socket_accept_op.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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_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 
22 #include <boost/asio/detail/bind_handler.hpp>
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>
26 #include <boost/asio/detail/handler_work.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>
32 
33 #include <boost/asio/detail/push_options.hpp>
34 
35 namespace boost {
36 namespace asio {
37 namespace detail {
38 
39 template <typename Socket, typename Protocol,
40     typename Handler, typename IoExecutor>
41 class win_iocp_socket_accept_op : public operation
42 {
43 public:
44   BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op);
45 
win_iocp_socket_accept_op(win_iocp_socket_service_base & socket_service,socket_type socket,Socket & peer,const Protocol & protocol,typename Protocol::endpoint * peer_endpoint,bool enable_connection_aborted,Handler & handler,const IoExecutor & io_ex)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),
52       socket_(socket),
53       peer_(peer),
54       protocol_(protocol),
55       peer_endpoint_(peer_endpoint),
56       enable_connection_aborted_(enable_connection_aborted),
57       handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
58       work_(handler_, io_ex)
59   {
60   }
61 
new_socket()62   socket_holder& new_socket()
63   {
64     return new_socket_;
65   }
66 
output_buffer()67   void* output_buffer()
68   {
69     return output_buffer_;
70   }
71 
address_length()72   DWORD address_length()
73   {
74     return sizeof(sockaddr_storage_type) + 16;
75   }
76 
do_complete(void * owner,operation * base,const boost::system::error_code & result_ec,std::size_t)77   static void do_complete(void* owner, operation* base,
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 
126     BOOST_ASIO_HANDLER_COMPLETION((*o));
127 
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 
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_));
149       w.complete(handler, handler.handler_);
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_;
164   handler_work<Handler, IoExecutor> work_;
165 };
166 
167 #if defined(BOOST_ASIO_HAS_MOVE)
168 
169 template <typename Protocol, typename PeerIoExecutor,
170     typename Handler, typename IoExecutor>
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 
win_iocp_socket_move_accept_op(win_iocp_socket_service_base & socket_service,socket_type socket,const Protocol & protocol,const PeerIoExecutor & peer_io_ex,typename Protocol::endpoint * peer_endpoint,bool enable_connection_aborted,Handler & handler,const IoExecutor & io_ex)176   win_iocp_socket_move_accept_op(
177       win_iocp_socket_service_base& socket_service, socket_type socket,
178       const Protocol& protocol, const PeerIoExecutor& peer_io_ex,
179       typename Protocol::endpoint* peer_endpoint,
180       bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)
181     : operation(&win_iocp_socket_move_accept_op::do_complete),
182       socket_service_(socket_service),
183       socket_(socket),
184       peer_(peer_io_ex),
185       protocol_(protocol),
186       peer_endpoint_(peer_endpoint),
187       enable_connection_aborted_(enable_connection_aborted),
188       handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
189       work_(handler_, io_ex)
190   {
191   }
192 
new_socket()193   socket_holder& new_socket()
194   {
195     return new_socket_;
196   }
197 
output_buffer()198   void* output_buffer()
199   {
200     return output_buffer_;
201   }
202 
address_length()203   DWORD address_length()
204   {
205     return sizeof(sockaddr_storage_type) + 16;
206   }
207 
do_complete(void * owner,operation * base,const boost::system::error_code & result_ec,std::size_t)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 };
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 
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 
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,
272       boost::system::error_code, peer_socket_type>
273         handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), ec,
274           BOOST_ASIO_MOVE_CAST(peer_socket_type)(o->peer_));
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:
289   typedef typename Protocol::socket::template
290     rebind_executor<PeerIoExecutor>::other peer_socket_type;
291 
292   win_iocp_socket_service_base& socket_service_;
293   socket_type socket_;
294   socket_holder new_socket_;
295   peer_socket_type peer_;
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_;
301   handler_work<Handler, IoExecutor> work_;
302 };
303 
304 #endif // defined(BOOST_ASIO_HAS_MOVE)
305 
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
315