1 // 2 // detail/reactive_socket_service_base.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_BASE_HPP 12 #define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_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/reactive_null_buffers_op.hpp" 25 #include "asio/detail/reactive_socket_recv_op.hpp" 26 #include "asio/detail/reactive_socket_recvmsg_op.hpp" 27 #include "asio/detail/reactive_socket_send_op.hpp" 28 #include "asio/detail/reactor.hpp" 29 #include "asio/detail/reactor_op.hpp" 30 #include "asio/detail/socket_holder.hpp" 31 #include "asio/detail/socket_ops.hpp" 32 #include "asio/detail/socket_types.hpp" 33 34 #include "asio/detail/push_options.hpp" 35 36 namespace asio { 37 namespace detail { 38 39 class reactive_socket_service_base 40 { 41 public: 42 // The native type of a socket. 43 typedef socket_type native_handle_type; 44 45 // The implementation type of the socket. 46 struct base_implementation_type 47 { 48 // The native socket representation. 49 socket_type socket_; 50 51 // The current state of the socket. 52 socket_ops::state_type state_; 53 54 // Per-descriptor data used by the reactor. 55 reactor::per_descriptor_data reactor_data_; 56 }; 57 58 // Constructor. 59 ASIO_DECL reactive_socket_service_base( 60 asio::io_service& io_service); 61 62 // Destroy all user-defined handler objects owned by the service. 63 ASIO_DECL void shutdown_service(); 64 65 // Construct a new socket implementation. 66 ASIO_DECL void construct(base_implementation_type& impl); 67 68 // Move-construct a new socket implementation. 69 ASIO_DECL void base_move_construct(base_implementation_type& impl, 70 base_implementation_type& other_impl); 71 72 // Move-assign from another socket implementation. 73 ASIO_DECL void base_move_assign(base_implementation_type& impl, 74 reactive_socket_service_base& other_service, 75 base_implementation_type& other_impl); 76 77 // Destroy a socket implementation. 78 ASIO_DECL void destroy(base_implementation_type& impl); 79 80 // Determine whether the socket is open. is_open(const base_implementation_type & impl) const81 bool is_open(const base_implementation_type& impl) const 82 { 83 return impl.socket_ != invalid_socket; 84 } 85 86 // Destroy a socket implementation. 87 ASIO_DECL asio::error_code close( 88 base_implementation_type& impl, asio::error_code& ec); 89 90 // Get the native socket representation. native_handle(base_implementation_type & impl)91 native_handle_type native_handle(base_implementation_type& impl) 92 { 93 return impl.socket_; 94 } 95 96 // Cancel all operations associated with the socket. 97 ASIO_DECL asio::error_code cancel( 98 base_implementation_type& impl, asio::error_code& ec); 99 100 // Determine whether the socket is at the out-of-band data mark. at_mark(const base_implementation_type & impl,asio::error_code & ec) const101 bool at_mark(const base_implementation_type& impl, 102 asio::error_code& ec) const 103 { 104 return socket_ops::sockatmark(impl.socket_, ec); 105 } 106 107 // Determine the number of bytes available for reading. available(const base_implementation_type & impl,asio::error_code & ec) const108 std::size_t available(const base_implementation_type& impl, 109 asio::error_code& ec) const 110 { 111 return socket_ops::available(impl.socket_, ec); 112 } 113 114 // Place the socket into the state where it will listen for new connections. listen(base_implementation_type & impl,int backlog,asio::error_code & ec)115 asio::error_code listen(base_implementation_type& impl, 116 int backlog, asio::error_code& ec) 117 { 118 socket_ops::listen(impl.socket_, backlog, ec); 119 return ec; 120 } 121 122 // Perform an IO control command on the socket. 123 template <typename IO_Control_Command> io_control(base_implementation_type & impl,IO_Control_Command & command,asio::error_code & ec)124 asio::error_code io_control(base_implementation_type& impl, 125 IO_Control_Command& command, asio::error_code& ec) 126 { 127 socket_ops::ioctl(impl.socket_, impl.state_, command.name(), 128 static_cast<ioctl_arg_type*>(command.data()), ec); 129 return ec; 130 } 131 132 // Gets the non-blocking mode of the socket. non_blocking(const base_implementation_type & impl) const133 bool non_blocking(const base_implementation_type& impl) const 134 { 135 return (impl.state_ & socket_ops::user_set_non_blocking) != 0; 136 } 137 138 // Sets the non-blocking mode of the socket. non_blocking(base_implementation_type & impl,bool mode,asio::error_code & ec)139 asio::error_code non_blocking(base_implementation_type& impl, 140 bool mode, asio::error_code& ec) 141 { 142 socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec); 143 return ec; 144 } 145 146 // Gets the non-blocking mode of the native socket implementation. native_non_blocking(const base_implementation_type & impl) const147 bool native_non_blocking(const base_implementation_type& impl) const 148 { 149 return (impl.state_ & socket_ops::internal_non_blocking) != 0; 150 } 151 152 // Sets the non-blocking mode of the native socket implementation. native_non_blocking(base_implementation_type & impl,bool mode,asio::error_code & ec)153 asio::error_code native_non_blocking(base_implementation_type& impl, 154 bool mode, asio::error_code& ec) 155 { 156 socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec); 157 return ec; 158 } 159 160 // Disable sends or receives on the socket. shutdown(base_implementation_type & impl,socket_base::shutdown_type what,asio::error_code & ec)161 asio::error_code shutdown(base_implementation_type& impl, 162 socket_base::shutdown_type what, asio::error_code& ec) 163 { 164 socket_ops::shutdown(impl.socket_, what, ec); 165 return ec; 166 } 167 168 // Send the given data to the peer. 169 template <typename ConstBufferSequence> send(base_implementation_type & impl,const ConstBufferSequence & buffers,socket_base::message_flags flags,asio::error_code & ec)170 size_t send(base_implementation_type& impl, 171 const ConstBufferSequence& buffers, 172 socket_base::message_flags flags, asio::error_code& ec) 173 { 174 buffer_sequence_adapter<asio::const_buffer, 175 ConstBufferSequence> bufs(buffers); 176 177 return socket_ops::sync_send(impl.socket_, impl.state_, 178 bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); 179 } 180 181 // Wait until data can be sent without blocking. send(base_implementation_type & impl,const null_buffers &,socket_base::message_flags,asio::error_code & ec)182 size_t send(base_implementation_type& impl, const null_buffers&, 183 socket_base::message_flags, asio::error_code& ec) 184 { 185 // Wait for socket to become ready. 186 socket_ops::poll_write(impl.socket_, impl.state_, ec); 187 188 return 0; 189 } 190 191 // Start an asynchronous send. The data being sent must be valid for the 192 // lifetime of the asynchronous operation. 193 template <typename ConstBufferSequence, typename Handler> async_send(base_implementation_type & impl,const ConstBufferSequence & buffers,socket_base::message_flags flags,Handler & handler)194 void async_send(base_implementation_type& impl, 195 const ConstBufferSequence& buffers, 196 socket_base::message_flags flags, Handler& handler) 197 { 198 bool is_continuation = 199 asio_handler_cont_helpers::is_continuation(handler); 200 201 // Allocate and construct an operation to wrap the handler. 202 typedef reactive_socket_send_op<ConstBufferSequence, Handler> op; 203 typename op::ptr p = { asio::detail::addressof(handler), 204 asio_handler_alloc_helpers::allocate( 205 sizeof(op), handler), 0 }; 206 p.p = new (p.v) op(impl.socket_, buffers, flags, handler); 207 208 ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send")); 209 210 start_op(impl, reactor::write_op, p.p, is_continuation, true, 211 ((impl.state_ & socket_ops::stream_oriented) 212 && buffer_sequence_adapter<asio::const_buffer, 213 ConstBufferSequence>::all_empty(buffers))); 214 p.v = p.p = 0; 215 } 216 217 // Start an asynchronous wait until data can be sent without blocking. 218 template <typename Handler> async_send(base_implementation_type & impl,const null_buffers &,socket_base::message_flags,Handler & handler)219 void async_send(base_implementation_type& impl, const null_buffers&, 220 socket_base::message_flags, Handler& handler) 221 { 222 bool is_continuation = 223 asio_handler_cont_helpers::is_continuation(handler); 224 225 // Allocate and construct an operation to wrap the handler. 226 typedef reactive_null_buffers_op<Handler> op; 227 typename op::ptr p = { asio::detail::addressof(handler), 228 asio_handler_alloc_helpers::allocate( 229 sizeof(op), handler), 0 }; 230 p.p = new (p.v) op(handler); 231 232 ASIO_HANDLER_CREATION((p.p, "socket", 233 &impl, "async_send(null_buffers)")); 234 235 start_op(impl, reactor::write_op, p.p, is_continuation, false, false); 236 p.v = p.p = 0; 237 } 238 239 // Receive some data from the peer. Returns the number of bytes received. 240 template <typename MutableBufferSequence> receive(base_implementation_type & impl,const MutableBufferSequence & buffers,socket_base::message_flags flags,asio::error_code & ec)241 size_t receive(base_implementation_type& impl, 242 const MutableBufferSequence& buffers, 243 socket_base::message_flags flags, asio::error_code& ec) 244 { 245 buffer_sequence_adapter<asio::mutable_buffer, 246 MutableBufferSequence> bufs(buffers); 247 248 return socket_ops::sync_recv(impl.socket_, impl.state_, 249 bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); 250 } 251 252 // Wait until data can be received without blocking. receive(base_implementation_type & impl,const null_buffers &,socket_base::message_flags,asio::error_code & ec)253 size_t receive(base_implementation_type& impl, const null_buffers&, 254 socket_base::message_flags, asio::error_code& ec) 255 { 256 // Wait for socket to become ready. 257 socket_ops::poll_read(impl.socket_, impl.state_, ec); 258 259 return 0; 260 } 261 262 // Start an asynchronous receive. The buffer for the data being received 263 // must be valid for the lifetime of the asynchronous operation. 264 template <typename MutableBufferSequence, typename Handler> async_receive(base_implementation_type & impl,const MutableBufferSequence & buffers,socket_base::message_flags flags,Handler & handler)265 void async_receive(base_implementation_type& impl, 266 const MutableBufferSequence& buffers, 267 socket_base::message_flags flags, Handler& handler) 268 { 269 bool is_continuation = 270 asio_handler_cont_helpers::is_continuation(handler); 271 272 // Allocate and construct an operation to wrap the handler. 273 typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op; 274 typename op::ptr p = { asio::detail::addressof(handler), 275 asio_handler_alloc_helpers::allocate( 276 sizeof(op), handler), 0 }; 277 p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); 278 279 ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive")); 280 281 start_op(impl, 282 (flags & socket_base::message_out_of_band) 283 ? reactor::except_op : reactor::read_op, 284 p.p, is_continuation, 285 (flags & socket_base::message_out_of_band) == 0, 286 ((impl.state_ & socket_ops::stream_oriented) 287 && buffer_sequence_adapter<asio::mutable_buffer, 288 MutableBufferSequence>::all_empty(buffers))); 289 p.v = p.p = 0; 290 } 291 292 // Wait until data can be received without blocking. 293 template <typename Handler> async_receive(base_implementation_type & impl,const null_buffers &,socket_base::message_flags flags,Handler & handler)294 void async_receive(base_implementation_type& impl, const null_buffers&, 295 socket_base::message_flags flags, Handler& handler) 296 { 297 bool is_continuation = 298 asio_handler_cont_helpers::is_continuation(handler); 299 300 // Allocate and construct an operation to wrap the handler. 301 typedef reactive_null_buffers_op<Handler> op; 302 typename op::ptr p = { asio::detail::addressof(handler), 303 asio_handler_alloc_helpers::allocate( 304 sizeof(op), handler), 0 }; 305 p.p = new (p.v) op(handler); 306 307 ASIO_HANDLER_CREATION((p.p, "socket", 308 &impl, "async_receive(null_buffers)")); 309 310 start_op(impl, 311 (flags & socket_base::message_out_of_band) 312 ? reactor::except_op : reactor::read_op, 313 p.p, is_continuation, false, false); 314 p.v = p.p = 0; 315 } 316 317 // Receive some data with associated flags. Returns the number of bytes 318 // received. 319 template <typename MutableBufferSequence> receive_with_flags(base_implementation_type & impl,const MutableBufferSequence & buffers,socket_base::message_flags in_flags,socket_base::message_flags & out_flags,asio::error_code & ec)320 size_t receive_with_flags(base_implementation_type& impl, 321 const MutableBufferSequence& buffers, 322 socket_base::message_flags in_flags, 323 socket_base::message_flags& out_flags, asio::error_code& ec) 324 { 325 buffer_sequence_adapter<asio::mutable_buffer, 326 MutableBufferSequence> bufs(buffers); 327 328 return socket_ops::sync_recvmsg(impl.socket_, impl.state_, 329 bufs.buffers(), bufs.count(), in_flags, out_flags, ec); 330 } 331 332 // Wait until data can be received without blocking. receive_with_flags(base_implementation_type & impl,const null_buffers &,socket_base::message_flags,socket_base::message_flags & out_flags,asio::error_code & ec)333 size_t receive_with_flags(base_implementation_type& impl, 334 const null_buffers&, socket_base::message_flags, 335 socket_base::message_flags& out_flags, asio::error_code& ec) 336 { 337 // Wait for socket to become ready. 338 socket_ops::poll_read(impl.socket_, impl.state_, ec); 339 340 // Clear out_flags, since we cannot give it any other sensible value when 341 // performing a null_buffers operation. 342 out_flags = 0; 343 344 return 0; 345 } 346 347 // Start an asynchronous receive. The buffer for the data being received 348 // must be valid for the lifetime of the asynchronous operation. 349 template <typename MutableBufferSequence, typename Handler> async_receive_with_flags(base_implementation_type & impl,const MutableBufferSequence & buffers,socket_base::message_flags in_flags,socket_base::message_flags & out_flags,Handler & handler)350 void async_receive_with_flags(base_implementation_type& impl, 351 const MutableBufferSequence& buffers, socket_base::message_flags in_flags, 352 socket_base::message_flags& out_flags, Handler& handler) 353 { 354 bool is_continuation = 355 asio_handler_cont_helpers::is_continuation(handler); 356 357 // Allocate and construct an operation to wrap the handler. 358 typedef reactive_socket_recvmsg_op<MutableBufferSequence, Handler> op; 359 typename op::ptr p = { asio::detail::addressof(handler), 360 asio_handler_alloc_helpers::allocate( 361 sizeof(op), handler), 0 }; 362 p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler); 363 364 ASIO_HANDLER_CREATION((p.p, "socket", 365 &impl, "async_receive_with_flags")); 366 367 start_op(impl, 368 (in_flags & socket_base::message_out_of_band) 369 ? reactor::except_op : reactor::read_op, 370 p.p, is_continuation, 371 (in_flags & socket_base::message_out_of_band) == 0, false); 372 p.v = p.p = 0; 373 } 374 375 // Wait until data can be received without blocking. 376 template <typename Handler> async_receive_with_flags(base_implementation_type & impl,const null_buffers &,socket_base::message_flags in_flags,socket_base::message_flags & out_flags,Handler & handler)377 void async_receive_with_flags(base_implementation_type& impl, 378 const null_buffers&, socket_base::message_flags in_flags, 379 socket_base::message_flags& out_flags, Handler& handler) 380 { 381 bool is_continuation = 382 asio_handler_cont_helpers::is_continuation(handler); 383 384 // Allocate and construct an operation to wrap the handler. 385 typedef reactive_null_buffers_op<Handler> op; 386 typename op::ptr p = { asio::detail::addressof(handler), 387 asio_handler_alloc_helpers::allocate( 388 sizeof(op), handler), 0 }; 389 p.p = new (p.v) op(handler); 390 391 ASIO_HANDLER_CREATION((p.p, "socket", &impl, 392 "async_receive_with_flags(null_buffers)")); 393 394 // Clear out_flags, since we cannot give it any other sensible value when 395 // performing a null_buffers operation. 396 out_flags = 0; 397 398 start_op(impl, 399 (in_flags & socket_base::message_out_of_band) 400 ? reactor::except_op : reactor::read_op, 401 p.p, is_continuation, false, false); 402 p.v = p.p = 0; 403 } 404 405 protected: 406 // Open a new socket implementation. 407 ASIO_DECL asio::error_code do_open( 408 base_implementation_type& impl, int af, 409 int type, int protocol, asio::error_code& ec); 410 411 // Assign a native socket to a socket implementation. 412 ASIO_DECL asio::error_code do_assign( 413 base_implementation_type& impl, int type, 414 const native_handle_type& native_socket, asio::error_code& ec); 415 416 // Start the asynchronous read or write operation. 417 ASIO_DECL void start_op(base_implementation_type& impl, int op_type, 418 reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); 419 420 // Start the asynchronous accept operation. 421 ASIO_DECL void start_accept_op(base_implementation_type& impl, 422 reactor_op* op, bool is_continuation, bool peer_is_open); 423 424 // Start the asynchronous connect operation. 425 ASIO_DECL void start_connect_op(base_implementation_type& impl, 426 reactor_op* op, bool is_continuation, 427 const socket_addr_type* addr, size_t addrlen); 428 429 // The selector that performs event demultiplexing for the service. 430 reactor& reactor_; 431 }; 432 433 } // namespace detail 434 } // namespace asio 435 436 #include "asio/detail/pop_options.hpp" 437 438 # include "asio/detail/impl/reactive_socket_service_base.ipp" 439 440 // && !defined(ASIO_WINDOWS_RUNTIME) 441 442 #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP 443