Files
alksocks/tasks/implementation/vendor-client-session.md
T
glm-5.3-flash 2cc010cf2b tasks: decompose the vendor group — six dependency-ordered tasks
The inline vendor (vendor.md, ADR-011 §Amendment) is the root of the
crate's dependency graph; this decomposes it before any downstream
group (params/wire/producer/consumer/doors).

- vendor-crate-scaffolding: Cargo.toml (wasm-clean tokio subset, no
  alkcall yet), lib.rs, vendor/ skeleton, bundled MIT notice
- vendor-wire-vocabulary: consts, codecs, errors, macros — with the
  extraction-boundary pins (error-variant pruning, pub command
  codecs, macro de-exporting)
- vendor-server-typestate: Socks5ServerProtocol + the new_reply
  publication (carried change #2); BIND's driving is producer-group
  work, the vendor carries only the surface
- vendor-client-session: Socks5Stream::use_stream path + the
  AsyncRead/AsyncWrite impls; Config pruned (connect_timeout cut);
  tests against a raw-byte mock server so it runs parallel with the
  typestate task
- vendor-differential-tests: RFC edge-case suite over duplex streams,
  pinning upstream behavior per vendor.md's differential posture
- review-vendor-extraction: the gate before downstream groups —
  file-by-file diff vs /workspace/fast-socks5 must contain only
  cut/carried-change/adjustment hunks

Graph validated: all dependency ids resolve, no cycles; topological
order scaffolding → wire → (typestate ∥ client) → tests → review.
2026-09-21 11:39:12 +00:00

5.6 KiB
Raw Blame History

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
implementation/vendor-client-session Vendor — the client session (Socks5Stream::use_stream path) pending
implementation/vendor-wire-vocabulary
narrow low component implementation

Description

Extract the client session — the consumer half's stream-session base (ADR-002; POC #1's fit) — into src/vendor/client.rs: the Socks5Stream<S>::use_stream path plus its AsyncRead/AsyncWrite impls, generic over the backing stream. The consumer layer (a later task group) opens a channels BiStream and feeds it here; the first-party associate session in consumer.rs was informed by this shape (vendor.md's extraction table).

What is extracted (upstream src/client.rs → src/vendor/client.rs):

  1. Socks5Stream<S> struct + the generic impl block, verbatim: use_stream, request, send_version_and_methods, which_method_accepted, use_password_auth, request_header, read_request_reply, get_socket/get_socket_ref/get_socket_mut.
  2. The AsyncRead/AsyncWrite impls for Socks5Stream<S> (upstream client.rs:641–681) verbatim — the consumer's session rides these (a Socks5Stream is itself a stream, so pump_bidi-shaped consumers and the front doors can pipe through it).
  3. The client Config struct — pruned: upstream carries connect_timeout (only consumed by the cut connect_raw) and skip_auth (consumed by use_stream). Keep skip_auth; drop connect_timeout and its setter (its only consumer is cut). If dropping it leaves Config a single-field struct, keep it anyway (fidelity: the field is load-bearing in use_stream's handshake branch) or inline the flag — implementer's choice, but the use_stream behavior must stay byte-identical.

What is NOT extracted (vendor.md's cut table row 2):

  • Socks5Datagram (struct + impl — the kernel UdpSocket associate client; the crate's associate session is first-party in consumer.rs per ADR-003's handle swap).
  • The Socks5Stream<TcpStream> convenience impl (connect/connect_with_password/connect_raw — the tokio::net::TcpStream dialers; the consumer's transport is a channels BiStream, not a TCP dial).

Extraction-time adjustments (mechanical):

  • Drop anyhow::Context — upstream wraps nearly every client error in .context(...). The error surface is SocksError (thiserror): replace .context("...")? with plain ? where the error variant already carries the meaning, and with the typed variants (SocksError::Io, AuthMethodUnacceptable, ...) where upstream used anyhow::Error::msg(...).into() (upstream client.rs:285 — the missing-target-addr case) or SocksError::Other(anyhow!(...)) (upstream client.rs:528 — but that site is inside the cut Socks5Datagram, so it goes with the cut). No behavior change to the wire: the same bytes are read/written; only the error typing changes.
  • Drop log calls (debug! in the extracted region).
  • use_password_auth's unreachable!() (upstream client.rs:207 — methods.get(1) being Some(AuthenticationMethod::None)): convention 2 forbids panics in library code. Replace with a typed error path (SocksError::AuthenticationRejected(...) or an AuthMethodUnacceptable) — the state is reachable only by misuse of the public API, but the faithful translation is an error return, not a panic.
  • client_src-style "[::]:0".parse().unwrap() sites are all inside the cut Socks5Datagram region — verify none remain.

Acceptance Criteria

  • src/vendor/client.rs exists with the inventory above; cargo test compiles
  • cargo check --target wasm32-unknown-unknown clean
  • No Socks5Datagram, no Socks5Stream<TcpStream> convenience impl (connect/connect_with_password/connect_raw) anywhere under src/vendor/
  • No anyhow, log, tokio::net, UdpSocket anywhere under src/vendor/
  • No unwrap/expect/unreachable!/panic paths in the extracted client code (convention 2)
  • Socks5Stream::use_stream over an in-memory duplex completes: no-auth handshake, password handshake (both accept and reject paths), CONNECT request + reply read (success and each mapped failure code), domain-target and IP-target request encoding — against a raw-byte mock server (pinned byte sequences written directly, not the vendored server typestate — keeping this task parallel with the typestate extraction and the client's wire expectations uncorrelated from the server implementation; tokio duplex streams, no sockets)
  • Socks5Stream<S> implements AsyncRead + AsyncWrite (the impls extracted) and the impls are exercised by at least one test (e.g. tokio::io::copy through the session)
  • cargo clippy --all-targets -- -D warnings and cargo fmt --check clean

References

  • docs/architecture/vendor.md (the extraction table row 5, the cut table row 2)
  • docs/architecture/decisions/002-protocol-base.md (the client side: Socks5Stream<S>::use_stream)
  • docs/architecture/decisions/003-udp-handle-swap.md (why Socks5Datagram is cut — the associate session is first-party)
  • docs/research/poc-connect-wasm-findings.md §Wire/API notes (Socks5Stream::request target construction; the AuthenticationRejected unit-variant note)
  • Upstream: /workspace/fast-socks5/src/client.rs
  • POC #4 gate map: docs/research/poc-connect-wasm-findings.md (client.rs row)

Notes

To be filled by implementation agent

Summary

To be filled on completion