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