consumer: Socks5ChannelSession (CONNECT) — teardown ownership + e2e suite
- Socks5ChannelSession::connect: open_channel(OP_SOCKS5_OPEN, {},
SOCKS5_ALPN) then the forked client typestate's use_stream path
over the channel BiStream (POC #1's fit); post-reply the session
is the raw byte pipe (0 B framing)
- Target construction via ToTargetAddr: IP-string forms parse to IP
targets, domain form passes through unresolved (ADR-012)
- split() borrowed halves (SplitPipe) / into_inner() owned pipe
(TakenInner — the session rides along as the teardown owner);
channel_id() for correlation
- Teardown ownership (alktunnels ADR-005 posture): Drop sync-reaps
the adopted entry (teardown_channel is sync; Drop cannot await) +
the pipe drop EOFs the producer pump structurally; close() is the
graceful path (write-half shutdown, then reap); the in-stream
refusal tears the channel down in connect (teardown-at-birth —
no phantom channel); no Clone (compile_fail doctest)
- Error surface: open failures are the typed SocksOpenError reasons
(ADR-049 §4); a refused target is the RFC reply code through
SocksSessionError::Rfc (consumer.md §Error surface)
- Harness: the consumer-side topology (wire_consumer_side[_with] —
the consumer dials with a real ChannelClient; the producer accepts
with the real registration) + witnessing_echo_dial; the
allow(dead_code) attr rides the alktunnels harness posture
- tests/consumer-connect.rs: 9 e2e tests — echo round-trip + CF-006
witness, target forms at the dial seam (ADR-012), refused dial →
typed RFC error + no phantom channel, FORBIDDEN open → typed open
error + no session, drop teardown + connection health, half-close
EOF semantics, into_inner pairing, Send shape
Verified: cargo test (219 green incl. the compile_fail doctest),
clippy --all-targets -D warnings, fmt --check,
check/clippy --target wasm32-unknown-unknown
This commit is contained in:
1 parent
df772ccbeb
commit
76717f3944
5 files changed
+876
-7
No files matched your search
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: implementation/core-consumer-connect
|
||||
name: "Core — consumer half: Socks5ChannelSession (CONNECT) + e2e tests"
|
||||
status: pending
|
||||
status: completed
|
||||
depends_on: [implementation/core-producer-connect]
|
||||
scope: narrow
|
||||
risk: low
|
||||
@@ -70,8 +70,51 @@ consumer.rs`, adapted to the crate's params/error surface):
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
> Filled by the implementation agent (2026-09-23):
|
||||
|
||||
- The session shape is exactly the POC's, adapted to the crate
|
||||
surface: `Socks5Stream::use_stream(bidi, None, Config::default())`
|
||||
over `BiStream::from_joined(recv, send)`, then `request(TCPConnect,
|
||||
target)`. `Config::default()` is the no-auth posture (the
|
||||
`skip_auth` knob stays internal to the fork; the identity seam is
|
||||
the open op's, CF-005/CF-006 — no RFC-facing auth on this path).
|
||||
- `split()` returns borrowed halves (`tokio::io::split` over a
|
||||
`&mut Socks5Stream<BiStream>`; the `SplitPipe` type alias), not
|
||||
owned ones: the session keeps teardown ownership for every shape,
|
||||
including the split-driven one. The owned path is `into_inner()`
|
||||
(`TakenInner { session, inner }` — the session rides along as the
|
||||
teardown owner).
|
||||
- Refusal teardown: an in-stream refusal (Rfc error) tears the
|
||||
adopted channel down inside `connect` before the error returns
|
||||
(teardown-at-birth; the phantom-channel property, tested both
|
||||
sides). The producer's own handler-exit teardown races the
|
||||
consumer's — the leak-check probe polls past that race.
|
||||
- Drop is the sync-reap posture (`teardown_channel` is sync;
|
||||
`Drop` cannot await) + the structural EOF of the dropped pipe; the
|
||||
graceful path is `close()` (write-half shutdown first, then reap).
|
||||
- Harness: added the consumer-side topology (`wire_consumer_side[_with]`
|
||||
— the consumer dials with a real `ChannelClient`; the producer
|
||||
accepts with the real registration) plus `witnessing_echo_dial`
|
||||
(the dial-witness target-form probe). The `allow(dead_code)` attr
|
||||
rides the alktunnels harness posture (each test binary compiles the
|
||||
harness and uses a different subset).
|
||||
- No `Clone` is compile-asserted by the doctest; a runtime probe
|
||||
pins `Send` (the `Clone` bound itself is the doctest's job).
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
Implemented `Socks5ChannelSession` (CONNECT) in `src/consumer.rs` —
|
||||
`connect`/`channel_id`/`split`/`into_inner`/`close` + `Drop` teardown
|
||||
ownership and the `SplitPipe`/`TakenInner` companions — with the
|
||||
typed error surface (`SocksOpenError` for opens, the RFC reply code
|
||||
through `SocksSessionError::Rfc` for refused targets) and
|
||||
teardown-at-birth on the in-stream refusal path. E2E suite
|
||||
(`tests/consumer-connect.rs`, 9 tests over the new consumer-side
|
||||
harness topology): echo round-trip + CF-006 witness, target forms
|
||||
(IP-string parses / domain passes through — ADR-012, wire-observed
|
||||
at the dial), refused dial → typed RFC error + no phantom channel,
|
||||
FORBIDDEN open → typed open error + no session, drop teardown +
|
||||
connection health, half-close EOF semantics, `into_inner` pairing,
|
||||
and the no-`Clone`/`Send` compile shape (the `compile_fail` doctest
|
||||
pins `!Clone`). Verification: `cargo test` (219 incl. the doctest),
|
||||
clippy `-D warnings` (all targets), fmt, and both wasm checks clean.
|
||||
Reference in new issue
Block a user