Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / asio / detail / win_iocp_socket_accept_op.hpp
1 //
2 // detail/win_iocp_socket_accept_op.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 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/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>
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
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       io_executor_(io_ex)
59   {
60     handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
61   }
62
63   socket_holder& new_socket()
64   {
65     return new_socket_;
66   }
67
68   void* output_buffer()
69   {
70     return output_buffer_;
71   }
72
73   DWORD address_length()
74   {
75     return sizeof(sockaddr_storage_type) + 16;
76   }
77
78   static void do_complete(void* owner, operation* base,
79       const boost::system::error_code& result_ec,
80       std::size_t /*bytes_transferred*/)
81   {
82     boost::system::error_code ec(result_ec);
83
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_);
88
89     if (owner)
90     {
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);
97
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_)
102       {
103         handler_work<Handler, IoExecutor>::start(o->handler_, o->io_executor_);
104         o->reset();
105         o->socket_service_.restart_accept_op(o->socket_,
106             o->new_socket_, o->protocol_.family(),
107             o->protocol_.type(), o->protocol_.protocol(),
108             o->output_buffer(), o->address_length(), o);
109         p.v = p.p = 0;
110         return;
111       }
112
113       // If the socket was successfully accepted, transfer ownership of the
114       // socket to the peer object.
115       if (!ec)
116       {
117         o->peer_.assign(o->protocol_,
118             typename Socket::native_handle_type(
119               o->new_socket_.get(), peer_endpoint), ec);
120         if (!ec)
121           o->new_socket_.release();
122       }
123
124       // Pass endpoint back to caller.
125       if (o->peer_endpoint_)
126         *o->peer_endpoint_ = peer_endpoint;
127     }
128
129     BOOST_ASIO_HANDLER_COMPLETION((*o));
130
131     // Make a copy of the handler so that the memory can be deallocated before
132     // the upcall is made. Even if we're not about to make an upcall, a
133     // sub-object of the handler may be the true owner of the memory associated
134     // with the handler. Consequently, a local copy of the handler is required
135     // to ensure that any owning sub-object remains valid until after we have
136     // deallocated the memory here.
137     detail::binder1<Handler, boost::system::error_code>
138       handler(o->handler_, ec);
139     p.h = boost::asio::detail::addressof(handler.handler_);
140     p.reset();
141
142     // Make the upcall if required.
143     if (owner)
144     {
145       fenced_block b(fenced_block::half);
146       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
147       w.complete(handler, handler.handler_);
148       BOOST_ASIO_HANDLER_INVOCATION_END;
149     }
150   }
151
152 private:
153   win_iocp_socket_service_base& socket_service_;
154   socket_type socket_;
155   socket_holder new_socket_;
156   Socket& peer_;
157   Protocol protocol_;
158   typename Protocol::endpoint* peer_endpoint_;
159   unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
160   bool enable_connection_aborted_;
161   Handler handler_;
162   IoExecutor io_executor_;
163 };
164
165 #if defined(BOOST_ASIO_HAS_MOVE)
166
167 template <typename Protocol, typename PeerIoExecutor,
168     typename Handler, typename IoExecutor>
169 class win_iocp_socket_move_accept_op : public operation
170 {
171 public:
172   BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op);
173
174   win_iocp_socket_move_accept_op(
175       win_iocp_socket_service_base& socket_service, socket_type socket,
176       const Protocol& protocol, const PeerIoExecutor& peer_io_ex,
177       typename Protocol::endpoint* peer_endpoint,
178       bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)
179     : operation(&win_iocp_socket_move_accept_op::do_complete),
180       socket_service_(socket_service),
181       socket_(socket),
182       peer_(peer_io_ex),
183       protocol_(protocol),
184       peer_endpoint_(peer_endpoint),
185       enable_connection_aborted_(enable_connection_aborted),
186       handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
187       io_executor_(io_ex)
188   {
189     handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
190   }
191
192   socket_holder& new_socket()
193   {
194     return new_socket_;
195   }
196
197   void* output_buffer()
198   {
199     return output_buffer_;
200   }
201
202   DWORD address_length()
203   {
204     return sizeof(sockaddr_storage_type) + 16;
205   }
206
207   static void do_complete(void* owner, operation* base,
208       const boost::system::error_code& result_ec,
209       std::size_t /*bytes_transferred*/)
210   {
211     boost::system::error_code ec(result_ec);
212
213     // Take ownership of the operation object.
214     win_iocp_socket_move_accept_op* o(
215         static_cast<win_iocp_socket_move_accept_op*>(base));
216     ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
217     handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
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         handler_work<Handler, IoExecutor>::start(o->handler_, o->io_executor_);
234         o->reset();
235         o->socket_service_.restart_accept_op(o->socket_,
236             o->new_socket_, o->protocol_.family(),
237             o->protocol_.type(), o->protocol_.protocol(),
238             o->output_buffer(), o->address_length(), o);
239         p.v = p.p = 0;
240         return;
241       }
242
243       // If the socket was successfully accepted, transfer ownership of the
244       // socket to the peer object.
245       if (!ec)
246       {
247         o->peer_.assign(o->protocol_,
248             typename Protocol::socket::native_handle_type(
249               o->new_socket_.get(), peer_endpoint), ec);
250         if (!ec)
251           o->new_socket_.release();
252       }
253
254       // Pass endpoint back to caller.
255       if (o->peer_endpoint_)
256         *o->peer_endpoint_ = peer_endpoint;
257     }
258
259     BOOST_ASIO_HANDLER_COMPLETION((*o));
260
261     // Make a copy of the handler so that the memory can be deallocated before
262     // the upcall is made. Even if we're not about to make an upcall, a
263     // sub-object of the handler may be the true owner of the memory associated
264     // with the handler. Consequently, a local copy of the handler is required
265     // to ensure that any owning sub-object remains valid until after we have
266     // deallocated the memory here.
267     detail::move_binder2<Handler,
268       boost::system::error_code, peer_socket_type>
269         handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), ec,
270           BOOST_ASIO_MOVE_CAST(peer_socket_type)(o->peer_));
271     p.h = boost::asio::detail::addressof(handler.handler_);
272     p.reset();
273
274     // Make the upcall if required.
275     if (owner)
276     {
277       fenced_block b(fenced_block::half);
278       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
279       w.complete(handler, handler.handler_);
280       BOOST_ASIO_HANDLER_INVOCATION_END;
281     }
282   }
283
284 private:
285   typedef typename Protocol::socket::template
286     rebind_executor<PeerIoExecutor>::other peer_socket_type;
287
288   win_iocp_socket_service_base& socket_service_;
289   socket_type socket_;
290   socket_holder new_socket_;
291   peer_socket_type peer_;
292   Protocol protocol_;
293   typename Protocol::endpoint* peer_endpoint_;
294   unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
295   bool enable_connection_aborted_;
296   Handler handler_;
297   IoExecutor io_executor_;
298 };
299
300 #endif // defined(BOOST_ASIO_HAS_MOVE)
301
302 } // namespace detail
303 } // namespace asio
304 } // namespace boost
305
306 #include <boost/asio/detail/pop_options.hpp>
307
308 #endif // defined(BOOST_ASIO_HAS_IOCP)
309
310 #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP