phase 4: distribution data channel

Channel wraps the post-handshake socket and carries 4-byte length-
prefixed distribution messages: pass-through byte ('p') + ETF control
tuple + optional payload term.

API surface:
  send_raw / recv_raw     -- raw 4-byte framed bytes, empty == net_tick
  send_tick               -- send keepalive frame
  send_control / recv_message  -- structured control + payload
  send_reg_send           -- helper for the REG_SEND case (FromPid,
                             registered name, payload)

recv_message() transparently skips inbound ticks; callers wanting tick
awareness use recv_raw().

etf.decode_term(data, offset) exposed as a streaming decoder so the
channel can read control + payload back-to-back from one frame body.

Tests:
  - pure encode/decode round-trips
  - socketpair tests for framing, ticks, helper signatures
  - live end-to-end against an erl node with a registered echo process:
    EPMD -> handshake -> REG_SEND -> recv reply, payload matches
  - boot script writes a /tmp ready-flag after registering `echo`;
    fixture waits for both EPMD registration AND the flag to dodge
    the race where EPMD registers the node before -eval runs

101 tests green, lint clean.
This commit is contained in:
russell@unturf.com 2026-06-16 11:23:16 -04:00
parent 8c9311f18a
commit 776efaead3
No known key found for this signature in database
5 changed files with 501 additions and 9 deletions

View file

@ -46,13 +46,21 @@ EPMD (Erlang Port Mapper Daemon) maps node names to TCP ports.
Newer SHA-256 digest (DFLAG_MANDATORY_25_DIGEST) deferred — landed only
if we hit a peer that requires it.
## Phase 4 — Distribution channel
## Phase 4 — Distribution channel
- After handshake, the socket carries control + payload messages framed
by a 4-byte length prefix
- Send `SEND_TT` / `REG_SEND` for outgoing messages
- Receive replies, route by ref
- Tick loop for keepalive (60s default per OTP)
- `Channel` wraps the post-handshake socket: 4-byte length frames,
pass-through byte (`'p'`), control tuple + optional payload term
- `send_reg_send(from_pid, to_name, payload)` helper for the common case
- `recv_message()` skips ticks transparently; `recv_raw()` exposes them
for callers that need tick awareness
- Tick keepalive via `send_tick()` — caller drives the timer for now
(background ticker lands in Phase 7 alongside unfeed integration)
- Tests:
- Pure encode/decode round-trips
- Socket-pair tests for send/recv framing, tick handling
- Live end-to-end against an `erl` node with a registered echo
process: EPMD → handshake → REG_SEND → recv reply, payload matches
- Survives an outbound tick before the reply
## Phase 5 — gen_call convenience layer