consumer: the BIND reply#2 re-entry guard + session hygiene (review-002 C-1, D-1, N-6, S-2)

- C-1: BindSession::await_inbound is take-guarded — the first read
  takes the session's stream; the returned BindDataPlane owns it (the
  TakenInner pairing posture; the session stays the teardown owner),
  so a second call returns the family's spent shape Ok(None) and can
  never re-read the live data plane. A failed read restores the inner
  (the phase is only consumed on success; the producer ends the
  session on every post-reply#1 failure exit, so a re-call EOFs —
  never a live data-plane re-read either way). Pinned by the
  double-await_inbound integration test (the spent shape + the
  data-plane bytes asserted untouched) and the spent-BIND unit test.
- D-1: one normative reply#2 reader (option a) — the session's
  await_inbound; BindReply1::await_inbound is cut and reply1() is
  documented as a view (bind_addr + raw_mut), matching its actual
  usage; the reply1()-twice re-entry path is closed (pinned by the
  view test).
- N-6: the three session constructors' prologues collapsed into one
  private open_and_negotiate helper (teardown-at-birth in one place);
  zero behavior change.
- S-2: the EOF-propagation doc line on all three reap sites (the
  dropped teardown_channel handle is deliberate — the graceful shape;
  clear_all aborts instead).
- BindDataPlane is un-lifetimed (owns the stream); into_inner returns
  the owned Socks5Stream<BiStream>; docs synced (module + session
  docs, consumer.md §The BIND client).

Verification: cargo test 352 green (all-features too), clippy
-D warnings clean, fmt clean, cargo doc clean, both wasm checks clean.
This commit is contained in:
glm-5.3-flash committed 2026-09-24 11:58:55 +00:00
1 parent 6d14d35a54
commit 53739b20cb
4 files changed
+459 -139

No files matched your search

+15 -5
View File
@@ -1,8 +1,8 @@
---
status: draft
last_updated: 2026-09-24 (the landed session signatures reconciled —
`&ChannelClient` constructors, `impl ToTargetAddr` datagrams, the
`Option`-shaped `recv_datagram`; Phase 1 initial draft 2026-09-20)
last_updated: 2026-09-24 (the BIND spent posture reconciled — the
take-guarded reply#2 reader, review 002 C-1/D-1; the landed session
signatures reconciled 2026-09-24; Phase 1 initial draft 2026-09-20)
---
# alksocks — The Consumer Half
@@ -69,8 +69,18 @@ The BIND reply#2 reader (POC #5's `read_reply2` sketch): the forked
client `request()` reads reply#1; reply#2 is hand-read with the
forked public `read_address` codec (reply#1's codec applied again;
no second codec). The session then rides the pass-through data
plane. The BIND client is a wrapper-aware-consumer convenience —
vanilla clients reach BIND through the front door instead.
plane. The reply#2 phase is take-guarded: the one normative reader
is `await_inbound` — the first read consumes the session's stream
(the returned plane owns it; the session stays the teardown owner),
so a second call returns the family's spent shape (`Ok(None)`, the
same posture the sibling sessions pin) and cannot re-read the live
data plane; a failed read restores the inner (the producer ends the
session on every post-reply#1 failure exit, so a re-call EOFs —
never a live data-plane re-read either way). The
`reply1()` handle is a view (the advertised BND.ADDR + the raw
pre-reply#2 stream), not a reader. The BIND client is a
wrapper-aware-consumer convenience — vanilla clients reach BIND
through the front door instead.
### Error surface