POSIX sapi_netlink backend: IPv4 UDP sockets. LISTEN binds and learns its one peer from that peer's first HELLO datagram; CONNECT dials and retries HELLO until the peer's HELLO_ACK arrives. Both sides then connect() the datagram socket to its one fixed peer, so ordinary send()/recv() (no *_to/_from) carry every later message - see ADR-027.
More...
|
| static sapi_status_t | set_nonblocking (int fd) |
| static void | compute_deadline (sapi_duration_ms_t timeout_ms, struct timespec *out_deadline) |
| static int | remaining_ms (const struct timespec *deadline) |
| static sapi_status_t | open_listen_udp (const sapi_netlink_config_t *config, int *out_fd) |
| static sapi_status_t | open_connect_udp (const sapi_netlink_config_t *config, int *out_fd) |
| static sapi_status_t | backend_open (sapi_netlink_storage_t *storage, const sapi_netlink_config_t *config, sapi_netlink_handle_t *out_handle) |
| static sapi_status_t | backend_send (sapi_netlink_handle_t handle, const void *message, size_t message_size, sapi_duration_ms_t timeout_ms) |
| static sapi_status_t | backend_receive (sapi_netlink_handle_t handle, void *out_message, size_t buffer_size, sapi_duration_ms_t timeout_ms) |
| static sapi_status_t | backend_close (sapi_netlink_handle_t handle) |
| const sapi_netlink_backend_t * | sapi_posix_backend_netlink (void) |
| | The POSIX sapi_netlink backend (TCP sockets, LISTEN/CONNECT).
|
POSIX sapi_netlink backend: IPv4 UDP sockets. LISTEN binds and learns its one peer from that peer's first HELLO datagram; CONNECT dials and retries HELLO until the peer's HELLO_ACK arrives. Both sides then connect() the datagram socket to its one fixed peer, so ordinary send()/recv() (no *_to/_from) carry every later message - see ADR-027.
Known simplifications, stated plainly (this is a demo-grade first cut, not a hardened network stack):
- IPv4 only (AF_INET). IPv6 would need a second code path or an AF_UNSPEC + address-family-agnostic sockaddr_storage rewrite.
- LISTEN learns exactly one peer from the first valid HELLO it sees and connect()s to it - this backend models a single fixed point-to-point link (matching sapi_netlink's own scope), not a server accepting many clients.
- No transport-level "peer disconnected" signal: UDP has no connection to tear down, so unlike the old TCP backend this one essentially never returns SAPI_STATUS_HARDWARE_FAULT spontaneously. The one exception is ECONNREFUSED, which Linux surfaces on a connected UDP socket's next send()/recv() after an ICMP Port-Unreachable arrives (e.g. the peer process exited and closed its socket) - this is opportunistic and best-effort (silently suppressed by many NATs/firewalls, and never fires for a merely slow or partitioned peer), NOT the primary liveness mechanism. Detecting a truly stuck/gone peer is now the caller's job (e.g. sapi_dual_channel's ACK timeout, or an application-level staleness timer) - see ADR-027.
- Each send()/receive() call transfers exactly one datagram, never more or less - there is no byte-accumulation loop like a TCP backend needs, since UDP already preserves message boundaries. A received datagram whose length doesn't match this link's configured message_size is treated as a wire protocol violation (SAPI_STATUS_DATA_CORRUPTION), not silently truncated or padded.
- No TLS/authentication: this is a plaintext link, appropriate for a demo on localhost or a trusted network, not for anything exposed to an untrusted network.
Definition in file sapi_posix_backend_netlink.c.