Expand description
Core drain consumer (A2 / A3): core dials C2, drains one node stream, and answers on the same stream. C2 never dials core and never sees plaintext.
Per stream: Noise_NK msg1 arrives as a DATA envelope, core answers msg2 as downlink
DATA, then every envelope is Noise transport. Each plaintext goes to a
CoreHandler together with the node id taken from the stream (never from the
payload); the reply is encrypted back down. Every processed seq is ACKed, and a
reconnect RESUMEs after the last ACK.
Restart safety: the last ACK per node/channel is persisted (see CursorStore) so a
restarted core does not replay the node’s stream from zero. When a replay still
happens (no cursor, C2 reset), only the newest Handshake1 of the backlog is answered:
a Handshake1 is held until the backlog goes idle, a newer one replaces it, and
transport frames queued behind an unanswered Handshake1 belong to an older session
and are dropped. If no handshake lands for a while after resuming from a persisted
cursor (C2 restarted and its seqs restarted), the cursor is reset to zero.
A node does not notice a core restart (its C2 uplink stays up), so when core holds
no session it sends an undecryptable transport frame; the node drops its stale keys
and re-handshakes.
Structs§
- Cursor
Store - File-backed last-ACK cursor for one node stream. Writes are atomic (tmp + rename).
- Drain
Consumer - Node
Stream
Constants§
- DRAIN_
STATE_ DIR_ ENV - Env var naming the directory for persisted drain cursors (absolute path).
Type Aliases§
- Core
Handler - Core logic for one decrypted inner message. Blocking work is fine: it runs on a
blocking thread. Return
Nonefor messages that need no reply.