122 lines
5.9 KiB
Markdown
122 lines
5.9 KiB
Markdown
---
|
|
id: implementation/composed-accept
|
|
name: Composed — the bind-first accept (the listener on a listen resource)
|
|
status: pending
|
|
depends_on: [implementation/composed-egress]
|
|
scope: moderate
|
|
risk: medium
|
|
impact: component
|
|
level: implementation
|
|
---
|
|
|
|
## Description
|
|
|
|
The `composed` feature's accept provider (ADR-008's composed
|
|
variants; ADR-007 variant 2): the BIND accept whose listener lives on
|
|
an alktunnels 0.2.0 bind-first listen resource
|
|
(`register_tunnel_bindfirst_openable` + `BindFirstInjections`) —
|
|
per-listener ACL for free, hub-relayable. **Vanilla-fidelity with no
|
|
stand-ins since the graduation** (ADR-007): reply#1 advertises the
|
|
real OS-chosen `bound` (the open-op reply's `bound` field, alkcall
|
|
0.8.0 reply projection); reply#2 carries the real peer (the forwarded
|
|
op's `peer` param).
|
|
|
|
Deliverables:
|
|
|
|
1. **`src/composed/` additions** (feature `composed`) — the composed
|
|
accept, named per producer.md §Wiring:
|
|
- `bindfirst_accept(...)` → `BindAcceptFactory`: the POC #5
|
|
`composed_bind_accept` shape **updated to the graduation** —
|
|
the POC's pinned workaround (reply#1 first, the tunnel open
|
|
rides the accept future; the factory carries an expected
|
|
`bind_addr`) is **retired** (ADR-007 §Consequences). The landed
|
|
shape: the factory opens the bind-first listen channel
|
|
(`TunnelListener::open` — the reply projection surfaces
|
|
`bound`), reply#1 advertises the real `bound`, and the accept
|
|
future correlates the forwarded sessions (the `listen` token →
|
|
the adopted forwarded sessions the assembly correlates; the
|
|
forwarded op's `peer` param is reply#2's peer).
|
|
- **The correlation shape is the design center** (the POC's
|
|
upstream-ask ledger retired by the graduation): the factory
|
|
returns `BindAccept` whose accept future waits for the ONE
|
|
forwarded session matching the listener's token. The
|
|
correlation registry is assembly-side bookkeeping (the
|
|
alktunnels `TunnelListener` docs: "forwarded sessions arrive as
|
|
ordinary adopted sessions on the manager; the listener does not
|
|
own the receipt queue"). The provider owns: the
|
|
`register_tunnel_forwarded_openable` serving side (the opener
|
|
half — the SOCKS5 producer's connection must serve the
|
|
forwarded op), the token→waiter map, and the per-forwarded
|
|
pump. Design the wait shape against the landed alkcall 0.8.0
|
|
adopt surface (`manager.adopt_channel`) and record it in Notes.
|
|
- **The Sync-bound wrinkle** (shared with composed-egress): the
|
|
accepted halves must be `Box<dyn AsyncRead + Send + Sync +
|
|
Unpin>` (`BindTargetHandle`'s payloads); alktunnels' `Taken
|
|
Halves` yields `Send + Unpin` only. The owner-wrapper rides
|
|
**inside the handle payloads** (egress.rs's documented posture)
|
|
— the wrapper owns the adopted channel session so dropping the
|
|
handle drops everything (the teardown-at-birth discipline,
|
|
compiler-enforced). This is the load-bearing wrapper: design it
|
|
once (with composed-egress's needs), pin it with a test.
|
|
- **Peer-address fidelity**: the forwarded op's `peer` param is
|
|
reply#2's real peer (the graduation's win); the wrapper-aware
|
|
sentinel (`0.0.0.0:0`) is the in-band default's shape, not this
|
|
variant's.
|
|
- **The establishment bound covers only the open-op round trip**
|
|
(ADR-007): the accept wait lives in the teardown-governed pump
|
|
phase — the quiet wait's `select!` drop of the accept future IS
|
|
the client-gone teardown; the listener (inside the future)
|
|
closes with it. The forwarded-op correlation must survive a
|
|
client-gone drop without leaking the listener (the accept
|
|
future owns it end-to-end — the seam contract).
|
|
- Module doc: names the ADRs (007/008), the graduation's
|
|
vanilla-fidelity win, the correlation shape, the owner-wrapper.
|
|
2. **Tests** (`tests/composed-accept.rs`): the full composed BIND
|
|
story over channels — a bind-first tunnel producer
|
|
(`register_tunnel_bindfirst_openable` + injections), the SOCKS5
|
|
producer with `composed::bindfirst_accept(...)`, a consumer BIND
|
|
session: reply#1 carries the real `bound`, an app server dials
|
|
the far listener, reply#2 carries the real peer, the pass-through
|
|
data plane round-trips; the client-gone teardown releases the
|
|
listener (drop-witness); two concurrent BIND sessions get
|
|
distinct tokens; a forwarded-open failure is per-accept isolated.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [ ] `cargo test` passes; `cargo test --all-features` passes
|
|
- [ ] `cargo check --features composed --target wasm32-unknown-
|
|
unknown` clean (hard gate)
|
|
- [ ] `cargo clippy --all-targets --all-features -- -D warnings`
|
|
clean; `cargo fmt --check` clean
|
|
- [ ] The graduation's shape lands (reply#1 = the real `bound`;
|
|
reply#2 = the forwarded op's real `peer`) — no expected-addr
|
|
stand-in — pinned by test
|
|
- [ ] The owner-wrapper rides inside the handle payloads (Sync
|
|
halves; teardown structural) — pinned by test
|
|
- [ ] The client-gone teardown releases the listener (the accept
|
|
future owns it end-to-end) — pinned by drop-witness test
|
|
- [ ] The forwarded-op serving side + correlation land; per-accept
|
|
isolation — pinned by tests
|
|
|
|
## References
|
|
|
|
- docs/architecture/decisions/007-bind-in-base.md (variant 2 + the
|
|
graduation), 008-provider-defaults.md, 004 (the accept seam's
|
|
contracts), 006 (the command gate)
|
|
- docs/architecture/producer.md §Wiring
|
|
(`composed::bindfirst_accept`), §The Three Seams
|
|
- POC reference: `/workspace/alksocks-bind-poc/src/accept.rs`
|
|
(`composed_bind_accept` — the superseded-in-shape workaround, the
|
|
owner-wrapper's first witness)
|
|
- Landed surfaces: `src/egress.rs` (`BindAccept`/`BindTargetHandle`
|
|
— the contracts), alktunnels 0.2.0 (`register_tunnel_bindfirst_
|
|
openable`, `BindFirstInjections`, `TunnelListener`,
|
|
`register_tunnel_forwarded_openable`, `ForwardedHandler`)
|
|
|
|
## Notes
|
|
|
|
> To be filled by implementation agent
|
|
|
|
## Summary
|
|
|
|
> To be filled on completion |