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 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 io_executor_(io_ex) 59 { 60 handler_work<Handler, IoExecutor>::start(handler_, io_executor_); 61 } 62 new_socket()63 socket_holder& new_socket() 64 { 65 return new_socket_; 66 } 67 output_buffer()68 void* output_buffer() 69 { 70 return output_buffer_; 71 } 72 address_length()73 DWORD address_length() 74 { 75 return sizeof(sockaddr_storage_type) + 16; 76 } 77 do_complete(void * owner,operation * base,const boost::system::error_code & result_ec,std::size_t)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 o->reset(); 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); 108 p.v = p.p = 0; 109 return; 110 } 111 112 // If the socket was successfully accepted, transfer ownership of the 113 // socket to the peer object. 114 if (!ec) 115 { 116 o->peer_.assign(o->protocol_, 117 typename Socket::native_handle_type( 118 o->new_socket_.get(), peer_endpoint), ec); 119 if (!ec) 120 o->new_socket_.release(); 121 } 122 123 // Pass endpoint back to caller. 124 if (o->peer_endpoint_) 125 *o->peer_endpoint_ = peer_endpoint; 126 } 127 128 BOOST_ASIO_HANDLER_COMPLETION((*o)); 129 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_); 139 p.reset(); 140 141 // Make the upcall if required. 142 if (owner) 143 { 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; 148 } 149 } 150 151 private: 152 win_iocp_socket_service_base& socket_service_; 153 socket_type socket_; 154 socket_holder new_socket_; 155 Socket& peer_; 156 Protocol protocol_; 157 typename Protocol::endpoint* peer_endpoint_; 158 unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; 159 bool enable_connection_aborted_; 160 Handler handler_; 161 IoExecutor io_executor_; 162 }; 163 164 #if defined(BOOST_ASIO_HAS_MOVE) 165 166 template <typename Protocol, typename PeerIoExecutor, 167 typename Handler, typename IoExecutor> 168 class win_iocp_socket_move_accept_op : public operation 169 { 170 public: 171 BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op); 172 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)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), 180 socket_(socket), 181 peer_(peer_io_ex), 182 protocol_(protocol), 183 peer_endpoint_(peer_endpoint), 184 enable_connection_aborted_(enable_connection_aborted), 185 handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), 186 io_executor_(io_ex) 187 { 188 handler_work<Handler, IoExecutor>::start(handler_, io_executor_); 189 } 190 new_socket()191 socket_holder& new_socket() 192 { 193 return new_socket_; 194 } 195 output_buffer()196 void* output_buffer() 197 { 198 return output_buffer_; 199 } 200 address_length()201 DWORD address_length() 202 { 203 return sizeof(sockaddr_storage_type) + 16; 204 } 205 do_complete(void * owner,operation * base,const boost::system::error_code & result_ec,std::size_t)206 static void do_complete(void* owner, operation* base, 207 const boost::system::error_code& result_ec, 208 std::size_t /*bytes_transferred*/) 209 { 210 boost::system::error_code ec(result_ec); 211 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_); 217 218 if (owner) 219 { 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); 226 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_) 231 { 232 o->reset(); 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); 237 p.v = p.p = 0; 238 return; 239 } 240 241 // If the socket was successfully accepted, transfer ownership of the 242 // socket to the peer object. 243 if (!ec) 244 { 245 o->peer_.assign(o->protocol_, 246 typename Protocol::socket::native_handle_type( 247 o->new_socket_.get(), peer_endpoint), ec); 248 if (!ec) 249 o->new_socket_.release(); 250 } 251 252 // Pass endpoint back to caller. 253 if (o->peer_endpoint_) 254 *o->peer_endpoint_ = peer_endpoint; 255 } 256 257 BOOST_ASIO_HANDLER_COMPLETION((*o)); 258 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_); 270 p.reset(); 271 272 // Make the upcall if required. 273 if (owner) 274 { 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; 279 } 280 } 281 282 private: 283 typedef typename Protocol::socket::template 284 rebind_executor<PeerIoExecutor>::other peer_socket_type; 285 286 win_iocp_socket_service_base& socket_service_; 287 socket_type socket_; 288 socket_holder new_socket_; 289 peer_socket_type peer_; 290 Protocol protocol_; 291 typename Protocol::endpoint* peer_endpoint_; 292 unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; 293 bool enable_connection_aborted_; 294 Handler handler_; 295 IoExecutor io_executor_; 296 }; 297 298 #endif // defined(BOOST_ASIO_HAS_MOVE) 299 300 } // namespace detail 301 } // namespace asio 302 } // namespace boost 303 304 #include <boost/asio/detail/pop_options.hpp> 305 306 #endif // defined(BOOST_ASIO_HAS_IOCP) 307 308 #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP 309