1 // 2 // detail/reactive_socket_service.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2015 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 ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP 12 #define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP 13 14 15 #include "asio/detail/config.hpp" 16 17 18 #include "asio/buffer.hpp" 19 #include "asio/error.hpp" 20 #include "asio/io_service.hpp" 21 #include "asio/socket_base.hpp" 22 #include "asio/detail/addressof.hpp" 23 #include "asio/detail/buffer_sequence_adapter.hpp" 24 #include "asio/detail/noncopyable.hpp" 25 #include "asio/detail/reactive_null_buffers_op.hpp" 26 #include "asio/detail/reactive_socket_accept_op.hpp" 27 #include "asio/detail/reactive_socket_connect_op.hpp" 28 #include "asio/detail/reactive_socket_recvfrom_op.hpp" 29 #include "asio/detail/reactive_socket_sendto_op.hpp" 30 #include "asio/detail/reactive_socket_service_base.hpp" 31 #include "asio/detail/reactor.hpp" 32 #include "asio/detail/reactor_op.hpp" 33 #include "asio/detail/socket_holder.hpp" 34 #include "asio/detail/socket_ops.hpp" 35 #include "asio/detail/socket_types.hpp" 36 37 #include "asio/detail/push_options.hpp" 38 39 namespace asio { 40 namespace detail { 41 42 template <typename Protocol> 43 class reactive_socket_service : 44 public reactive_socket_service_base 45 { 46 public: 47 // The protocol type. 48 typedef Protocol protocol_type; 49 50 // The endpoint type. 51 typedef typename Protocol::endpoint endpoint_type; 52 53 // The native type of a socket. 54 typedef socket_type native_handle_type; 55 56 // The implementation type of the socket. 57 struct implementation_type : 58 reactive_socket_service_base::base_implementation_type 59 { 60 // Default constructor. implementation_typeasio::detail::reactive_socket_service::implementation_type61 implementation_type() 62 : protocol_(endpoint_type().protocol()) 63 { 64 } 65 66 // The protocol associated with the socket. 67 protocol_type protocol_; 68 }; 69 70 // Constructor. reactive_socket_service(asio::io_service & io_service)71 reactive_socket_service(asio::io_service& io_service) 72 : reactive_socket_service_base(io_service) 73 { 74 } 75 76 // Move-construct a new socket implementation. move_construct(implementation_type & impl,implementation_type & other_impl)77 void move_construct(implementation_type& impl, 78 implementation_type& other_impl) 79 { 80 this->base_move_construct(impl, other_impl); 81 82 impl.protocol_ = other_impl.protocol_; 83 other_impl.protocol_ = endpoint_type().protocol(); 84 } 85 86 // Move-assign from another socket implementation. move_assign(implementation_type & impl,reactive_socket_service_base & other_service,implementation_type & other_impl)87 void move_assign(implementation_type& impl, 88 reactive_socket_service_base& other_service, 89 implementation_type& other_impl) 90 { 91 this->base_move_assign(impl, other_service, other_impl); 92 93 impl.protocol_ = other_impl.protocol_; 94 other_impl.protocol_ = endpoint_type().protocol(); 95 } 96 97 // Move-construct a new socket implementation from another protocol type. 98 template <typename Protocol1> converting_move_construct(implementation_type & impl,typename reactive_socket_service<Protocol1>::implementation_type & other_impl)99 void converting_move_construct(implementation_type& impl, 100 typename reactive_socket_service< 101 Protocol1>::implementation_type& other_impl) 102 { 103 this->base_move_construct(impl, other_impl); 104 105 impl.protocol_ = protocol_type(other_impl.protocol_); 106 other_impl.protocol_ = typename Protocol1::endpoint().protocol(); 107 } 108 109 // Open a new socket implementation. open(implementation_type & impl,const protocol_type & protocol,asio::error_code & ec)110 asio::error_code open(implementation_type& impl, 111 const protocol_type& protocol, asio::error_code& ec) 112 { 113 if (!do_open(impl, protocol.family(), 114 protocol.type(), protocol.protocol(), ec)) 115 impl.protocol_ = protocol; 116 return ec; 117 } 118 119 // Assign a native socket to a socket implementation. assign(implementation_type & impl,const protocol_type & protocol,const native_handle_type & native_socket,asio::error_code & ec)120 asio::error_code assign(implementation_type& impl, 121 const protocol_type& protocol, const native_handle_type& native_socket, 122 asio::error_code& ec) 123 { 124 if (!do_assign(impl, protocol.type(), native_socket, ec)) 125 impl.protocol_ = protocol; 126 return ec; 127 } 128 129 // Get the native socket representation. native_handle(implementation_type & impl)130 native_handle_type native_handle(implementation_type& impl) 131 { 132 return impl.socket_; 133 } 134 135 // Bind the socket to the specified local endpoint. bind(implementation_type & impl,const endpoint_type & endpoint,asio::error_code & ec)136 asio::error_code bind(implementation_type& impl, 137 const endpoint_type& endpoint, asio::error_code& ec) 138 { 139 socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); 140 return ec; 141 } 142 143 // Set a socket option. 144 template <typename Option> set_option(implementation_type & impl,const Option & option,asio::error_code & ec)145 asio::error_code set_option(implementation_type& impl, 146 const Option& option, asio::error_code& ec) 147 { 148 socket_ops::setsockopt(impl.socket_, impl.state_, 149 option.level(impl.protocol_), option.name(impl.protocol_), 150 option.data(impl.protocol_), option.size(impl.protocol_), ec); 151 return ec; 152 } 153 154 // Set a socket option. 155 template <typename Option> get_option(const implementation_type & impl,Option & option,asio::error_code & ec) const156 asio::error_code get_option(const implementation_type& impl, 157 Option& option, asio::error_code& ec) const 158 { 159 std::size_t size = option.size(impl.protocol_); 160 socket_ops::getsockopt(impl.socket_, impl.state_, 161 option.level(impl.protocol_), option.name(impl.protocol_), 162 option.data(impl.protocol_), &size, ec); 163 if (!ec) 164 option.resize(impl.protocol_, size); 165 return ec; 166 } 167 168 // Get the local endpoint. local_endpoint(const implementation_type & impl,asio::error_code & ec) const169 endpoint_type local_endpoint(const implementation_type& impl, 170 asio::error_code& ec) const 171 { 172 endpoint_type endpoint; 173 std::size_t addr_len = endpoint.capacity(); 174 if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) 175 return endpoint_type(); 176 endpoint.resize(addr_len); 177 return endpoint; 178 } 179 180 // Get the remote endpoint. remote_endpoint(const implementation_type & impl,asio::error_code & ec) const181 endpoint_type remote_endpoint(const implementation_type& impl, 182 asio::error_code& ec) const 183 { 184 endpoint_type endpoint; 185 std::size_t addr_len = endpoint.capacity(); 186 if (socket_ops::getpeername(impl.socket_, 187 endpoint.data(), &addr_len, false, ec)) 188 return endpoint_type(); 189 endpoint.resize(addr_len); 190 return endpoint; 191 } 192 193 // Send a datagram to the specified endpoint. Returns the number of bytes 194 // sent. 195 template <typename ConstBufferSequence> send_to(implementation_type & impl,const ConstBufferSequence & buffers,const endpoint_type & destination,socket_base::message_flags flags,asio::error_code & ec)196 size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, 197 const endpoint_type& destination, socket_base::message_flags flags, 198 asio::error_code& ec) 199 { 200 buffer_sequence_adapter<asio::const_buffer, 201 ConstBufferSequence> bufs(buffers); 202 203 return socket_ops::sync_sendto(impl.socket_, impl.state_, 204 bufs.buffers(), bufs.count(), flags, 205 destination.data(), destination.size(), ec); 206 } 207 208 // Wait until data can be sent without blocking. send_to(implementation_type & impl,const null_buffers &,const endpoint_type &,socket_base::message_flags,asio::error_code & ec)209 size_t send_to(implementation_type& impl, const null_buffers&, 210 const endpoint_type&, socket_base::message_flags, 211 asio::error_code& ec) 212 { 213 // Wait for socket to become ready. 214 socket_ops::poll_write(impl.socket_, impl.state_, ec); 215 216 return 0; 217 } 218 219 // Start an asynchronous send. The data being sent must be valid for the 220 // lifetime of the asynchronous operation. 221 template <typename ConstBufferSequence, typename Handler> async_send_to(implementation_type & impl,const ConstBufferSequence & buffers,const endpoint_type & destination,socket_base::message_flags flags,Handler & handler)222 void async_send_to(implementation_type& impl, 223 const ConstBufferSequence& buffers, 224 const endpoint_type& destination, socket_base::message_flags flags, 225 Handler& handler) 226 { 227 bool is_continuation = 228 asio_handler_cont_helpers::is_continuation(handler); 229 230 // Allocate and construct an operation to wrap the handler. 231 typedef reactive_socket_sendto_op<ConstBufferSequence, 232 endpoint_type, Handler> op; 233 typename op::ptr p = { asio::detail::addressof(handler), 234 asio_handler_alloc_helpers::allocate( 235 sizeof(op), handler), 0 }; 236 p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler); 237 238 ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send_to")); 239 240 start_op(impl, reactor::write_op, p.p, is_continuation, true, false); 241 p.v = p.p = 0; 242 } 243 244 // Start an asynchronous wait until data can be sent without blocking. 245 template <typename Handler> async_send_to(implementation_type & impl,const null_buffers &,const endpoint_type &,socket_base::message_flags,Handler & handler)246 void async_send_to(implementation_type& impl, const null_buffers&, 247 const endpoint_type&, socket_base::message_flags, Handler& handler) 248 { 249 bool is_continuation = 250 asio_handler_cont_helpers::is_continuation(handler); 251 252 // Allocate and construct an operation to wrap the handler. 253 typedef reactive_null_buffers_op<Handler> op; 254 typename op::ptr p = { asio::detail::addressof(handler), 255 asio_handler_alloc_helpers::allocate( 256 sizeof(op), handler), 0 }; 257 p.p = new (p.v) op(handler); 258 259 ASIO_HANDLER_CREATION((p.p, "socket", 260 &impl, "async_send_to(null_buffers)")); 261 262 start_op(impl, reactor::write_op, p.p, is_continuation, false, false); 263 p.v = p.p = 0; 264 } 265 266 // Receive a datagram with the endpoint of the sender. Returns the number of 267 // bytes received. 268 template <typename MutableBufferSequence> receive_from(implementation_type & impl,const MutableBufferSequence & buffers,endpoint_type & sender_endpoint,socket_base::message_flags flags,asio::error_code & ec)269 size_t receive_from(implementation_type& impl, 270 const MutableBufferSequence& buffers, 271 endpoint_type& sender_endpoint, socket_base::message_flags flags, 272 asio::error_code& ec) 273 { 274 buffer_sequence_adapter<asio::mutable_buffer, 275 MutableBufferSequence> bufs(buffers); 276 277 std::size_t addr_len = sender_endpoint.capacity(); 278 std::size_t bytes_recvd = socket_ops::sync_recvfrom( 279 impl.socket_, impl.state_, bufs.buffers(), bufs.count(), 280 flags, sender_endpoint.data(), &addr_len, ec); 281 282 if (!ec) 283 sender_endpoint.resize(addr_len); 284 285 return bytes_recvd; 286 } 287 288 // Wait until data can be received without blocking. receive_from(implementation_type & impl,const null_buffers &,endpoint_type & sender_endpoint,socket_base::message_flags,asio::error_code & ec)289 size_t receive_from(implementation_type& impl, const null_buffers&, 290 endpoint_type& sender_endpoint, socket_base::message_flags, 291 asio::error_code& ec) 292 { 293 // Wait for socket to become ready. 294 socket_ops::poll_read(impl.socket_, impl.state_, ec); 295 296 // Reset endpoint since it can be given no sensible value at this time. 297 sender_endpoint = endpoint_type(); 298 299 return 0; 300 } 301 302 // Start an asynchronous receive. The buffer for the data being received and 303 // the sender_endpoint object must both be valid for the lifetime of the 304 // asynchronous operation. 305 template <typename MutableBufferSequence, typename Handler> async_receive_from(implementation_type & impl,const MutableBufferSequence & buffers,endpoint_type & sender_endpoint,socket_base::message_flags flags,Handler & handler)306 void async_receive_from(implementation_type& impl, 307 const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, 308 socket_base::message_flags flags, Handler& handler) 309 { 310 bool is_continuation = 311 asio_handler_cont_helpers::is_continuation(handler); 312 313 // Allocate and construct an operation to wrap the handler. 314 typedef reactive_socket_recvfrom_op<MutableBufferSequence, 315 endpoint_type, Handler> op; 316 typename op::ptr p = { asio::detail::addressof(handler), 317 asio_handler_alloc_helpers::allocate( 318 sizeof(op), handler), 0 }; 319 int protocol = impl.protocol_.type(); 320 p.p = new (p.v) op(impl.socket_, protocol, 321 buffers, sender_endpoint, flags, handler); 322 323 ASIO_HANDLER_CREATION((p.p, "socket", 324 &impl, "async_receive_from")); 325 326 start_op(impl, 327 (flags & socket_base::message_out_of_band) 328 ? reactor::except_op : reactor::read_op, 329 p.p, is_continuation, true, false); 330 p.v = p.p = 0; 331 } 332 333 // Wait until data can be received without blocking. 334 template <typename Handler> async_receive_from(implementation_type & impl,const null_buffers &,endpoint_type & sender_endpoint,socket_base::message_flags flags,Handler & handler)335 void async_receive_from(implementation_type& impl, 336 const null_buffers&, endpoint_type& sender_endpoint, 337 socket_base::message_flags flags, Handler& handler) 338 { 339 bool is_continuation = 340 asio_handler_cont_helpers::is_continuation(handler); 341 342 // Allocate and construct an operation to wrap the handler. 343 typedef reactive_null_buffers_op<Handler> op; 344 typename op::ptr p = { asio::detail::addressof(handler), 345 asio_handler_alloc_helpers::allocate( 346 sizeof(op), handler), 0 }; 347 p.p = new (p.v) op(handler); 348 349 ASIO_HANDLER_CREATION((p.p, "socket", 350 &impl, "async_receive_from(null_buffers)")); 351 352 // Reset endpoint since it can be given no sensible value at this time. 353 sender_endpoint = endpoint_type(); 354 355 start_op(impl, 356 (flags & socket_base::message_out_of_band) 357 ? reactor::except_op : reactor::read_op, 358 p.p, is_continuation, false, false); 359 p.v = p.p = 0; 360 } 361 362 // Accept a new connection. 363 template <typename Socket> accept(implementation_type & impl,Socket & peer,endpoint_type * peer_endpoint,asio::error_code & ec)364 asio::error_code accept(implementation_type& impl, 365 Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) 366 { 367 // We cannot accept a socket that is already open. 368 if (peer.is_open()) 369 { 370 ec = asio::error::already_open; 371 return ec; 372 } 373 374 std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; 375 socket_holder new_socket(socket_ops::sync_accept(impl.socket_, 376 impl.state_, peer_endpoint ? peer_endpoint->data() : 0, 377 peer_endpoint ? &addr_len : 0, ec)); 378 379 // On success, assign new connection to peer socket object. 380 if (new_socket.get() != invalid_socket) 381 { 382 if (peer_endpoint) 383 peer_endpoint->resize(addr_len); 384 if (!peer.assign(impl.protocol_, new_socket.get(), ec)) 385 new_socket.release(); 386 } 387 388 return ec; 389 } 390 391 // Start an asynchronous accept. The peer and peer_endpoint objects 392 // must be valid until the accept's handler is invoked. 393 template <typename Socket, typename Handler> async_accept(implementation_type & impl,Socket & peer,endpoint_type * peer_endpoint,Handler & handler)394 void async_accept(implementation_type& impl, Socket& peer, 395 endpoint_type* peer_endpoint, Handler& handler) 396 { 397 bool is_continuation = 398 asio_handler_cont_helpers::is_continuation(handler); 399 400 // Allocate and construct an operation to wrap the handler. 401 typedef reactive_socket_accept_op<Socket, Protocol, Handler> op; 402 typename op::ptr p = { asio::detail::addressof(handler), 403 asio_handler_alloc_helpers::allocate( 404 sizeof(op), handler), 0 }; 405 p.p = new (p.v) op(impl.socket_, impl.state_, peer, 406 impl.protocol_, peer_endpoint, handler); 407 408 ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_accept")); 409 410 start_accept_op(impl, p.p, is_continuation, peer.is_open()); 411 p.v = p.p = 0; 412 } 413 414 // Connect the socket to the specified endpoint. connect(implementation_type & impl,const endpoint_type & peer_endpoint,asio::error_code & ec)415 asio::error_code connect(implementation_type& impl, 416 const endpoint_type& peer_endpoint, asio::error_code& ec) 417 { 418 socket_ops::sync_connect(impl.socket_, 419 peer_endpoint.data(), peer_endpoint.size(), ec); 420 return ec; 421 } 422 423 // Start an asynchronous connect. 424 template <typename Handler> async_connect(implementation_type & impl,const endpoint_type & peer_endpoint,Handler & handler)425 void async_connect(implementation_type& impl, 426 const endpoint_type& peer_endpoint, Handler& handler) 427 { 428 bool is_continuation = 429 asio_handler_cont_helpers::is_continuation(handler); 430 431 // Allocate and construct an operation to wrap the handler. 432 typedef reactive_socket_connect_op<Handler> op; 433 typename op::ptr p = { asio::detail::addressof(handler), 434 asio_handler_alloc_helpers::allocate( 435 sizeof(op), handler), 0 }; 436 p.p = new (p.v) op(impl.socket_, handler); 437 438 ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect")); 439 440 start_connect_op(impl, p.p, is_continuation, 441 peer_endpoint.data(), peer_endpoint.size()); 442 p.v = p.p = 0; 443 } 444 }; 445 446 } // namespace detail 447 } // namespace asio 448 449 #include "asio/detail/pop_options.hpp" 450 451 452 #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP 453