Skip to content

Deliver loopback UDP datagrams across processes on the same machine#855

Open
brandonpayton wants to merge 1 commit into
mainfrom
fix/cross-process-loopback-udp
Open

Deliver loopback UDP datagrams across processes on the same machine#855
brandonpayton wants to merge 1 commit into
mainfrom
fix/cross-process-loopback-udp

Conversation

@brandonpayton

Copy link
Copy Markdown
Member

Contract: POSIX loopback is machine-scoped, not process-scoped

sendto(127.0.0.1:port) from one process must reach a socket bound to that port in another process on the same machine. Kandelo delivered loopback datagrams only within the sender's own process — udp_send_datagram holds a single &mut Process and skipped every endpoint whose pid != proc.pid. So cross-process loopback UDP was silently dropped: unconnected sendto returned success with the datagram lost, and connected sockets got a spurious ECONNREFUSED.

TCP already handled the analogous case (cross_process_loopback_connect, invoked from kernel_connect — this is how nginx→PHP-FPM works over loopback). UDP had no equivalent.

Fix

Add deliver_cross_process_loopback_udp (in syscalls.rs, table-agnostic and unit-testable), invoked from the kernel_sendto / kernel_send / kernel_sendmsg dispatch entry points after the same-process attempt. The dispatch layer owns the global process table, mirroring the existing TCP cross-process pattern; syscalls.rs stays table-agnostic.

  • Only engages for AF_INET DGRAM sockets whose effective destination is 127.x. Non-loopback (virtual-network 10.88.x) and same-process delivery are untouched.
  • A loopback UDP port binds in exactly one process, and endpoints owned by the sender are skipped, so this never double-delivers a datagram already queued same-process.
  • An unconnected sender auto-binds to INADDR_ANY; its source is reported as 127.0.0.1 so the receiver's recvfrom sees a loopback source, matching real semantics.

ABI

No change — no new kernel exports/imports or repr(C) types. scripts/check-abi-version.sh reports the snapshot in sync and ABI_VERSION/snapshot consistent.

Validation

  • cargo test -p kandelo --target aarch64-apple-darwin --lib964 pass, including new test_udp_loopback_cross_process, which binds a UDP socket in process B, delivers from process A, and reads it back via real sys_socket/sys_bind/sys_recvfrom across two Processes (asserting payload + loopback source addr/port).
  • scripts/check-abi-version.sh — snapshot in sync.
  • Same-process loopback UDP (test_udp_loopback) and non-loopback paths unchanged (helper is a no-op for them).

Follow-up (not in this PR): a host-level two-process integration test would exercise the guest sendto() syscall end-to-end; the dispatch wiring here mirrors the already-proven TCP cross_process_loopback_connect.

🤖 Generated with Claude Code

POSIX loopback is machine-scoped: `sendto(127.0.0.1:port)` from one process
must reach a socket bound to that port in another process on the same machine.
Kandelo delivered loopback datagrams only within the sender's own process
(`udp_send_datagram` holds a single `&mut Process` and skipped every endpoint
whose `pid != proc.pid`), so cross-process loopback UDP was silently dropped —
unconnected `sendto` returned success with the datagram lost, and connected
sockets got a spurious `ECONNREFUSED`. TCP already handled the analogous case
via `cross_process_loopback_connect`; UDP had no equivalent.

Add `deliver_cross_process_loopback_udp`, invoked from the `kernel_sendto`,
`kernel_send`, and `kernel_sendmsg` dispatch entry points after the
same-process attempt (the dispatch layer owns the global process table, mirroring
`cross_process_loopback_connect`). A loopback UDP port binds in exactly one
process, and endpoints owned by the sender are skipped, so this never
double-delivers a datagram already queued same-process.

No ABI change: no new kernel exports/imports or repr(C) types; snapshot
unchanged.

Validation: `cargo test -p kandelo --lib` (964 pass, incl. new
`test_udp_loopback_cross_process` exercising bind/deliver/recvfrom across two
processes); `scripts/check-abi-version.sh` reports snapshot in sync.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant