• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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