|
wired
libc-free QUIC/HTTP3 SDK in C for x86_64-linux
|
UDP via direct x86_64 syscalls, dual-stack (one AF_INET6 socket serves IPv6 natively and IPv4 as v4-mapped addresses). More...
Go to the source code of this file.
Data Structures | |
| struct | quic_sockaddr |
| A sockaddr_in6 laid out for the kernel (big-endian port; a 16-byte address that is either native IPv6 or an IPv4-mapped ::ffff:a.b.c.d). More... | |
| struct | quic_mmsg_buf |
| One slot of a recvmmsg() batch: caller-owned receive buffer and source address, filled in by wired_udp_recvmmsg on return. More... | |
Macros | |
| #define | WIRED_AF_INET 2 |
| AF_INET address family constant. | |
| #define | WIRED_AF_INET6 10 |
| AF_INET6 address family constant. | |
| #define | WIRED_SOCK_DGRAM 2 |
| SOCK_DGRAM socket type constant. | |
| #define | WIRED_GSO_CMSG_SPACE 24 |
| Byte length of a UDP_SEGMENT cmsg (header + u16 payload, 8-byte aligned). | |
Functions | |
| void | wired_udp_addr (quic_sockaddr *sa, u16 port, const u8 octets[4]) |
| Build an address from host-order port and IPv4 octets[0..3] = a.b.c.d, as the v4-mapped ::ffff:a.b.c.d — or, when the octets are all zero, the unspecified :: (the dual-stack bind-any address; a mapped 0.0.0.0 would bind IPv4-only). | |
| static u32 | wired_udp_addr4_be (const quic_sockaddr *sa) |
| Read a v4-mapped (or any) address's IPv4 bytes as a big-endian u32 — the accessor the IPv4-only paths (AF_XDP framing, MAC learning) use. | |
| i64 | wired_udp_socket (void) |
| Create a dual-stack UDP socket: AF_INET6 with IPV6_V6ONLY disabled, so IPv4 peers arrive as v4-mapped addresses on the same fd. | |
| i64 | wired_udp_bind (i64 fd, const quic_sockaddr *sa) |
| Bind fd to sa. | |
| i64 | wired_udp_send (i64 fd, const quic_sockaddr *sa, quic_span buf) |
| Send buf to sa. | |
| i64 | wired_udp_recv (i64 fd, quic_mspan buf) |
| Receive up to buf.n bytes into buf.p. | |
| i64 | wired_udp_recvfrom (i64 fd, quic_mspan buf, quic_sockaddr *src) |
| Receive up to buf.n bytes into buf.p and write the source address into src. | |
| i64 | wired_udp_close (i64 fd) |
| Close fd. | |
| i64 | wired_udp_gso_enable (i64 fd, u16 segsize) |
| Enable UDP GSO on fd: kernel will split a large sendmsg() payload into segsize-byte datagrams (Linux UDP_SEGMENT, kernel >= 4.18). | |
| void | wired_udp_gso_cmsg_build (u8 out[WIRED_GSO_CMSG_SPACE], u16 segsize) |
| Build a UDP_SEGMENT cmsg buffer for sendmsg() into out[0..WIRED_GSO_CMSG_SPACE). | |
| i64 | wired_udp_send_gso (i64 fd, const quic_sockaddr *sa, quic_span buf, u16 segsize) |
| Send count back-to-back segsize-byte segments (the last may be shorter, total = buf.n) to sa in one sendmsg() syscall using UDP GSO. | |
| i64 | wired_udp_send_batch (i64 fd, const quic_sockaddr *sa, quic_span buf, u16 segsize) |
| Send count back-to-back segsize-byte segments to sa via one sendto() call per segment (no GSO). | |
| i64 | wired_udp_recvmmsg (i64 fd, quic_mmsg_buf *bufs, usz count) |
| Receive up to count datagrams in one recvmmsg() syscall (Linux GRO-style batched receive, kernel >= 2.6.33). | |
| i64 | wired_udp_recvmmsg_fallback (i64 fd, quic_mmsg_buf *bufs, usz count) |
| Receive up to count datagrams via a wired_udp_recvfrom() loop (one syscall per datagram), stopping at the first empty/error result. | |
| i64 | wired_udp_ect0_enable (i64 fd) |
| Enable ECT(0) marking (RFC 3168, RFC 9000 13.4.1) on every packet fd sends: sets the IPv4 TOS byte's low 2 bits to 0b10 via IP_TOS (Linux uapi in.h). | |
| i64 | wired_udp_pmtu_probe_enable (i64 fd) |
| Enable IP_MTU_DISCOVER=IP_PMTUDISC_DO on fd (Linux uapi in.h): the kernel always sets the IPv4 DF (Don't Fragment) bit and never fragments outgoing datagrams on this socket, and suppresses its own PMTU enforcement/caching from ICMP Fragmentation Needed messages (RFC 8899 4.5) – the flow's PLPMTU search (quic_pmtu) owns path MTU discovery instead of the kernel. | |
| i64 | wired_udp_recvtos_enable (i64 fd) |
| Enable IP_RECVTOS on fd (Linux uapi in.h) so wired_udp_recvmmsg/ wired_udp_recvmmsg_nowait attach each received datagram's ECN codepoint into quic_mmsg_buf.ecn via an IP_TOS cmsg. | |
| i64 | wired_udp_reuseport_enable (i64 fd) |
| Enable SO_REUSEPORT on fd so multiple sockets (e.g. | |
| i64 | wired_udp_recvmmsg_nowait (i64 fd, quic_mmsg_buf *bufs, usz count) |
| Same as wired_udp_recvmmsg but non-blocking (MSG_DONTWAIT): returns immediately with a negative errno (e.g. | |
| i64 | wired_udp_busy_poll_enable (i64 fd, int microseconds) |
| Enable SO_BUSY_POLL on fd: the kernel spins the driver's poll routine for up to microseconds before sleeping (Linux, needs CONFIG_NET_RX_BUSY_POLL and driver support; a no-op on kernels/drivers without it). | |
| i64 | wired_udp_prefer_busy_poll_enable (i64 fd, int enable) |
| Enable/disable SO_PREFER_BUSY_POLL on fd: prefers busy-polling over interrupts for this socket. | |
| i64 | wired_udp_busy_poll_budget_set (i64 fd, int budget) |
| Set SO_BUSY_POLL_BUDGET on fd: caps how many packets a single busy-poll spin processes before yielding (Linux, needs CONFIG_NET_RX_BUSY_POLL). | |
| i64 | wired_udp_incoming_cpu_set (i64 fd, int cpu) |
| Set SO_INCOMING_CPU on fd: hints the kernel to steer this socket's incoming packets toward the given CPU (RPS/RSS steering, Linux). | |
UDP via direct x86_64 syscalls, dual-stack (one AF_INET6 socket serves IPv6 natively and IPv4 as v4-mapped addresses).
No libc.
| void wired_udp_addr | ( | quic_sockaddr * | sa, |
| u16 | port, | ||
| const u8 | octets[4] ) |
Build an address from host-order port and IPv4 octets[0..3] = a.b.c.d, as the v4-mapped ::ffff:a.b.c.d — or, when the octets are all zero, the unspecified :: (the dual-stack bind-any address; a mapped 0.0.0.0 would bind IPv4-only).
| sa | receives the kernel-ready address |
| port | UDP port in host byte order |
| octets | IPv4 address octets a.b.c.d |
|
inlinestatic |
| i64 wired_udp_bind | ( | i64 | fd, |
| const quic_sockaddr * | sa ) |
Bind fd to sa.
Ownership of fd stays with the caller; wired_udp_bind neither closes it on failure nor takes it over on success.
| fd | the socket fd |
| sa | the local address to bind |
Set SO_BUSY_POLL_BUDGET on fd: caps how many packets a single busy-poll spin processes before yielding (Linux, needs CONFIG_NET_RX_BUSY_POLL).
| fd | the socket fd |
| budget | packet budget per spin |
Enable SO_BUSY_POLL on fd: the kernel spins the driver's poll routine for up to microseconds before sleeping (Linux, needs CONFIG_NET_RX_BUSY_POLL and driver support; a no-op on kernels/drivers without it).
The codec does not interpret magnitude — 0 is a valid value, it just disables this knob.
| fd | the socket fd |
| microseconds | busy-poll budget in microseconds |
Close fd.
Takes ownership of fd: after this call fd is invalid regardless of the return value, and the caller must not use or close it again.
| fd | the socket fd |
Enable ECT(0) marking (RFC 3168, RFC 9000 13.4.1) on every packet fd sends: sets the IPv4 TOS byte's low 2 bits to 0b10 via IP_TOS (Linux uapi in.h).
RFC 9000 13.4.1 recommends ECT(0) as the default codepoint; this SDK never sends ECT(1) (see udp.c's cmsg reader, which still accepts ECT(1) on receive for a peer that does). ponytail: no fallback path on setsockopt failure – the error propagates to the caller as-is. quic-interop-runner's execution environment (Linux container, IPv4 UDP) has IP_TOS/IP_RECVTOS available unconditionally, so a degraded-but-functional non-ECN send path is out of this SDK's scope; add one if a real deployment target ever lacks IP_TOS.
| fd | the socket fd |
Build a UDP_SEGMENT cmsg buffer for sendmsg() into out[0..WIRED_GSO_CMSG_SPACE).
Pure byte-layout builder, no syscall: cmsg_len=18, cmsg_level=SOL_UDP, cmsg_type=UDP_SEGMENT, followed by segsize as a little-endian u16, zero- padded to WIRED_GSO_CMSG_SPACE bytes (Linux CMSG_SPACE(sizeof(u16))).
| out | destination buffer, must be >= WIRED_GSO_CMSG_SPACE bytes |
| segsize | per-segment byte size to encode |
Enable UDP GSO on fd: kernel will split a large sendmsg() payload into segsize-byte datagrams (Linux UDP_SEGMENT, kernel >= 4.18).
| fd | the socket fd |
| segsize | per-segment byte size |
Set SO_INCOMING_CPU on fd: hints the kernel to steer this socket's incoming packets toward the given CPU (RPS/RSS steering, Linux).
SET direction only – this libc-free SDK has no getsockopt infrastructure, so there is no corresponding getter.
| fd | the socket fd |
| cpu | target CPU number |
Enable IP_MTU_DISCOVER=IP_PMTUDISC_DO on fd (Linux uapi in.h): the kernel always sets the IPv4 DF (Don't Fragment) bit and never fragments outgoing datagrams on this socket, and suppresses its own PMTU enforcement/caching from ICMP Fragmentation Needed messages (RFC 8899 4.5) – the flow's PLPMTU search (quic_pmtu) owns path MTU discovery instead of the kernel.
ponytail: no fallback path on setsockopt failure, same scope note as wired_udp_ect0_enable – the quic-interop-runner's Linux container has this option unconditionally.
| fd | the socket fd |
Enable/disable SO_PREFER_BUSY_POLL on fd: prefers busy-polling over interrupts for this socket.
Only has kernel effect when SO_BUSY_POLL (wired_udp_busy_poll_enable with microseconds > 0) is also enabled on the same fd (Linux, needs CONFIG_NET_RX_BUSY_POLL and driver support).
| fd | the socket fd |
| enable | 0 or 1 |
| i64 wired_udp_recv | ( | i64 | fd, |
| quic_mspan | buf ) |
Receive up to buf.n bytes into buf.p.
| fd | the socket fd |
| buf | destination buffer |
| i64 wired_udp_recvfrom | ( | i64 | fd, |
| quic_mspan | buf, | ||
| quic_sockaddr * | src ) |
Receive up to buf.n bytes into buf.p and write the source address into src.
| fd | the socket fd |
| buf | destination buffer |
| src | receives the datagram's source address |
| i64 wired_udp_recvmmsg | ( | i64 | fd, |
| quic_mmsg_buf * | bufs, | ||
| usz | count ) |
Receive up to count datagrams in one recvmmsg() syscall (Linux GRO-style batched receive, kernel >= 2.6.33).
Each bufs[i].buf is a caller-owned destination buffer; on return bufs[i].len and bufs[i].src are filled for the first N slots actually received. On a blocking socket the call waits for the first datagram only (MSG_WAITFORONE) and then returns with whatever else was already queued, so a receive loop may always offer a full batch of slots without risking a wait for the whole batch.
| fd | the socket fd |
| bufs | array of count receive slots |
| count | number of slots in bufs |
| i64 wired_udp_recvmmsg_fallback | ( | i64 | fd, |
| quic_mmsg_buf * | bufs, | ||
| usz | count ) |
Receive up to count datagrams via a wired_udp_recvfrom() loop (one syscall per datagram), stopping at the first empty/error result.
The always- available fallback path for a kernel without recvmmsg support — symmetric with wired_udp_send_batch on the send side.
| fd | the socket fd |
| bufs | array of count receive slots |
| count | number of slots in bufs |
| i64 wired_udp_recvmmsg_nowait | ( | i64 | fd, |
| quic_mmsg_buf * | bufs, | ||
| usz | count ) |
Same as wired_udp_recvmmsg but non-blocking (MSG_DONTWAIT): returns immediately with a negative errno (e.g.
EAGAIN) if no datagram is queued, instead of waiting for the first one.
| fd | the socket fd |
| bufs | array of count receive slots |
| count | number of slots in bufs |
Enable IP_RECVTOS on fd (Linux uapi in.h) so wired_udp_recvmmsg/ wired_udp_recvmmsg_nowait attach each received datagram's ECN codepoint into quic_mmsg_buf.ecn via an IP_TOS cmsg.
Independent of wired_udp_ect0_enable: a socket may receive ECN reports without marking its own outgoing packets, or vice versa. ponytail: no fallback on failure, same scope note as wired_udp_ect0_enable.
| fd | the socket fd |
Enable SO_REUSEPORT on fd so multiple sockets (e.g.
one per worker process) can bind the same port; the kernel shards incoming datagrams across them by a 4-tuple hash (Linux, kernel >= 3.9).
| fd | the socket fd |
| i64 wired_udp_send | ( | i64 | fd, |
| const quic_sockaddr * | sa, | ||
| quic_span | buf ) |
Send buf to sa.
| fd | the socket fd |
| sa | the destination address |
| buf | the datagram to send |
| i64 wired_udp_send_batch | ( | i64 | fd, |
| const quic_sockaddr * | sa, | ||
| quic_span | buf, | ||
| u16 | segsize ) |
Send count back-to-back segsize-byte segments to sa via one sendto() call per segment (no GSO).
The last segment may be shorter (total = buf.n). The fallback path for a kernel without UDP_SEGMENT support.
| fd | the socket fd |
| sa | the destination address |
| buf | the concatenated segments to send |
| segsize | per-segment byte size (last segment may be shorter) |
| i64 wired_udp_send_gso | ( | i64 | fd, |
| const quic_sockaddr * | sa, | ||
| quic_span | buf, | ||
| u16 | segsize ) |
Send count back-to-back segsize-byte segments (the last may be shorter, total = buf.n) to sa in one sendmsg() syscall using UDP GSO.
| fd | the socket fd (GSO already enabled via wired_udp_gso_enable) |
| sa | the destination address |
| buf | the concatenated segments to send |
| segsize | per-segment byte size (last segment may be shorter) |
| i64 wired_udp_socket | ( | void | ) |
Create a dual-stack UDP socket: AF_INET6 with IPV6_V6ONLY disabled, so IPv4 peers arrive as v4-mapped addresses on the same fd.