12#include <linux/netlink.h>
14#include <boost/asio/async_result.hpp>
15#include <boost/asio/awaitable.hpp>
16#include <boost/asio/buffer.hpp>
17#include <boost/asio/redirect_error.hpp>
18#include <boost/asio/use_awaitable.hpp>
19#include <boost/system/error_code.hpp>
29 -> std::expected<void, std::error_code> {
30 if (bytes >= capacity) {
31 return std::unexpected(std::make_error_code(std::errc::message_size));
39template<
typename Derived,
typename Result>
41 requires(Derived& derived,
const Derived& const_derived,
const nlmsghdr& header) {
42 { derived.prepare_request() } -> std::same_as<void>;
43 { const_derived.request_payload() } -> std::same_as<std::span<const uint8_t>>;
45 derived.process_message(header)
46 } -> std::same_as<std::optional<std::expected<Result, std::error_code>>>;
58template<
typename Derived,
typename Result>
87 auto async_run() -> boost::asio::awaitable<std::expected<Result, std::error_code>> {
88 impl().prepare_request();
90 if (
auto send_result =
co_await send_request(); !send_result) {
91 co_return std::unexpected(send_result.error());
111 auto impl() noexcept -> Derived& {
112 return static_cast<Derived&
>(*this);
115 auto impl() const noexcept -> const Derived& {
116 return static_cast<const Derived&
>(*this);
119 auto send_request() -> boost::asio::awaitable<std::expected<void, std::error_code>> {
120 const auto payload =
impl().request_payload();
123 while (offset < payload.size()) {
124 boost::system::error_code ec{};
125 const auto sent =
co_await socket().async_send(
126 boost::asio::buffer(payload.data() + offset, payload.size() - offset),
127 boost::asio::redirect_error(boost::asio::use_awaitable, ec));
130 co_return std::unexpected(
131 std::error_code{ec.value(), std::generic_category()});
137 co_return std::expected<void, std::error_code>{};
140 auto read_loop() -> boost::asio::awaitable<std::expected<Result, std::error_code>> {
142 boost::system::error_code ec{};
143 const auto bytes =
co_await socket().async_receive(
145 boost::asio::redirect_error(boost::asio::use_awaitable, ec));
148 co_return std::unexpected(
149 std::error_code{ec.value(), std::generic_category()});
155 co_return std::unexpected(size_ok.error());
158 auto remaining =
static_cast<unsigned int>(bytes);
159 const auto header_size =
static_cast<unsigned int>(
sizeof(nlmsghdr));
163 while (remaining >= header_size && NLMSG_OK(header, remaining)) {
164 if (
auto result =
impl().process_message(*header)) {
165 co_return std::move(*result);
168 header = NLMSG_NEXT(header, remaining);
auto impl() const noexcept -> const Derived &
Definition nl_request_task.hxx:115
uint32_t sequence_
Definition nl_request_task.hxx:65
auto socket() noexcept -> Socket &
Definition nl_request_task.hxx:98
virtual ~RequestTask()=default
Virtual destructor.
SocketGuard & socket_guard_
Definition nl_request_task.hxx:63
auto read_loop() -> boost::asio::awaitable< std::expected< Result, std::error_code > >
Definition nl_request_task.hxx:140
static constexpr size_t MAX_RESPONSE_BYTES
Definition nl_request_task.hxx:60
auto impl() noexcept -> Derived &
Definition nl_request_task.hxx:111
RequestTask(SocketGuard &socket_guard, uint32_t ifindex, uint32_t sequence) noexcept
Construct a RequestTask.
Definition nl_request_task.hxx:74
auto async_run() -> boost::asio::awaitable< std::expected< Result, std::error_code > >
Run the request asynchronously and return the result.
Definition nl_request_task.hxx:87
auto send_request() -> boost::asio::awaitable< std::expected< void, std::error_code > >
Definition nl_request_task.hxx:119
uint32_t ifindex_
Definition nl_request_task.hxx:64
std::array< uint8_t, MAX_RESPONSE_BYTES > receive_buffer_
Definition nl_request_task.hxx:61
auto sequence() const noexcept -> uint32_t
Definition nl_request_task.hxx:102
auto ifindex() const noexcept -> uint32_t
Definition nl_request_task.hxx:106
Thread-safe guard owning a labeled Socket.
Definition nl_socket_guard.hxx:25
RAII wrapper for a Boost.Asio netlink socket.
Definition nl_socket.hxx:46
Definition nl_request_task.hxx:40
Definition nl_signal.hxx:28
auto validate_received_size(size_t bytes, size_t capacity) -> std::expected< void, std::error_code >
Definition nl_request_task.hxx:28
Definition nl_common.hxx:22
Definition nl_common.hxx:21