1// 2// detail/reactive_socket_service_base.ipp 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_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP 12#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP 13 14 15#include "asio/detail/config.hpp" 16 17 18#include "asio/detail/reactive_socket_service_base.hpp" 19 20#include "asio/detail/push_options.hpp" 21 22namespace asio { 23namespace detail { 24 25reactive_socket_service_base::reactive_socket_service_base( 26 asio::io_service& io_service) 27 : reactor_(use_service<reactor>(io_service)) 28{ 29 reactor_.init_task(); 30} 31 32void reactive_socket_service_base::shutdown_service() 33{ 34} 35 36void reactive_socket_service_base::construct( 37 reactive_socket_service_base::base_implementation_type& impl) 38{ 39 impl.socket_ = invalid_socket; 40 impl.state_ = 0; 41} 42 43void reactive_socket_service_base::base_move_construct( 44 reactive_socket_service_base::base_implementation_type& impl, 45 reactive_socket_service_base::base_implementation_type& other_impl) 46{ 47 impl.socket_ = other_impl.socket_; 48 other_impl.socket_ = invalid_socket; 49 50 impl.state_ = other_impl.state_; 51 other_impl.state_ = 0; 52 53 reactor_.move_descriptor(impl.socket_, 54 impl.reactor_data_, other_impl.reactor_data_); 55} 56 57void reactive_socket_service_base::base_move_assign( 58 reactive_socket_service_base::base_implementation_type& impl, 59 reactive_socket_service_base& other_service, 60 reactive_socket_service_base::base_implementation_type& other_impl) 61{ 62 destroy(impl); 63 64 impl.socket_ = other_impl.socket_; 65 other_impl.socket_ = invalid_socket; 66 67 impl.state_ = other_impl.state_; 68 other_impl.state_ = 0; 69 70 other_service.reactor_.move_descriptor(impl.socket_, 71 impl.reactor_data_, other_impl.reactor_data_); 72} 73 74void reactive_socket_service_base::destroy( 75 reactive_socket_service_base::base_implementation_type& impl) 76{ 77 if (impl.socket_ != invalid_socket) 78 { 79 ASIO_HANDLER_OPERATION(("socket", &impl, "close")); 80 81 reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, 82 (impl.state_ & socket_ops::possible_dup) == 0); 83 84 asio::error_code ignored_ec; 85 socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); 86 } 87} 88 89asio::error_code reactive_socket_service_base::close( 90 reactive_socket_service_base::base_implementation_type& impl, 91 asio::error_code& ec) 92{ 93 if (is_open(impl)) 94 { 95 ASIO_HANDLER_OPERATION(("socket", &impl, "close")); 96 97 reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, 98 (impl.state_ & socket_ops::possible_dup) == 0); 99 } 100 101 socket_ops::close(impl.socket_, impl.state_, false, ec); 102 103 // The descriptor is closed by the OS even if close() returns an error. 104 // 105 // (Actually, POSIX says the state of the descriptor is unspecified. On 106 // Linux the descriptor is apparently closed anyway; e.g. see 107 // http://lkml.org/lkml/2005/9/10/129 108 // We'll just have to assume that other OSes follow the same behaviour. The 109 // known exception is when Windows's closesocket() function fails with 110 // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close(). 111 construct(impl); 112 113 return ec; 114} 115 116asio::error_code reactive_socket_service_base::cancel( 117 reactive_socket_service_base::base_implementation_type& impl, 118 asio::error_code& ec) 119{ 120 if (!is_open(impl)) 121 { 122 ec = asio::error::bad_descriptor; 123 return ec; 124 } 125 126 ASIO_HANDLER_OPERATION(("socket", &impl, "cancel")); 127 128 reactor_.cancel_ops(impl.socket_, impl.reactor_data_); 129 ec = asio::error_code(); 130 return ec; 131} 132 133asio::error_code reactive_socket_service_base::do_open( 134 reactive_socket_service_base::base_implementation_type& impl, 135 int af, int type, int protocol, asio::error_code& ec) 136{ 137 if (is_open(impl)) 138 { 139 ec = asio::error::already_open; 140 return ec; 141 } 142 143 socket_holder sock(socket_ops::socket(af, type, protocol, ec)); 144 if (sock.get() == invalid_socket) 145 return ec; 146 147 if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) 148 { 149 ec = asio::error_code(err, 150 asio::error::get_system_category()); 151 return ec; 152 } 153 154 impl.socket_ = sock.release(); 155 switch (type) 156 { 157 case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; 158 case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; 159 default: impl.state_ = 0; break; 160 } 161 ec = asio::error_code(); 162 return ec; 163} 164 165asio::error_code reactive_socket_service_base::do_assign( 166 reactive_socket_service_base::base_implementation_type& impl, int type, 167 const reactive_socket_service_base::native_handle_type& native_socket, 168 asio::error_code& ec) 169{ 170 if (is_open(impl)) 171 { 172 ec = asio::error::already_open; 173 return ec; 174 } 175 176 if (int err = reactor_.register_descriptor( 177 native_socket, impl.reactor_data_)) 178 { 179 ec = asio::error_code(err, 180 asio::error::get_system_category()); 181 return ec; 182 } 183 184 impl.socket_ = native_socket; 185 switch (type) 186 { 187 case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; 188 case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; 189 default: impl.state_ = 0; break; 190 } 191 impl.state_ |= socket_ops::possible_dup; 192 ec = asio::error_code(); 193 return ec; 194} 195 196void reactive_socket_service_base::start_op( 197 reactive_socket_service_base::base_implementation_type& impl, 198 int op_type, reactor_op* op, bool is_continuation, 199 bool is_non_blocking, bool noop) 200{ 201 if (!noop) 202 { 203 if ((impl.state_ & socket_ops::non_blocking) 204 || socket_ops::set_internal_non_blocking( 205 impl.socket_, impl.state_, true, op->ec_)) 206 { 207 reactor_.start_op(op_type, impl.socket_, 208 impl.reactor_data_, op, is_continuation, is_non_blocking); 209 return; 210 } 211 } 212 213 reactor_.post_immediate_completion(op, is_continuation); 214} 215 216void reactive_socket_service_base::start_accept_op( 217 reactive_socket_service_base::base_implementation_type& impl, 218 reactor_op* op, bool is_continuation, bool peer_is_open) 219{ 220 if (!peer_is_open) 221 start_op(impl, reactor::read_op, op, true, is_continuation, false); 222 else 223 { 224 op->ec_ = asio::error::already_open; 225 reactor_.post_immediate_completion(op, is_continuation); 226 } 227} 228 229void reactive_socket_service_base::start_connect_op( 230 reactive_socket_service_base::base_implementation_type& impl, 231 reactor_op* op, bool is_continuation, 232 const socket_addr_type* addr, size_t addrlen) 233{ 234 if ((impl.state_ & socket_ops::non_blocking) 235 || socket_ops::set_internal_non_blocking( 236 impl.socket_, impl.state_, true, op->ec_)) 237 { 238 if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) 239 { 240 if (op->ec_ == asio::error::in_progress 241 || op->ec_ == asio::error::would_block) 242 { 243 op->ec_ = asio::error_code(); 244 reactor_.start_op(reactor::connect_op, impl.socket_, 245 impl.reactor_data_, op, is_continuation, false); 246 return; 247 } 248 } 249 } 250 251 reactor_.post_immediate_completion(op, is_continuation); 252} 253 254} // namespace detail 255} // namespace asio 256 257#include "asio/detail/pop_options.hpp" 258 259 // && !defined(ASIO_WINDOWS_RUNTIME) 260 261#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP 262