1//
2// detail/reactive_socket_recv_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_RECV_OP_HPP
12#define ASIO_DETAIL_REACTIVE_SOCKET_RECV_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_ops.hpp"
22
23#include "asio/detail/push_options.hpp"
24
25namespace asio {
26namespace detail {
27
28template <typename MutableBufferSequence>
29class reactive_socket_recv_op_base : public reactor_op
30{
31public:
32  reactive_socket_recv_op_base(socket_type socket,
33      socket_ops::state_type state, const MutableBufferSequence& buffers,
34      socket_base::message_flags flags, func_type complete_func)
35    : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func),
36      socket_(socket),
37      state_(state),
38      buffers_(buffers),
39      flags_(flags)
40  {
41  }
42
43  static bool do_perform(reactor_op* base)
44  {
45    reactive_socket_recv_op_base* o(
46        static_cast<reactive_socket_recv_op_base*>(base));
47
48    buffer_sequence_adapter<asio::mutable_buffer,
49        MutableBufferSequence> bufs(o->buffers_);
50
51    return socket_ops::non_blocking_recv(o->socket_,
52        bufs.buffers(), bufs.count(), o->flags_,
53        (o->state_ & socket_ops::stream_oriented) != 0,
54        o->ec_, o->bytes_transferred_);
55  }
56
57private:
58  socket_type socket_;
59  socket_ops::state_type state_;
60  MutableBufferSequence buffers_;
61  socket_base::message_flags flags_;
62};
63
64template <typename MutableBufferSequence, typename Handler>
65class reactive_socket_recv_op :
66  public reactive_socket_recv_op_base<MutableBufferSequence>
67{
68public:
69  ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op);
70
71  reactive_socket_recv_op(socket_type socket,
72      socket_ops::state_type state, const MutableBufferSequence& buffers,
73      socket_base::message_flags flags, Handler& handler)
74    : reactive_socket_recv_op_base<MutableBufferSequence>(socket, state,
75        buffers, flags, &reactive_socket_recv_op::do_complete),
76      handler_(ASIO_MOVE_CAST(Handler)(handler))
77  {
78  }
79
80  static void do_complete(io_service_impl* owner, operation* base,
81      const asio::error_code& /*ec*/,
82      std::size_t /*bytes_transferred*/)
83  {
84    // Take ownership of the handler object.
85    reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base));
86    ptr p = { asio::detail::addressof(o->handler_), o, o };
87
88    ASIO_HANDLER_COMPLETION((o));
89
90    // Make a copy of the handler so that the memory can be deallocated before
91    // the upcall is made. Even if we're not about to make an upcall, a
92    // sub-object of the handler may be the true owner of the memory associated
93    // with the handler. Consequently, a local copy of the handler is required
94    // to ensure that any owning sub-object remains valid until after we have
95    // deallocated the memory here.
96    detail::binder2<Handler, asio::error_code, std::size_t>
97      handler(o->handler_, o->ec_, o->bytes_transferred_);
98    p.h = asio::detail::addressof(handler.handler_);
99    p.reset();
100
101    // Make the upcall if required.
102    if (owner)
103    {
104      fenced_block b(fenced_block::half);
105      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
106      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
107      ASIO_HANDLER_INVOCATION_END;
108    }
109  }
110
111private:
112  Handler handler_;
113};
114
115} // namespace detail
116} // namespace asio
117
118#include "asio/detail/pop_options.hpp"
119
120#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
121