Workflow status is tracked in GitHub: https://github.com/emulebb/emulebb-rust/issues/1. This local document is retained as an engineering spec/evidence record.
RUST-FEAT-001 - eD2K — Implement client UDP source reask and queue-slot persistence¶
Summary¶
The eD2K client↔client UDP reask family (OP_REASKFILEPING 0x90, OP_REASKACK
0x91, OP_FILENOTFOUND 0x92, OP_QUEUEFULL 0x93, and the LowID variants
OP_REASKCALLBACKUDP 0x94 / OP_DIRECTCALLBACKREQ 0x95) is implemented and
enabled by default in emulebb-rust. This item remains open until the live
interoperability proof is refreshed after the latest parity fixes. Full design:
docs/design/udp-source-reask.md.
Current State¶
Update 2026-06-14 — code-complete off by default. The pure + state + loop
layers were implemented behind enable_udp_reask (off): codec/policy/registry/
state, the shared-Kad-UDP-port transport, uploader reciprocity, downloader detach,
and TCP-fallback re-engage (~64 tests, clippy-clean). The temporary omission was
recorded in policy/rust-client-omissions.toml while the feature was staged.
Update 2026-06-17 — enabled by default; metadata hardening in progress. Kad
source conversion now preserves non-zero FT_SOURCEUPORT for HighID as well as
firewalled-buddy sources, so UDP-reask reachability metadata is not lost before a
TCP hello can refresh it. Remaining work is live interoperability validation and
closing any defects found during that validation.
Parity closure note 2026-06-19. This item is no longer a broad
implementation blocker for core MFC parity. The remaining blocker is evidence:
regenerate the overnight/local parity campaign after the latest parity fixes and
run the targeted Rust/eMuleBB UDP reask proof owned by RUST-CI-002.
crates/emulebb-ed2k/src/ed2k_client_udp/owns the client UDP reask codec, dispatch, obfuscation, source set, reciprocity, buddy relay, and runtime.crates/emulebb-ed2k/src/config.rsdefaultsenable_udp_reaskto true.crates/emulebb-core/src/lib.rsspawns the reask loop while connected and wires detach/re-engage events back into transfer scheduling.policy/rust-client-omissions.tomlno longer records UDP reask as an active omission.
Why This Matters¶
UDP reask is the backbone of eMule's queue economy. On a busy swarm, uploaders reclaim idle TCP sockets, so a held-TCP queued model loses the slot as soon as the connection drops. The remaining risk is not the implementation itself; it is whether the refreshed evidence proves Rust keeps MFC-compatible queue behavior across Rust↔Rust, Rust↔eMuleBB, Rust↔aMule, and public smoke scenarios.
Representative Sites¶
crates/emulebb-ed2k/src/ed2k_client_udp/— UDP source reask transport, codec, runtime, source set, outbound framing, reciprocity, and buddy relay.crates/emulebb-ed2k/src/ed2k_tcp/download/session/reask_detach.rs— queued source detach eligibility.crates/emulebb-core/src/lib.rs— reask loop spawn, detach/re-engage event wiring, and direct-download scheduling integration.crates/emulebb-ed2k/src/ed2k_tcp/listener/session/upload_queue.rsandcrates/emulebb-ed2k/src/ed2k_transfer/reask_reciprocity.rs— upload queue state used to answer inbound reasks.- Reference (stock):
emulebb-main/srchybrid/DownloadClient.cpp(UDPReaskForDownload,UDPReaskACK,UDPReaskFNF),ClientUDPSocket.cpp(reask receive/answer),opcodes.h(FILEREASKTIME29 min,MIN_REQUESTTIME10 min,UDPMAXQUEUETIME20 s).
Intended Shape¶
Per the design doc: add one shared client UDP transport module
(ed2k_client_udp/) that owns the recv loop, de-obfuscates, dispatches the
OP_EMULEPROT reask opcodes, and fans replies back to the owning transfer/source
by (peer_ip, peer_udp_port) correlation under a pending anti-spoof gate. Each
download transfer drives its own reask ticker (no global scheduler — honours
the independent per-transfer-task download model); UDP-eligible queued sources
release their TCP socket and keep position by datagram, with TCP reconnect-reask
as the bounded fallback. Implement both downloader and uploader (reciprocity)
sides with exact stock framing (udp_version-gated partstatus/complete-count
tails) and stock obfuscation choice. Phase the LowID buddy reask
(OP_REASKCALLBACKUDP) and OP_DIRECTCALLBACKREQ separately.
Scope Constraints¶
- Out of RC2 scope — capture and stage; do not build under the freeze.
- IPv4-only; reuse existing obfuscation primitives; introduce focused modules
for independently nameable responsibilities; no prerequisite big-refactor of
legacy
.rsfiles. - Phase 1 = HighID UDP reask + TCP fallback + reciprocity. Phase 2 = LowID buddy reask + direct callback.
- Non-goal: A4AF cross-file source dedup (separate parked design); the two compose but neither requires the other.
Acceptance Criteria¶
- [x] Phase 0: omission reconciled: UDP reask is no longer recorded as an
active omission and advertised
udp_versionmatches implemented support. - [x] Client UDP transport module bound to the local eD2K UDP port, with obfuscated + plaintext recv/send and opcode dispatch keyed on socket + protocol byte.
- [x] Downloader sends
OP_REASKFILEPINGwith stock-exact framing (hash16 +udp_version-gated partstatus + complete-count) only when UDP-eligible (peer UDP port + version, not firewalled, no live TCP, no proxy). - [x] Downloader handles
OP_REASKACK(rank + optional partstatus),OP_QUEUEFULL(rank 0, stay),OP_FILENOTFOUND(drop source); unsolicited replies dropped by thependinggate. - [x] UDP-eligible queued sources release the TCP socket and retain queue
position across TCP teardown via UDP reask on a
FILEREASKTIME-based cadence (×2 NNP,≥ MIN_REQUESTTIME), with failure-ratio backoff to TCP. - [x] Non-UDP-eligible sources fall back to bounded TCP reconnect-reask.
- [x] Uploader answers well-formed inbound
OP_REASKFILEPINGfrom known waiting clients with a correct queue position (silent/OP_QUEUEFULLper stock rules otherwise). - [x] Per-transfer reask cadence introduces no cross-transfer shared scheduler.
- [ ] Refreshed live interoperability evidence proves the implemented behavior
against the current post-
RUST-BUG-099parity baseline.
Validation¶
- Unit: per-opcode encode/decode round-trips incl.
udp_version > 2/> 3tails; pending-gate drop; backoff threshold; reask-interval math. - Rust↔Rust: queued downloader releases TCP and keeps position purely via UDP reask across an accelerated cadence.
- Rust↔aMule / Rust↔eMuleBB short-path witness (gentle, widely-spaced, single-pass; confirm before any live-wire run per live-wire policy).
- packet_trace labels added for the new opcodes so the harness can assert the exchange.
- Core parity close: run the targeted Rust/eMuleBB reask proof from
RUST-CI-002after current HEAD evidence is regenerated.
Notes¶
- Provenance: protocol-divergence audit across
emulebb-community-baseline,emulebb-main, and emulebb-rust; gap confirmed identical inp2p-overlord-agents. - Related design:
docs/design/udp-source-reask.md,docs/design/source-management-and-a4af.md. - Depends on nothing else; A4AF is independent.