PAL network: datagrams, readiness polling, and exact errno semantics
- Type: feature (Track B PAL / networking)
- Status: done (POSIX slice; ESP run-validation + IPv6/DNS deferred)
- Owner: —
- Opened: 2026-06-21 (PAL network slice)
- Relation: follows
feature-platform-abstraction-layer; feedsfeature-networking
Problem
The first PAL network slice provides the minimum proven IPv4 TCP primitives: socket, reuseaddr, nonblocking, bind/connect/listen/accept, send/recv, shutdown, and socket close. POSIX uses raw Linux syscalls; ESP-IDF targets import lwIP symbols.
Missing surface that should be added deliberately:
- UDP/datagram operations (
sendto/recvfrom) and peer address reporting. - Readiness polling/select-style waits as PAL primitives, not only the existing Linux epoll coroutine reactor.
- Exact errno semantics across POSIX and ESP-IDF/lwIP. Raw Linux syscalls return
-errno, while lwIP returns-1and stores the real error in errno. - ESP-IDF link/run validation with a configured network interface or loopback configuration, not only object-level lwIP symbol imports.
- IPv6 and DNS/resolver hooks for the higher-level
feature-networkingAPI.
Acceptance
- POSIX PAL has loopback tests for TCP and UDP.
- ESP-IDF PAL links and runs a socket smoke in an IDF app on C3 and S3, with the app responsible for network interface bring-up.
- Error returns are documented and consistent enough for
net.pasand future Posix.* shims to distinguish EAGAIN/EINPROGRESS/connection failures. - The public higher-level networking unit can be written without platform conditionals above PAL.
Log
- 2026-06-21 — Opened after landing the first TCP PAL primitives. These gaps are real missing features, not reasons to bend the current PAL code into unvalidated workarounds.
- 2026-06-22 — POSIX slice landed (Track B, stable v37):
- UDP
PalSendToIpv4/PalRecvFromIpv4with peer-address reporting (ParseSockAddrIpv4), rawsendto/recvfromsyscalls per arch (x86-64/i386 socketcall/aarch64/arm32); i386 needed a 6-argSockCall6. PalPoll(handle, events, timeoutMs)readiness primitive via rawppoll(chosen overpollbecause aarch64 lacks the legacy syscall); revents packed in the second pollfd word, little-endian. NewPAL_POLL_*bits inplatform.pas.- Errno surface widened: raw POSIX syscalls already return
-errno; addedPAL_NET_EWOULDBLOCK/ECONNREFUSED/ECONNRESETsonet.pasand Posix.* shims can classify failures without platform conditionals. - ESP backend gained matching
lwip_sendto/lwip_recvfrom/lwip_pollbindings; off-target build returnsPAL_ERR_UNSUPPORTED(host-asserted inlib_platform_esp). - Verified by
test/lib_platform_net_udp.pas(loopback UDP echo + poll readiness + peer-addr check) wired intomake lib-test; full gate green. - Landed in commit
db1d3e1. - 2026-06-22 follow-up: the per-arch syscall numbers (sendto/recvfrom/ppoll,
i386 socketcall) are NO LONGER deferred — validated on i386, aarch64,
arm32 under qemu-user (
tools/run_target.sh), now a qemu-guarded cross block inmake lib-test. This is Track-B-runnable; earlier "cross = Track A" note was wrong (qemu-user is available here). riscv32 has no POSIX SYS_* table (it is the ESP target, served by the esp backend) — expected, not a gap. Still genuinely deferred: ESP-IDF lwIP run smoke on C3/S3 (needs an IDF app with network-interface bring-up under the Espressif qemu-system fork, not qemu-user); IPv6 + DNS hooks tracked byfeature-networking/feature-dns-resolver-library.
- UDP