Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //
0002 // detail/io_uring_socket_service.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_SERVICE_HPP
0012 #define BOOST_ASIO_DETAIL_IO_URING_SOCKET_SERVICE_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/buffer.hpp>
0023 #include <boost/asio/error.hpp>
0024 #include <boost/asio/execution_context.hpp>
0025 #include <boost/asio/socket_base.hpp>
0026 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
0027 #include <boost/asio/detail/memory.hpp>
0028 #include <boost/asio/detail/noncopyable.hpp>
0029 #include <boost/asio/detail/io_uring_null_buffers_op.hpp>
0030 #include <boost/asio/detail/io_uring_service.hpp>
0031 #include <boost/asio/detail/io_uring_socket_accept_op.hpp>
0032 #include <boost/asio/detail/io_uring_socket_connect_op.hpp>
0033 #include <boost/asio/detail/io_uring_socket_recvfrom_op.hpp>
0034 #include <boost/asio/detail/io_uring_socket_sendto_op.hpp>
0035 #include <boost/asio/detail/io_uring_socket_service_base.hpp>
0036 #include <boost/asio/detail/socket_holder.hpp>
0037 #include <boost/asio/detail/socket_ops.hpp>
0038 #include <boost/asio/detail/socket_types.hpp>
0039 
0040 #include <boost/asio/detail/push_options.hpp>
0041 
0042 namespace boost {
0043 namespace asio {
0044 namespace detail {
0045 
0046 template <typename Protocol>
0047 class io_uring_socket_service :
0048   public execution_context_service_base<io_uring_socket_service<Protocol>>,
0049   public io_uring_socket_service_base
0050 {
0051 public:
0052   // The protocol type.
0053   typedef Protocol protocol_type;
0054 
0055   // The endpoint type.
0056   typedef typename Protocol::endpoint endpoint_type;
0057 
0058   // The native type of a socket.
0059   typedef socket_type native_handle_type;
0060 
0061   // The implementation type of the socket.
0062   struct implementation_type :
0063     io_uring_socket_service_base::base_implementation_type
0064   {
0065     // Default constructor.
0066     implementation_type()
0067       : protocol_(endpoint_type().protocol())
0068     {
0069     }
0070 
0071     // The protocol associated with the socket.
0072     protocol_type protocol_;
0073   };
0074 
0075   // Constructor.
0076   io_uring_socket_service(execution_context& context)
0077     : execution_context_service_base<
0078         io_uring_socket_service<Protocol>>(context),
0079       io_uring_socket_service_base(context)
0080   {
0081   }
0082 
0083   // Destroy all user-defined handler objects owned by the service.
0084   void shutdown()
0085   {
0086     this->base_shutdown();
0087   }
0088 
0089   // Move-construct a new socket implementation.
0090   void move_construct(implementation_type& impl,
0091       implementation_type& other_impl) noexcept
0092   {
0093     this->base_move_construct(impl, other_impl);
0094 
0095     impl.protocol_ = other_impl.protocol_;
0096     other_impl.protocol_ = endpoint_type().protocol();
0097   }
0098 
0099   // Move-assign from another socket implementation.
0100   void move_assign(implementation_type& impl,
0101       io_uring_socket_service_base& other_service,
0102       implementation_type& other_impl)
0103   {
0104     this->base_move_assign(impl, other_service, other_impl);
0105 
0106     impl.protocol_ = other_impl.protocol_;
0107     other_impl.protocol_ = endpoint_type().protocol();
0108   }
0109 
0110   // Move-construct a new socket implementation from another protocol type.
0111   template <typename Protocol1>
0112   void converting_move_construct(implementation_type& impl,
0113       io_uring_socket_service<Protocol1>&,
0114       typename io_uring_socket_service<
0115         Protocol1>::implementation_type& other_impl)
0116   {
0117     this->base_move_construct(impl, other_impl);
0118 
0119     impl.protocol_ = protocol_type(other_impl.protocol_);
0120     other_impl.protocol_ = typename Protocol1::endpoint().protocol();
0121   }
0122 
0123   // Open a new socket implementation.
0124   boost::system::error_code open(implementation_type& impl,
0125       const protocol_type& protocol, boost::system::error_code& ec)
0126   {
0127     if (!do_open(impl, protocol.family(),
0128           protocol.type(), protocol.protocol(), ec))
0129       impl.protocol_ = protocol;
0130     BOOST_ASIO_ERROR_LOCATION(ec);
0131     return ec;
0132   }
0133 
0134   // Assign a native socket to a socket implementation.
0135   boost::system::error_code assign(implementation_type& impl,
0136       const protocol_type& protocol, const native_handle_type& native_socket,
0137       boost::system::error_code& ec)
0138   {
0139     if (!do_assign(impl, protocol.type(), native_socket, ec))
0140       impl.protocol_ = protocol;
0141     BOOST_ASIO_ERROR_LOCATION(ec);
0142     return ec;
0143   }
0144 
0145   // Get the native socket representation.
0146   native_handle_type native_handle(implementation_type& impl)
0147   {
0148     return impl.socket_;
0149   }
0150 
0151   // Bind the socket to the specified local endpoint.
0152   boost::system::error_code bind(implementation_type& impl,
0153       const endpoint_type& endpoint, boost::system::error_code& ec)
0154   {
0155     socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
0156     BOOST_ASIO_ERROR_LOCATION(ec);
0157     return ec;
0158   }
0159 
0160   // Set a socket option.
0161   template <typename Option>
0162   boost::system::error_code set_option(implementation_type& impl,
0163       const Option& option, boost::system::error_code& ec)
0164   {
0165     socket_ops::setsockopt(impl.socket_, impl.state_,
0166         option.level(impl.protocol_), option.name(impl.protocol_),
0167         option.data(impl.protocol_), option.size(impl.protocol_), ec);
0168     BOOST_ASIO_ERROR_LOCATION(ec);
0169     return ec;
0170   }
0171 
0172   // Set a socket option.
0173   template <typename Option>
0174   boost::system::error_code get_option(const implementation_type& impl,
0175       Option& option, boost::system::error_code& ec) const
0176   {
0177     std::size_t size = option.size(impl.protocol_);
0178     socket_ops::getsockopt(impl.socket_, impl.state_,
0179         option.level(impl.protocol_), option.name(impl.protocol_),
0180         option.data(impl.protocol_), &size, ec);
0181     if (!ec)
0182       option.resize(impl.protocol_, size);
0183     BOOST_ASIO_ERROR_LOCATION(ec);
0184     return ec;
0185   }
0186 
0187   // Get the local endpoint.
0188   endpoint_type local_endpoint(const implementation_type& impl,
0189       boost::system::error_code& ec) const
0190   {
0191     endpoint_type endpoint;
0192     std::size_t addr_len = endpoint.capacity();
0193     if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
0194     {
0195       BOOST_ASIO_ERROR_LOCATION(ec);
0196       return endpoint_type();
0197     }
0198     endpoint.resize(addr_len);
0199     return endpoint;
0200   }
0201 
0202   // Get the remote endpoint.
0203   endpoint_type remote_endpoint(const implementation_type& impl,
0204       boost::system::error_code& ec) const
0205   {
0206     endpoint_type endpoint;
0207     std::size_t addr_len = endpoint.capacity();
0208     if (socket_ops::getpeername(impl.socket_,
0209           endpoint.data(), &addr_len, false, ec))
0210     {
0211       BOOST_ASIO_ERROR_LOCATION(ec);
0212       return endpoint_type();
0213     }
0214     endpoint.resize(addr_len);
0215     return endpoint;
0216   }
0217 
0218   // Disable sends or receives on the socket.
0219   boost::system::error_code shutdown(base_implementation_type& impl,
0220       socket_base::shutdown_type what, boost::system::error_code& ec)
0221   {
0222     socket_ops::shutdown(impl.socket_, what, ec);
0223     BOOST_ASIO_ERROR_LOCATION(ec);
0224     return ec;
0225   }
0226 
0227   // Send a datagram to the specified endpoint. Returns the number of bytes
0228   // sent.
0229   template <typename ConstBufferSequence>
0230   size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
0231       const endpoint_type& destination, socket_base::message_flags flags,
0232       boost::system::error_code& ec)
0233   {
0234     typedef buffer_sequence_adapter<boost::asio::const_buffer,
0235         ConstBufferSequence> bufs_type;
0236 
0237     size_t n;
0238     if (bufs_type::is_single_buffer)
0239     {
0240       n = socket_ops::sync_sendto1(impl.socket_, impl.state_,
0241           bufs_type::first(buffers).data(),
0242           bufs_type::first(buffers).size(), flags,
0243           destination.data(), destination.size(), ec);
0244     }
0245     else
0246     {
0247       bufs_type bufs(buffers);
0248       n = socket_ops::sync_sendto(impl.socket_, impl.state_,
0249           bufs.buffers(), bufs.count(), flags,
0250           destination.data(), destination.size(), ec);
0251     }
0252 
0253     BOOST_ASIO_ERROR_LOCATION(ec);
0254     return n;
0255   }
0256 
0257   // Wait until data can be sent without blocking.
0258   size_t send_to(implementation_type& impl, const null_buffers&,
0259       const endpoint_type&, socket_base::message_flags,
0260       boost::system::error_code& ec)
0261   {
0262     // Wait for socket to become ready.
0263     socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
0264     BOOST_ASIO_ERROR_LOCATION(ec);
0265     return 0;
0266   }
0267 
0268   // Start an asynchronous send. The data being sent must be valid for the
0269   // lifetime of the asynchronous operation.
0270   template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
0271   void async_send_to(implementation_type& impl,
0272       const ConstBufferSequence& buffers,
0273       const endpoint_type& destination, socket_base::message_flags flags,
0274       Handler& handler, const IoExecutor& io_ex)
0275   {
0276     bool is_continuation =
0277       boost_asio_handler_cont_helpers::is_continuation(handler);
0278 
0279     associated_cancellation_slot_t<Handler> slot
0280       = boost::asio::get_associated_cancellation_slot(handler);
0281 
0282     // Allocate and construct an operation to wrap the handler.
0283     typedef io_uring_socket_sendto_op<ConstBufferSequence,
0284         endpoint_type, Handler, IoExecutor> op;
0285     typename op::ptr p = { boost::asio::detail::addressof(handler),
0286       op::ptr::allocate(handler), 0 };
0287     p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
0288         buffers, destination, flags, handler, io_ex);
0289 
0290     // Optionally register for per-operation cancellation.
0291     if (slot.is_connected())
0292     {
0293       p.p->cancellation_key_ =
0294         &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0295             &impl.io_object_data_, io_uring_service::write_op);
0296     }
0297 
0298     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0299           "socket", &impl, impl.socket_, "async_send_to"));
0300 
0301     start_op(impl, io_uring_service::write_op, p.p, is_continuation, false);
0302     p.v = p.p = 0;
0303   }
0304 
0305   // Start an asynchronous wait until data can be sent without blocking.
0306   template <typename Handler, typename IoExecutor>
0307   void async_send_to(implementation_type& impl, const null_buffers&,
0308       const endpoint_type&, socket_base::message_flags,
0309       Handler& handler, const IoExecutor& io_ex)
0310   {
0311     bool is_continuation =
0312       boost_asio_handler_cont_helpers::is_continuation(handler);
0313 
0314     associated_cancellation_slot_t<Handler> slot
0315       = boost::asio::get_associated_cancellation_slot(handler);
0316 
0317     // Allocate and construct an operation to wrap the handler.
0318     typedef io_uring_null_buffers_op<Handler, IoExecutor> op;
0319     typename op::ptr p = { boost::asio::detail::addressof(handler),
0320       op::ptr::allocate(handler), 0 };
0321     p.p = new (p.v) op(success_ec_, impl.socket_, POLLOUT, handler, io_ex);
0322 
0323     // Optionally register for per-operation cancellation.
0324     if (slot.is_connected())
0325     {
0326       p.p->cancellation_key_ =
0327         &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0328             &impl.io_object_data_, io_uring_service::write_op);
0329     }
0330 
0331     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, "socket",
0332           &impl, impl.socket_, "async_send_to(null_buffers)"));
0333 
0334     start_op(impl, io_uring_service::write_op, p.p, is_continuation, false);
0335     p.v = p.p = 0;
0336   }
0337 
0338   // Receive a datagram with the endpoint of the sender. Returns the number of
0339   // bytes received.
0340   template <typename MutableBufferSequence>
0341   size_t receive_from(implementation_type& impl,
0342       const MutableBufferSequence& buffers,
0343       endpoint_type& sender_endpoint, socket_base::message_flags flags,
0344       boost::system::error_code& ec)
0345   {
0346     typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
0347         MutableBufferSequence> bufs_type;
0348 
0349     std::size_t addr_len = sender_endpoint.capacity();
0350     std::size_t n;
0351     if (bufs_type::is_single_buffer)
0352     {
0353       n = socket_ops::sync_recvfrom1(impl.socket_, impl.state_,
0354           bufs_type::first(buffers).data(), bufs_type::first(buffers).size(),
0355           flags, sender_endpoint.data(), &addr_len, ec);
0356     }
0357     else
0358     {
0359       bufs_type bufs(buffers);
0360       n = socket_ops::sync_recvfrom(impl.socket_, impl.state_, bufs.buffers(),
0361           bufs.count(), flags, sender_endpoint.data(), &addr_len, ec);
0362     }
0363 
0364     if (!ec)
0365       sender_endpoint.resize(addr_len);
0366 
0367     BOOST_ASIO_ERROR_LOCATION(ec);
0368     return n;
0369   }
0370 
0371   // Wait until data can be received without blocking.
0372   size_t receive_from(implementation_type& impl, const null_buffers&,
0373       endpoint_type& sender_endpoint, socket_base::message_flags,
0374       boost::system::error_code& ec)
0375   {
0376     // Wait for socket to become ready.
0377     socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
0378 
0379     // Reset endpoint since it can be given no sensible value at this time.
0380     sender_endpoint = endpoint_type();
0381 
0382     BOOST_ASIO_ERROR_LOCATION(ec);
0383     return 0;
0384   }
0385 
0386   // Start an asynchronous receive. The buffer for the data being received and
0387   // the sender_endpoint object must both be valid for the lifetime of the
0388   // asynchronous operation.
0389   template <typename MutableBufferSequence,
0390       typename Handler, typename IoExecutor>
0391   void async_receive_from(implementation_type& impl,
0392       const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
0393       socket_base::message_flags flags, Handler& handler,
0394       const IoExecutor& io_ex)
0395   {
0396     bool is_continuation =
0397       boost_asio_handler_cont_helpers::is_continuation(handler);
0398 
0399     int op_type = (flags & socket_base::message_out_of_band)
0400       ? io_uring_service::except_op : io_uring_service::read_op;
0401 
0402     associated_cancellation_slot_t<Handler> slot
0403       = boost::asio::get_associated_cancellation_slot(handler);
0404 
0405     // Allocate and construct an operation to wrap the handler.
0406     typedef io_uring_socket_recvfrom_op<MutableBufferSequence,
0407         endpoint_type, Handler, IoExecutor> op;
0408     typename op::ptr p = { boost::asio::detail::addressof(handler),
0409       op::ptr::allocate(handler), 0 };
0410     p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
0411         buffers, sender_endpoint, flags, handler, io_ex);
0412 
0413     // Optionally register for per-operation cancellation.
0414     if (slot.is_connected())
0415     {
0416       p.p->cancellation_key_ =
0417         &slot.template emplace<io_uring_op_cancellation>(
0418             &io_uring_service_, &impl.io_object_data_, op_type);
0419     }
0420 
0421     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0422           "socket", &impl, impl.socket_, "async_receive_from"));
0423 
0424     start_op(impl, op_type, p.p, is_continuation, false);
0425     p.v = p.p = 0;
0426   }
0427 
0428   // Wait until data can be received without blocking.
0429   template <typename Handler, typename IoExecutor>
0430   void async_receive_from(implementation_type& impl, const null_buffers&,
0431       endpoint_type& sender_endpoint, socket_base::message_flags flags,
0432       Handler& handler, const IoExecutor& io_ex)
0433   {
0434     bool is_continuation =
0435       boost_asio_handler_cont_helpers::is_continuation(handler);
0436 
0437     int op_type;
0438     int poll_flags;
0439     if ((flags & socket_base::message_out_of_band) != 0)
0440     {
0441       op_type = io_uring_service::except_op;
0442       poll_flags = POLLPRI;
0443     }
0444     else
0445     {
0446       op_type = io_uring_service::read_op;
0447       poll_flags = POLLIN;
0448     }
0449 
0450     associated_cancellation_slot_t<Handler> slot
0451       = boost::asio::get_associated_cancellation_slot(handler);
0452 
0453     // Allocate and construct an operation to wrap the handler.
0454     typedef io_uring_null_buffers_op<Handler, IoExecutor> op;
0455     typename op::ptr p = { boost::asio::detail::addressof(handler),
0456       op::ptr::allocate(handler), 0 };
0457     p.p = new (p.v) op(success_ec_, impl.socket_, poll_flags, handler, io_ex);
0458 
0459     // Optionally register for per-operation cancellation.
0460     if (slot.is_connected())
0461     {
0462       p.p->cancellation_key_ =
0463         &slot.template emplace<io_uring_op_cancellation>(
0464             &io_uring_service_, &impl.io_object_data_, op_type);
0465     }
0466 
0467     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, "socket",
0468           &impl, impl.socket_, "async_receive_from(null_buffers)"));
0469 
0470     // Reset endpoint since it can be given no sensible value at this time.
0471     sender_endpoint = endpoint_type();
0472 
0473     start_op(impl, op_type, p.p, is_continuation, false);
0474     p.v = p.p = 0;
0475   }
0476 
0477   // Accept a new connection.
0478   template <typename Socket>
0479   boost::system::error_code accept(implementation_type& impl,
0480       Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec)
0481   {
0482     // We cannot accept a socket that is already open.
0483     if (peer.is_open())
0484     {
0485       ec = boost::asio::error::already_open;
0486       BOOST_ASIO_ERROR_LOCATION(ec);
0487       return ec;
0488     }
0489 
0490     std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
0491     socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
0492           impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
0493           peer_endpoint ? &addr_len : 0, ec));
0494 
0495     // On success, assign new connection to peer socket object.
0496     if (new_socket.get() != invalid_socket)
0497     {
0498       if (peer_endpoint)
0499         peer_endpoint->resize(addr_len);
0500       peer.assign(impl.protocol_, new_socket.get(), ec);
0501       if (!ec)
0502         new_socket.release();
0503     }
0504 
0505     BOOST_ASIO_ERROR_LOCATION(ec);
0506     return ec;
0507   }
0508 
0509   // Start an asynchronous accept. The peer and peer_endpoint objects must be
0510   // valid until the accept's handler is invoked.
0511   template <typename Socket, typename Handler, typename IoExecutor>
0512   void async_accept(implementation_type& impl, Socket& peer,
0513       endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)
0514   {
0515     bool is_continuation =
0516       boost_asio_handler_cont_helpers::is_continuation(handler);
0517 
0518     associated_cancellation_slot_t<Handler> slot
0519       = boost::asio::get_associated_cancellation_slot(handler);
0520 
0521     // Allocate and construct an operation to wrap the handler.
0522     typedef io_uring_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op;
0523     typename op::ptr p = { boost::asio::detail::addressof(handler),
0524       op::ptr::allocate(handler), 0 };
0525     p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
0526         peer, impl.protocol_, peer_endpoint, handler, io_ex);
0527 
0528     // Optionally register for per-operation cancellation.
0529     if (slot.is_connected() && !peer.is_open())
0530     {
0531       p.p->cancellation_key_ =
0532         &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0533             &impl.io_object_data_, io_uring_service::read_op);
0534     }
0535 
0536     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0537           "socket", &impl, impl.socket_, "async_accept"));
0538 
0539     start_accept_op(impl, p.p, is_continuation, peer.is_open());
0540     p.v = p.p = 0;
0541   }
0542 
0543   // Start an asynchronous accept. The peer_endpoint object must be valid until
0544   // the accept's handler is invoked.
0545   template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
0546   void async_move_accept(implementation_type& impl,
0547       const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
0548       Handler& handler, const IoExecutor& io_ex)
0549   {
0550     bool is_continuation =
0551       boost_asio_handler_cont_helpers::is_continuation(handler);
0552 
0553     associated_cancellation_slot_t<Handler> slot
0554       = boost::asio::get_associated_cancellation_slot(handler);
0555 
0556     // Allocate and construct an operation to wrap the handler.
0557     typedef io_uring_socket_move_accept_op<Protocol,
0558         PeerIoExecutor, Handler, IoExecutor> op;
0559     typename op::ptr p = { boost::asio::detail::addressof(handler),
0560       op::ptr::allocate(handler), 0 };
0561     p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_,
0562         impl.state_, impl.protocol_, peer_endpoint, handler, io_ex);
0563 
0564     // Optionally register for per-operation cancellation.
0565     if (slot.is_connected())
0566     {
0567       p.p->cancellation_key_ =
0568         &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0569             &impl.io_object_data_, io_uring_service::read_op);
0570     }
0571 
0572     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0573           "socket", &impl, impl.socket_, "async_accept"));
0574 
0575     start_accept_op(impl, p.p, is_continuation, false);
0576     p.v = p.p = 0;
0577   }
0578 
0579   // Connect the socket to the specified endpoint.
0580   boost::system::error_code connect(implementation_type& impl,
0581       const endpoint_type& peer_endpoint, boost::system::error_code& ec)
0582   {
0583     socket_ops::sync_connect(impl.socket_,
0584         peer_endpoint.data(), peer_endpoint.size(), ec);
0585     return ec;
0586   }
0587 
0588   // Start an asynchronous connect.
0589   template <typename Handler, typename IoExecutor>
0590   void async_connect(implementation_type& impl,
0591       const endpoint_type& peer_endpoint,
0592       Handler& handler, const IoExecutor& io_ex)
0593   {
0594     bool is_continuation =
0595       boost_asio_handler_cont_helpers::is_continuation(handler);
0596 
0597     associated_cancellation_slot_t<Handler> slot
0598       = boost::asio::get_associated_cancellation_slot(handler);
0599 
0600     // Allocate and construct an operation to wrap the handler.
0601     typedef io_uring_socket_connect_op<Protocol, Handler, IoExecutor> op;
0602     typename op::ptr p = { boost::asio::detail::addressof(handler),
0603       op::ptr::allocate(handler), 0 };
0604     p.p = new (p.v) op(success_ec_, impl.socket_,
0605         peer_endpoint, handler, io_ex);
0606 
0607     // Optionally register for per-operation cancellation.
0608     if (slot.is_connected())
0609     {
0610       p.p->cancellation_key_ =
0611         &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0612             &impl.io_object_data_, io_uring_service::write_op);
0613     }
0614 
0615     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0616           "socket", &impl, impl.socket_, "async_connect"));
0617 
0618     start_op(impl, io_uring_service::write_op, p.p, is_continuation, false);
0619     p.v = p.p = 0;
0620   }
0621 };
0622 
0623 } // namespace detail
0624 } // namespace asio
0625 } // namespace boost
0626 
0627 #include <boost/asio/detail/pop_options.hpp>
0628 
0629 #endif // defined(BOOST_ASIO_HAS_IO_URING)
0630 
0631 #endif // BOOST_ASIO_DETAIL_IO_URING_SOCKET_SERVICE_HPP