1 // 2 // detail/reactive_socket_recvmsg_op.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 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 BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP 12 #define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP 13 14 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 15 # pragma once 16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 17 18 #include <boost/asio/detail/config.hpp> 19 #include <boost/asio/detail/bind_handler.hpp> 20 #include <boost/asio/detail/buffer_sequence_adapter.hpp> 21 #include <boost/asio/detail/fenced_block.hpp> 22 #include <boost/asio/detail/handler_alloc_helpers.hpp> 23 #include <boost/asio/detail/handler_invoke_helpers.hpp> 24 #include <boost/asio/detail/handler_work.hpp> 25 #include <boost/asio/detail/memory.hpp> 26 #include <boost/asio/detail/reactor_op.hpp> 27 #include <boost/asio/detail/socket_ops.hpp> 28 #include <boost/asio/socket_base.hpp> 29 30 #include <boost/asio/detail/push_options.hpp> 31 32 namespace boost { 33 namespace asio { 34 namespace detail { 35 36 template <typename MutableBufferSequence> 37 class reactive_socket_recvmsg_op_base : public reactor_op 38 { 39 public: reactive_socket_recvmsg_op_base(const boost::system::error_code & success_ec,socket_type socket,const MutableBufferSequence & buffers,socket_base::message_flags in_flags,socket_base::message_flags & out_flags,func_type complete_func)40 reactive_socket_recvmsg_op_base(const boost::system::error_code& success_ec, 41 socket_type socket, const MutableBufferSequence& buffers, 42 socket_base::message_flags in_flags, 43 socket_base::message_flags& out_flags, func_type complete_func) 44 : reactor_op(success_ec, 45 &reactive_socket_recvmsg_op_base::do_perform, complete_func), 46 socket_(socket), 47 buffers_(buffers), 48 in_flags_(in_flags), 49 out_flags_(out_flags) 50 { 51 } 52 do_perform(reactor_op * base)53 static status do_perform(reactor_op* base) 54 { 55 reactive_socket_recvmsg_op_base* o( 56 static_cast<reactive_socket_recvmsg_op_base*>(base)); 57 58 buffer_sequence_adapter<boost::asio::mutable_buffer, 59 MutableBufferSequence> bufs(o->buffers_); 60 61 status result = socket_ops::non_blocking_recvmsg(o->socket_, 62 bufs.buffers(), bufs.count(), 63 o->in_flags_, o->out_flags_, 64 o->ec_, o->bytes_transferred_) ? done : not_done; 65 66 BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg", 67 o->ec_, o->bytes_transferred_)); 68 69 return result; 70 } 71 72 private: 73 socket_type socket_; 74 MutableBufferSequence buffers_; 75 socket_base::message_flags in_flags_; 76 socket_base::message_flags& out_flags_; 77 }; 78 79 template <typename MutableBufferSequence, typename Handler, typename IoExecutor> 80 class reactive_socket_recvmsg_op : 81 public reactive_socket_recvmsg_op_base<MutableBufferSequence> 82 { 83 public: 84 BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op); 85 reactive_socket_recvmsg_op(const boost::system::error_code & success_ec,socket_type socket,const MutableBufferSequence & buffers,socket_base::message_flags in_flags,socket_base::message_flags & out_flags,Handler & handler,const IoExecutor & io_ex)86 reactive_socket_recvmsg_op(const boost::system::error_code& success_ec, 87 socket_type socket, const MutableBufferSequence& buffers, 88 socket_base::message_flags in_flags, 89 socket_base::message_flags& out_flags, Handler& handler, 90 const IoExecutor& io_ex) 91 : reactive_socket_recvmsg_op_base<MutableBufferSequence>( 92 success_ec, socket, buffers, in_flags, out_flags, 93 &reactive_socket_recvmsg_op::do_complete), 94 handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), 95 work_(handler_, io_ex) 96 { 97 } 98 do_complete(void * owner,operation * base,const boost::system::error_code &,std::size_t)99 static void do_complete(void* owner, operation* base, 100 const boost::system::error_code& /*ec*/, 101 std::size_t /*bytes_transferred*/) 102 { 103 // Take ownership of the handler object. 104 reactive_socket_recvmsg_op* o( 105 static_cast<reactive_socket_recvmsg_op*>(base)); 106 ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; 107 108 BOOST_ASIO_HANDLER_COMPLETION((*o)); 109 110 // Take ownership of the operation's outstanding work. 111 handler_work<Handler, IoExecutor> w( 112 BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( 113 o->work_)); 114 115 // Make a copy of the handler so that the memory can be deallocated before 116 // the upcall is made. Even if we're not about to make an upcall, a 117 // sub-object of the handler may be the true owner of the memory associated 118 // with the handler. Consequently, a local copy of the handler is required 119 // to ensure that any owning sub-object remains valid until after we have 120 // deallocated the memory here. 121 detail::binder2<Handler, boost::system::error_code, std::size_t> 122 handler(o->handler_, o->ec_, o->bytes_transferred_); 123 p.h = boost::asio::detail::addressof(handler.handler_); 124 p.reset(); 125 126 // Make the upcall if required. 127 if (owner) 128 { 129 fenced_block b(fenced_block::half); 130 BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); 131 w.complete(handler, handler.handler_); 132 BOOST_ASIO_HANDLER_INVOCATION_END; 133 } 134 } 135 136 private: 137 Handler handler_; 138 handler_work<Handler, IoExecutor> work_; 139 }; 140 141 } // namespace detail 142 } // namespace asio 143 } // namespace boost 144 145 #include <boost/asio/detail/pop_options.hpp> 146 147 #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP 148