FastMM documentation
FastMM C++ API 0.6.0
Public headers, tier 1 and tier 2
Loading...
Searching...
No Matches
udp_socket.hpp
Go to the documentation of this file.
1#pragma once
2// Non-blocking IPv4 UDP socket with RAII fd ownership: multicast membership, batch receive
3// (recvmmsg) and send (sendmmsg), SO_TIMESTAMPING and busy-poll options. Linux only.
4//
5// Configuration calls return 0 or -errno and also keep the errno in last_error(). I/O returns
6// IoResult (single datagram) or a count / -errno (batches). Nothing here allocates or throws.
7#include "fastmm/net/io_result.hpp"
8#include "fastmm/net/tcp_socket.hpp"
9
10#include <sys/socket.h>
11
12#include <cstddef>
13#include <cstdint>
14#include <optional>
15#include <span>
16#include <string_view>
17
18namespace fastmm::net {
19
20// Parses dotted-quad IPv4 into network byte order. Returns false on anything else.
21[[nodiscard]] bool parse_ipv4(std::string_view text, std::uint32_t& out_be) noexcept;
22[[nodiscard]] constexpr bool is_ipv4_multicast(std::uint32_t addr_be) noexcept {
23 return (addr_be & 0xF0U) == 0xE0U; // first octet 224..239, lowest byte in network order
25
26// Interface for multicast membership and IP_MULTICAST_IF: an IPv4 address or an interface index.
27// Both zero lets the kernel pick the interface from the routing table.
28struct McastInterface {
29 std::uint32_t addr_be = 0;
30 unsigned index = 0;
32 // "" (kernel's choice), a dotted-quad address, or an interface name ("eth0", resolved with
33 // if_nametoindex). Returns 0 or -errno (-ENODEV for an unknown name).
34 [[nodiscard]] static int resolve(std::string_view spec, McastInterface& out) noexcept;
35};
37// SIOCSHWTSTAMP on `ifname`: hardware timestamps for all received packets, TX off. Needs
38// CAP_NET_ADMIN and a NIC that supports it; the setting is device-wide and outlives the process.
39// Returns 0 or -errno (-EOPNOTSUPP / -EINVAL without NIC support, -EPERM without the capability).
40[[nodiscard]] int enable_hw_timestamps(std::string_view ifname) noexcept;
41
42class UdpSocket {
43 public:
44 UdpSocket() = default;
45 explicit UdpSocket(int fd) noexcept : fd_(fd) {}
47 UdpSocket(const UdpSocket&) = delete;
48 UdpSocket& operator=(const UdpSocket&) = delete;
49 UdpSocket(UdpSocket&& o) noexcept : fd_(o.fd_), err_(o.err_) { o.fd_ = -1; }
50 UdpSocket& operator=(UdpSocket&& o) noexcept {
51 if (this != &o) {
53 fd_ = o.fd_;
54 err_ = o.err_;
55 o.fd_ = -1;
56 }
57 return *this;
58 }
59
60 // Non-blocking, close-on-exec AF_INET datagram socket. Invalid on failure (errno in
61 // last_error()).
62 [[nodiscard]] static UdpSocket open() noexcept;
63
64 [[nodiscard]] int bind(const SockAddr& addr) noexcept;
65 [[nodiscard]] int connect(const SockAddr& addr) noexcept;
66 [[nodiscard]] int set_reuseaddr(bool on) noexcept;
67 // SO_RCVBUFFORCE (CAP_NET_ADMIN), falling back to SO_RCVBUF, which net.core.rmem_max caps.
68 // rcvbuf() reports what the kernel granted (twice the request, for its bookkeeping).
69 [[nodiscard]] int set_rcvbuf(int bytes) noexcept;
70 [[nodiscard]] int rcvbuf() const noexcept;
71 [[nodiscard]] int set_sndbuf(int bytes) noexcept;
73 // IP_ADD_MEMBERSHIP (any source) and source-specific membership (IP_ADD_SOURCE_MEMBERSHIP for
74 // an interface address, MCAST_JOIN_SOURCE_GROUP for an index). Addresses in network order.
75 [[nodiscard]] int join_group(std::uint32_t group_be, const McastInterface& ifc) noexcept;
76 [[nodiscard]] int join_source_group(std::uint32_t group_be,
77 std::uint32_t source_be,
78 const McastInterface& ifc) noexcept;
79 // IP_MULTICAST_ALL: off delivers only the groups this socket joined. Linux defaults to on,
80 // which also delivers groups joined by other sockets that match the bound address.
81 [[nodiscard]] int set_multicast_all(bool on) noexcept;
82 [[nodiscard]] int set_multicast_if(const McastInterface& ifc) noexcept;
83 [[nodiscard]] int set_multicast_ttl(int ttl) noexcept;
84 [[nodiscard]] int set_multicast_loop(bool on) noexcept;
86 // SO_TIMESTAMPING with RX_SOFTWARE | SOFTWARE | RX_HARDWARE | RAW_HARDWARE. Both stamps arrive in
87 // an SCM_TIMESTAMPING control message: ts[0] is the kernel's CLOCK_REALTIME receive time,
88 // ts[2] the NIC's raw PHC time, which is present only after enable_hw_timestamps() on the
89 // interface and is not CLOCK_REALTIME unless the PHC is disciplined to it (phc2sys).
90 [[nodiscard]] int enable_rx_timestamps() noexcept;
91 // SO_BUSY_POLL (µs), SO_PREFER_BUSY_POLL and SO_BUSY_POLL_BUDGET (both Linux 5.11). Each
92 // returns the setsockopt errno and changes nothing on failure: -EPERM without CAP_NET_ADMIN in
93 // the initial namespace (SO_BUSY_POLL above the current value before Linux 6.4, enabling
94 // SO_PREFER_BUSY_POLL, raising SO_BUSY_POLL_BUDGET), -ENOPROTOOPT on older kernels.
95 [[nodiscard]] int set_busy_poll(int usec) noexcept;
96 [[nodiscard]] int set_prefer_busy_poll(bool on) noexcept;
97 [[nodiscard]] int set_busy_poll_budget(int packets) noexcept;
99 // One datagram. would_block() on EAGAIN; `bytes` is the datagram's full length, which can
100 // exceed buf.size() (the rest is discarded; MSG_TRUNC).
101 IoResult recv_from(std::span<std::byte> buf, SockAddr* from = nullptr) noexcept;
102 IoResult send_to(std::span<const std::byte> buf, const SockAddr& to) noexcept;
103 IoResult send(std::span<const std::byte> buf) noexcept;
104 // recvmmsg / sendmmsg without blocking: messages transferred, 0 when the socket would block,
105 // or -errno. The caller owns the headers and resets msg_namelen / msg_controllen between calls.
106 int recv_batch(std::span<mmsghdr> msgs) noexcept;
107 int send_batch(std::span<mmsghdr> msgs) noexcept;
109 std::optional<SockAddr> local_addr() const noexcept;
110
111 void close() noexcept;
112 int release() noexcept {
113 const int f = fd_;
114 fd_ = -1;
115 return f;
116 }
117 int fd() const noexcept { return fd_; }
118 bool valid() const noexcept { return fd_ >= 0; }
119 int last_error() const noexcept { return err_; }
121 private:
122 int set_int_opt(int level, int name, int value) noexcept;
123 int fail() noexcept;
124
125 int fd_ = -1;
126 int err_ = 0;
127};
128
129} // namespace fastmm::net
Definition udp_socket.hpp:44
bool valid() const noexcept
Definition udp_socket.hpp:120
UdpSocket(const UdpSocket &)=delete
int set_multicast_if(const McastInterface &ifc) noexcept
int rcvbuf() const noexcept
int connect(const SockAddr &addr) noexcept
IoResult recv_from(std::span< std::byte > buf, SockAddr *from=nullptr) noexcept
One datagram.
int set_busy_poll_budget(int packets) noexcept
std::optional< SockAddr > local_addr() const noexcept
int set_multicast_ttl(int ttl) noexcept
IoResult send(std::span< const std::byte > buf) noexcept
int recv_batch(std::span< mmsghdr > msgs) noexcept
recvmmsg / sendmmsg without blocking: messages transferred, 0 when the socket would block,...
int join_group(std::uint32_t group_be, const McastInterface &ifc) noexcept
IP_ADD_MEMBERSHIP (any source) and source-specific membership (IP_ADD_SOURCE_MEMBERSHIP for an interf...
int last_error() const noexcept
Definition udp_socket.hpp:121
~UdpSocket()
Definition udp_socket.hpp:48
static UdpSocket open() noexcept
Non-blocking, close-on-exec AF_INET datagram socket.
int set_prefer_busy_poll(bool on) noexcept
IoResult send_to(std::span< const std::byte > buf, const SockAddr &to) noexcept
int set_reuseaddr(bool on) noexcept
UdpSocket & operator=(const UdpSocket &)=delete
int release() noexcept
Definition udp_socket.hpp:114
int set_rcvbuf(int bytes) noexcept
SO_RCVBUFFORCE (CAP_NET_ADMIN), falling back to SO_RCVBUF, which net.core.rmem_max caps.
int join_source_group(std::uint32_t group_be, std::uint32_t source_be, const McastInterface &ifc) noexcept
int fd() const noexcept
Definition udp_socket.hpp:119
void close() noexcept
int set_multicast_all(bool on) noexcept
IP_MULTICAST_ALL: off delivers only the groups this socket joined.
int set_sndbuf(int bytes) noexcept
int enable_rx_timestamps() noexcept
SO_TIMESTAMPING with RX_SOFTWARE | SOFTWARE | RX_HARDWARE | RAW_HARDWARE.
int set_multicast_loop(bool on) noexcept
int send_batch(std::span< mmsghdr > msgs) noexcept
UdpSocket(int fd) noexcept
Definition udp_socket.hpp:47
int bind(const SockAddr &addr) noexcept
int set_busy_poll(int usec) noexcept
SO_BUSY_POLL (µs), SO_PREFER_BUSY_POLL and SO_BUSY_POLL_BUDGET (both Linux 5.11).
Definition reactor.hpp:37
int enable_hw_timestamps(std::string_view ifname) noexcept
SIOCSHWTSTAMP on ifname: hardware timestamps for all received packets, TX off.
bool parse_ipv4(std::string_view text, std::uint32_t &out_be) noexcept
Parses dotted-quad IPv4 into network byte order. Returns false on anything else.
constexpr bool is_ipv4_multicast(std::uint32_t addr_be) noexcept
Definition udp_socket.hpp:24
Interface for multicast membership and IP_MULTICAST_IF: an IPv4 address or an interface index.
Definition udp_socket.hpp:30
std::uint32_t addr_be
Definition udp_socket.hpp:31
unsigned index
Definition udp_socket.hpp:32
static int resolve(std::string_view spec, McastInterface &out) noexcept
"" (kernel's choice), a dotted-quad address, or an interface name ("eth0", resolved with if_nametoind...