File indexing completed on 2025-01-18 09:28:41
0001
0002
0003
0004
0005
0006
0007
0008
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
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
0053 typedef Protocol protocol_type;
0054
0055
0056 typedef typename Protocol::endpoint endpoint_type;
0057
0058
0059 typedef socket_type native_handle_type;
0060
0061
0062 struct implementation_type :
0063 io_uring_socket_service_base::base_implementation_type
0064 {
0065
0066 implementation_type()
0067 : protocol_(endpoint_type().protocol())
0068 {
0069 }
0070
0071
0072 protocol_type protocol_;
0073 };
0074
0075
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
0084 void shutdown()
0085 {
0086 this->base_shutdown();
0087 }
0088
0089
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
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
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
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
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
0146 native_handle_type native_handle(implementation_type& impl)
0147 {
0148 return impl.socket_;
0149 }
0150
0151
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
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
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
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
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
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
0228
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
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
0263 socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
0264 BOOST_ASIO_ERROR_LOCATION(ec);
0265 return 0;
0266 }
0267
0268
0269
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
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
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
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
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
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
0339
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
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
0377 socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
0378
0379
0380 sender_endpoint = endpoint_type();
0381
0382 BOOST_ASIO_ERROR_LOCATION(ec);
0383 return 0;
0384 }
0385
0386
0387
0388
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
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
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
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
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
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
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
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
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
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
0510
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
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
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
0544
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
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
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
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
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
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
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 }
0624 }
0625 }
0626
0627 #include <boost/asio/detail/pop_options.hpp>
0628
0629 #endif
0630
0631 #endif