Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:40

0001 //
0002 // detail/io_uring_socket_accept_op.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_DETAIL_IO_URING_SOCKET_ACCEPT_OP_HPP
0012 #define BOOST_ASIO_DETAIL_IO_URING_SOCKET_ACCEPT_OP_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #if defined(BOOST_ASIO_HAS_IO_URING)
0021 
0022 #include <boost/asio/detail/bind_handler.hpp>
0023 #include <boost/asio/detail/fenced_block.hpp>
0024 #include <boost/asio/detail/handler_alloc_helpers.hpp>
0025 #include <boost/asio/detail/handler_work.hpp>
0026 #include <boost/asio/detail/io_uring_operation.hpp>
0027 #include <boost/asio/detail/memory.hpp>
0028 #include <boost/asio/detail/socket_holder.hpp>
0029 #include <boost/asio/detail/socket_ops.hpp>
0030 
0031 #include <boost/asio/detail/push_options.hpp>
0032 
0033 namespace boost {
0034 namespace asio {
0035 namespace detail {
0036 
0037 template <typename Socket, typename Protocol>
0038 class io_uring_socket_accept_op_base : public io_uring_operation
0039 {
0040 public:
0041   io_uring_socket_accept_op_base(const boost::system::error_code& success_ec,
0042       socket_type socket, socket_ops::state_type state, Socket& peer,
0043       const Protocol& protocol, typename Protocol::endpoint* peer_endpoint,
0044       func_type complete_func)
0045     : io_uring_operation(success_ec,
0046         &io_uring_socket_accept_op_base::do_prepare,
0047         &io_uring_socket_accept_op_base::do_perform, complete_func),
0048       socket_(socket),
0049       state_(state),
0050       peer_(peer),
0051       protocol_(protocol),
0052       peer_endpoint_(peer_endpoint),
0053       addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0)
0054   {
0055   }
0056 
0057   static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe)
0058   {
0059     BOOST_ASIO_ASSUME(base != 0);
0060     io_uring_socket_accept_op_base* o(
0061         static_cast<io_uring_socket_accept_op_base*>(base));
0062 
0063     if ((o->state_ & socket_ops::internal_non_blocking) != 0)
0064     {
0065       ::io_uring_prep_poll_add(sqe, o->socket_, POLLIN);
0066     }
0067     else
0068     {
0069       ::io_uring_prep_accept(sqe, o->socket_,
0070           o->peer_endpoint_ ? o->peer_endpoint_->data() : 0,
0071           o->peer_endpoint_ ? &o->addrlen_ : 0, 0);
0072     }
0073   }
0074 
0075   static bool do_perform(io_uring_operation* base, bool after_completion)
0076   {
0077     BOOST_ASIO_ASSUME(base != 0);
0078     io_uring_socket_accept_op_base* o(
0079         static_cast<io_uring_socket_accept_op_base*>(base));
0080 
0081     if ((o->state_ & socket_ops::internal_non_blocking) != 0)
0082     {
0083       socket_type new_socket = invalid_socket;
0084       std::size_t addrlen = static_cast<std::size_t>(o->addrlen_);
0085       bool result = socket_ops::non_blocking_accept(o->socket_,
0086           o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0,
0087           o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_socket);
0088       o->new_socket_.reset(new_socket);
0089       o->addrlen_ = static_cast<socklen_t>(addrlen);
0090       return result;
0091     }
0092 
0093     if (o->ec_ && o->ec_ == boost::asio::error::would_block)
0094     {
0095       o->state_ |= socket_ops::internal_non_blocking;
0096       return false;
0097     }
0098 
0099     if (after_completion && !o->ec_)
0100       o->new_socket_.reset(static_cast<int>(o->bytes_transferred_));
0101 
0102     return after_completion;
0103   }
0104 
0105   void do_assign()
0106   {
0107     if (new_socket_.get() != invalid_socket)
0108     {
0109       if (peer_endpoint_)
0110         peer_endpoint_->resize(addrlen_);
0111       peer_.assign(protocol_, new_socket_.get(), ec_);
0112       if (!ec_)
0113         new_socket_.release();
0114     }
0115   }
0116 
0117 private:
0118   socket_type socket_;
0119   socket_ops::state_type state_;
0120   socket_holder new_socket_;
0121   Socket& peer_;
0122   Protocol protocol_;
0123   typename Protocol::endpoint* peer_endpoint_;
0124   socklen_t addrlen_;
0125 };
0126 
0127 template <typename Socket, typename Protocol,
0128     typename Handler, typename IoExecutor>
0129 class io_uring_socket_accept_op :
0130   public io_uring_socket_accept_op_base<Socket, Protocol>
0131 {
0132 public:
0133   BOOST_ASIO_DEFINE_HANDLER_PTR(io_uring_socket_accept_op);
0134 
0135   io_uring_socket_accept_op(const boost::system::error_code& success_ec,
0136       socket_type socket, socket_ops::state_type state, Socket& peer,
0137       const Protocol& protocol, typename Protocol::endpoint* peer_endpoint,
0138       Handler& handler, const IoExecutor& io_ex)
0139     : io_uring_socket_accept_op_base<Socket, Protocol>(
0140         success_ec, socket, state, peer, protocol, peer_endpoint,
0141         &io_uring_socket_accept_op::do_complete),
0142       handler_(static_cast<Handler&&>(handler)),
0143       work_(handler_, io_ex)
0144   {
0145   }
0146 
0147   static void do_complete(void* owner, operation* base,
0148       const boost::system::error_code& /*ec*/,
0149       std::size_t /*bytes_transferred*/)
0150   {
0151     // Take ownership of the handler object.
0152     BOOST_ASIO_ASSUME(base != 0);
0153     io_uring_socket_accept_op* o(static_cast<io_uring_socket_accept_op*>(base));
0154     ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
0155 
0156     // On success, assign new connection to peer socket object.
0157     if (owner)
0158       o->do_assign();
0159 
0160     BOOST_ASIO_HANDLER_COMPLETION((*o));
0161 
0162     // Take ownership of the operation's outstanding work.
0163     handler_work<Handler, IoExecutor> w(
0164         static_cast<handler_work<Handler, IoExecutor>&&>(
0165           o->work_));
0166 
0167     BOOST_ASIO_ERROR_LOCATION(o->ec_);
0168 
0169     // Make a copy of the handler so that the memory can be deallocated before
0170     // the upcall is made. Even if we're not about to make an upcall, a
0171     // sub-object of the handler may be the true owner of the memory associated
0172     // with the handler. Consequently, a local copy of the handler is required
0173     // to ensure that any owning sub-object remains valid until after we have
0174     // deallocated the memory here.
0175     detail::binder1<Handler, boost::system::error_code>
0176       handler(o->handler_, o->ec_);
0177     p.h = boost::asio::detail::addressof(handler.handler_);
0178     p.reset();
0179 
0180     // Make the upcall if required.
0181     if (owner)
0182     {
0183       fenced_block b(fenced_block::half);
0184       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
0185       w.complete(handler, handler.handler_);
0186       BOOST_ASIO_HANDLER_INVOCATION_END;
0187     }
0188   }
0189 
0190 private:
0191   Handler handler_;
0192   handler_work<Handler, IoExecutor> work_;
0193 };
0194 
0195 template <typename Protocol, typename PeerIoExecutor,
0196     typename Handler, typename IoExecutor>
0197 class io_uring_socket_move_accept_op :
0198   private Protocol::socket::template rebind_executor<PeerIoExecutor>::other,
0199   public io_uring_socket_accept_op_base<
0200     typename Protocol::socket::template rebind_executor<PeerIoExecutor>::other,
0201     Protocol>
0202 {
0203 public:
0204   BOOST_ASIO_DEFINE_HANDLER_PTR(io_uring_socket_move_accept_op);
0205 
0206   io_uring_socket_move_accept_op(const boost::system::error_code& success_ec,
0207       const PeerIoExecutor& peer_io_ex, socket_type socket,
0208       socket_ops::state_type state, const Protocol& protocol,
0209       typename Protocol::endpoint* peer_endpoint, Handler& handler,
0210       const IoExecutor& io_ex)
0211     : peer_socket_type(peer_io_ex),
0212       io_uring_socket_accept_op_base<peer_socket_type, Protocol>(
0213         success_ec, socket, state, *this, protocol, peer_endpoint,
0214         &io_uring_socket_move_accept_op::do_complete),
0215       handler_(static_cast<Handler&&>(handler)),
0216       work_(handler_, io_ex)
0217   {
0218   }
0219 
0220   static void do_complete(void* owner, operation* base,
0221       const boost::system::error_code& /*ec*/,
0222       std::size_t /*bytes_transferred*/)
0223   {
0224     // Take ownership of the handler object.
0225     BOOST_ASIO_ASSUME(base != 0);
0226     io_uring_socket_move_accept_op* o(
0227         static_cast<io_uring_socket_move_accept_op*>(base));
0228     ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
0229 
0230     // On success, assign new connection to peer socket object.
0231     if (owner)
0232       o->do_assign();
0233 
0234     BOOST_ASIO_HANDLER_COMPLETION((*o));
0235 
0236     // Take ownership of the operation's outstanding work.
0237     handler_work<Handler, IoExecutor> w(
0238         static_cast<handler_work<Handler, IoExecutor>&&>(
0239           o->work_));
0240 
0241     BOOST_ASIO_ERROR_LOCATION(o->ec_);
0242 
0243     // Make a copy of the handler so that the memory can be deallocated before
0244     // the upcall is made. Even if we're not about to make an upcall, a
0245     // sub-object of the handler may be the true owner of the memory associated
0246     // with the handler. Consequently, a local copy of the handler is required
0247     // to ensure that any owning sub-object remains valid until after we have
0248     // deallocated the memory here.
0249     detail::move_binder2<Handler,
0250       boost::system::error_code, peer_socket_type>
0251         handler(0, static_cast<Handler&&>(o->handler_), o->ec_,
0252           static_cast<peer_socket_type&&>(*o));
0253     p.h = boost::asio::detail::addressof(handler.handler_);
0254     p.reset();
0255 
0256     // Make the upcall if required.
0257     if (owner)
0258     {
0259       fenced_block b(fenced_block::half);
0260       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
0261       w.complete(handler, handler.handler_);
0262       BOOST_ASIO_HANDLER_INVOCATION_END;
0263     }
0264   }
0265 
0266 private:
0267   typedef typename Protocol::socket::template
0268     rebind_executor<PeerIoExecutor>::other peer_socket_type;
0269 
0270   Handler handler_;
0271   handler_work<Handler, IoExecutor> work_;
0272 };
0273 
0274 } // namespace detail
0275 } // namespace asio
0276 } // namespace boost
0277 
0278 #include <boost/asio/detail/pop_options.hpp>
0279 
0280 #endif // defined(BOOST_ASIO_HAS_IO_URING)
0281 
0282 #endif // BOOST_ASIO_DETAIL_IO_URING_SOCKET_ACCEPT_OP_HPP