1//
2// detail/reactive_socket_accept_op.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_ACCEPT_OP_HPP
12#define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
13
14
15#include "asio/detail/config.hpp"
16#include "asio/detail/addressof.hpp"
17#include "asio/detail/bind_handler.hpp"
18#include "asio/detail/buffer_sequence_adapter.hpp"
19#include "asio/detail/fenced_block.hpp"
20#include "asio/detail/reactor_op.hpp"
21#include "asio/detail/socket_holder.hpp"
22#include "asio/detail/socket_ops.hpp"
23
24#include "asio/detail/push_options.hpp"
25
26namespace asio {
27namespace detail {
28
29template <typename Socket, typename Protocol>
30class reactive_socket_accept_op_base : public reactor_op
31{
32public:
33  reactive_socket_accept_op_base(socket_type socket,
34      socket_ops::state_type state, Socket& peer, const Protocol& protocol,
35      typename Protocol::endpoint* peer_endpoint, func_type complete_func)
36    : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func),
37      socket_(socket),
38      state_(state),
39      peer_(peer),
40      protocol_(protocol),
41      peer_endpoint_(peer_endpoint)
42  {
43  }
44
45  static bool do_perform(reactor_op* base)
46  {
47    reactive_socket_accept_op_base* o(
48        static_cast<reactive_socket_accept_op_base*>(base));
49
50    std::size_t addrlen = o->peer_endpoint_ ? o->peer_endpoint_->capacity() : 0;
51    socket_type new_socket = invalid_socket;
52    bool result = socket_ops::non_blocking_accept(o->socket_,
53          o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0,
54          o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_socket);
55
56    // On success, assign new connection to peer socket object.
57    if (new_socket != invalid_socket)
58    {
59      socket_holder new_socket_holder(new_socket);
60      if (o->peer_endpoint_)
61        o->peer_endpoint_->resize(addrlen);
62      if (!o->peer_.assign(o->protocol_, new_socket, o->ec_))
63        new_socket_holder.release();
64    }
65
66    return result;
67  }
68
69private:
70  socket_type socket_;
71  socket_ops::state_type state_;
72  Socket& peer_;
73  Protocol protocol_;
74  typename Protocol::endpoint* peer_endpoint_;
75};
76
77template <typename Socket, typename Protocol, typename Handler>
78class reactive_socket_accept_op :
79  public reactive_socket_accept_op_base<Socket, Protocol>
80{
81public:
82  ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op);
83
84  reactive_socket_accept_op(socket_type socket,
85      socket_ops::state_type state, Socket& peer, const Protocol& protocol,
86      typename Protocol::endpoint* peer_endpoint, Handler& handler)
87    : reactive_socket_accept_op_base<Socket, Protocol>(socket, state, peer,
88        protocol, peer_endpoint, &reactive_socket_accept_op::do_complete),
89      handler_(ASIO_MOVE_CAST(Handler)(handler))
90  {
91  }
92
93  static void do_complete(io_service_impl* owner, operation* base,
94      const asio::error_code& /*ec*/,
95      std::size_t /*bytes_transferred*/)
96  {
97    // Take ownership of the handler object.
98    reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base));
99    ptr p = { asio::detail::addressof(o->handler_), o, o };
100
101    ASIO_HANDLER_COMPLETION((o));
102
103    // Make a copy of the handler so that the memory can be deallocated before
104    // the upcall is made. Even if we're not about to make an upcall, a
105    // sub-object of the handler may be the true owner of the memory associated
106    // with the handler. Consequently, a local copy of the handler is required
107    // to ensure that any owning sub-object remains valid until after we have
108    // deallocated the memory here.
109    detail::binder1<Handler, asio::error_code>
110      handler(o->handler_, o->ec_);
111    p.h = asio::detail::addressof(handler.handler_);
112    p.reset();
113
114    // Make the upcall if required.
115    if (owner)
116    {
117      fenced_block b(fenced_block::half);
118      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
119      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
120      ASIO_HANDLER_INVOCATION_END;
121    }
122  }
123
124private:
125  Handler handler_;
126};
127
128} // namespace detail
129} // namespace asio
130
131#include "asio/detail/pop_options.hpp"
132
133#endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
134