1 // 2 // detail/reactive_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_REACTIVE_SOCKET_ACCEPT_OP_HPP 12 #define BOOST_ASIO_DETAIL_REACTIVE_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 #include <boost/asio/detail/bind_handler.hpp> 20 #include <boost/asio/detail/fenced_block.hpp> 21 #include <boost/asio/detail/handler_alloc_helpers.hpp> 22 #include <boost/asio/detail/handler_invoke_helpers.hpp> 23 #include <boost/asio/detail/handler_work.hpp> 24 #include <boost/asio/detail/memory.hpp> 25 #include <boost/asio/detail/reactor_op.hpp> 26 #include <boost/asio/detail/socket_holder.hpp> 27 #include <boost/asio/detail/socket_ops.hpp> 28 29 #include <boost/asio/detail/push_options.hpp> 30 31 namespace boost { 32 namespace asio { 33 namespace detail { 34 35 template <typename Socket, typename Protocol> 36 class reactive_socket_accept_op_base : public reactor_op 37 { 38 public: reactive_socket_accept_op_base(const boost::system::error_code & success_ec,socket_type socket,socket_ops::state_type state,Socket & peer,const Protocol & protocol,typename Protocol::endpoint * peer_endpoint,func_type complete_func)39 reactive_socket_accept_op_base(const boost::system::error_code& success_ec, 40 socket_type socket, socket_ops::state_type state, Socket& peer, 41 const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, 42 func_type complete_func) 43 : reactor_op(success_ec, 44 &reactive_socket_accept_op_base::do_perform, complete_func), 45 socket_(socket), 46 state_(state), 47 peer_(peer), 48 protocol_(protocol), 49 peer_endpoint_(peer_endpoint), 50 addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0) 51 { 52 } 53 do_perform(reactor_op * base)54 static status do_perform(reactor_op* base) 55 { 56 reactive_socket_accept_op_base* o( 57 static_cast<reactive_socket_accept_op_base*>(base)); 58 59 socket_type new_socket = invalid_socket; 60 status result = socket_ops::non_blocking_accept(o->socket_, 61 o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, 62 o->peer_endpoint_ ? &o->addrlen_ : 0, o->ec_, new_socket) 63 ? done : not_done; 64 o->new_socket_.reset(new_socket); 65 66 BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_accept", o->ec_)); 67 68 return result; 69 } 70 do_assign()71 void do_assign() 72 { 73 if (new_socket_.get() != invalid_socket) 74 { 75 if (peer_endpoint_) 76 peer_endpoint_->resize(addrlen_); 77 peer_.assign(protocol_, new_socket_.get(), ec_); 78 if (!ec_) 79 new_socket_.release(); 80 } 81 } 82 83 private: 84 socket_type socket_; 85 socket_ops::state_type state_; 86 socket_holder new_socket_; 87 Socket& peer_; 88 Protocol protocol_; 89 typename Protocol::endpoint* peer_endpoint_; 90 std::size_t addrlen_; 91 }; 92 93 template <typename Socket, typename Protocol, 94 typename Handler, typename IoExecutor> 95 class reactive_socket_accept_op : 96 public reactive_socket_accept_op_base<Socket, Protocol> 97 { 98 public: 99 BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); 100 reactive_socket_accept_op(const boost::system::error_code & success_ec,socket_type socket,socket_ops::state_type state,Socket & peer,const Protocol & protocol,typename Protocol::endpoint * peer_endpoint,Handler & handler,const IoExecutor & io_ex)101 reactive_socket_accept_op(const boost::system::error_code& success_ec, 102 socket_type socket, socket_ops::state_type state, Socket& peer, 103 const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, 104 Handler& handler, const IoExecutor& io_ex) 105 : reactive_socket_accept_op_base<Socket, Protocol>( 106 success_ec, socket, state, peer, protocol, peer_endpoint, 107 &reactive_socket_accept_op::do_complete), 108 handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), 109 work_(handler_, io_ex) 110 { 111 } 112 do_complete(void * owner,operation * base,const boost::system::error_code &,std::size_t)113 static void do_complete(void* owner, operation* base, 114 const boost::system::error_code& /*ec*/, 115 std::size_t /*bytes_transferred*/) 116 { 117 // Take ownership of the handler object. 118 reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base)); 119 ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; 120 121 // On success, assign new connection to peer socket object. 122 if (owner) 123 o->do_assign(); 124 125 BOOST_ASIO_HANDLER_COMPLETION((*o)); 126 127 // Take ownership of the operation's outstanding work. 128 handler_work<Handler, IoExecutor> w( 129 BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( 130 o->work_)); 131 132 // Make a copy of the handler so that the memory can be deallocated before 133 // the upcall is made. Even if we're not about to make an upcall, a 134 // sub-object of the handler may be the true owner of the memory associated 135 // with the handler. Consequently, a local copy of the handler is required 136 // to ensure that any owning sub-object remains valid until after we have 137 // deallocated the memory here. 138 detail::binder1<Handler, boost::system::error_code> 139 handler(o->handler_, o->ec_); 140 p.h = boost::asio::detail::addressof(handler.handler_); 141 p.reset(); 142 143 // Make the upcall if required. 144 if (owner) 145 { 146 fenced_block b(fenced_block::half); 147 BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); 148 w.complete(handler, handler.handler_); 149 BOOST_ASIO_HANDLER_INVOCATION_END; 150 } 151 } 152 153 private: 154 Handler handler_; 155 handler_work<Handler, IoExecutor> work_; 156 }; 157 158 #if defined(BOOST_ASIO_HAS_MOVE) 159 160 template <typename Protocol, typename PeerIoExecutor, 161 typename Handler, typename IoExecutor> 162 class reactive_socket_move_accept_op : 163 private Protocol::socket::template rebind_executor<PeerIoExecutor>::other, 164 public reactive_socket_accept_op_base< 165 typename Protocol::socket::template rebind_executor<PeerIoExecutor>::other, 166 Protocol> 167 { 168 public: 169 BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); 170 reactive_socket_move_accept_op(const boost::system::error_code & success_ec,const PeerIoExecutor & peer_io_ex,socket_type socket,socket_ops::state_type state,const Protocol & protocol,typename Protocol::endpoint * peer_endpoint,Handler & handler,const IoExecutor & io_ex)171 reactive_socket_move_accept_op(const boost::system::error_code& success_ec, 172 const PeerIoExecutor& peer_io_ex, socket_type socket, 173 socket_ops::state_type state, const Protocol& protocol, 174 typename Protocol::endpoint* peer_endpoint, Handler& handler, 175 const IoExecutor& io_ex) 176 : peer_socket_type(peer_io_ex), 177 reactive_socket_accept_op_base<peer_socket_type, Protocol>( 178 success_ec, socket, state, *this, protocol, peer_endpoint, 179 &reactive_socket_move_accept_op::do_complete), 180 handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), 181 work_(handler_, io_ex) 182 { 183 } 184 do_complete(void * owner,operation * base,const boost::system::error_code &,std::size_t)185 static void do_complete(void* owner, operation* base, 186 const boost::system::error_code& /*ec*/, 187 std::size_t /*bytes_transferred*/) 188 { 189 // Take ownership of the handler object. 190 reactive_socket_move_accept_op* o( 191 static_cast<reactive_socket_move_accept_op*>(base)); 192 ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; 193 194 // On success, assign new connection to peer socket object. 195 if (owner) 196 o->do_assign(); 197 198 BOOST_ASIO_HANDLER_COMPLETION((*o)); 199 200 // Take ownership of the operation's outstanding work. 201 handler_work<Handler, IoExecutor> w( 202 BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( 203 o->work_)); 204 205 // Make a copy of the handler so that the memory can be deallocated before 206 // the upcall is made. Even if we're not about to make an upcall, a 207 // sub-object of the handler may be the true owner of the memory associated 208 // with the handler. Consequently, a local copy of the handler is required 209 // to ensure that any owning sub-object remains valid until after we have 210 // deallocated the memory here. 211 detail::move_binder2<Handler, 212 boost::system::error_code, peer_socket_type> 213 handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_, 214 BOOST_ASIO_MOVE_CAST(peer_socket_type)(*o)); 215 p.h = boost::asio::detail::addressof(handler.handler_); 216 p.reset(); 217 218 // Make the upcall if required. 219 if (owner) 220 { 221 fenced_block b(fenced_block::half); 222 BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); 223 w.complete(handler, handler.handler_); 224 BOOST_ASIO_HANDLER_INVOCATION_END; 225 } 226 } 227 228 private: 229 typedef typename Protocol::socket::template 230 rebind_executor<PeerIoExecutor>::other peer_socket_type; 231 232 Handler handler_; 233 handler_work<Handler, IoExecutor> work_; 234 }; 235 236 #endif // defined(BOOST_ASIO_HAS_MOVE) 237 238 } // namespace detail 239 } // namespace asio 240 } // namespace boost 241 242 #include <boost/asio/detail/pop_options.hpp> 243 244 #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP 245