Run your transport against a hostile link
Compose the stack and survive seeded loss, duplication, reordering, delay, and a small MTU.
Jump to code and terminal ↓All primitives, one connection
Implement all five callbacks using the contracts from the preceding stages. Open, send binary bytes with flow control, deliver peer bytes in order, recover dropped packets, and close. This final starter deliberately leaves the transport callbacks open; the framing/checksum helpers and test peer remain supplied.
The peer reacts to what you emit
The harness decodes your actual transmitted frames. Its ACK depends on the sequence and data it received, never on a prewritten success timeline. The lossy scenarios drop the first SYN, data segment, and FIN, then use a seeded generator for further loss and jitter. They duplicate deliveries, inject segment two before segment one, and vary MTU. MSS is configured as MTU minus 40 bytes; there is no IP fragmentation or path discovery.
Experiment, then test the contract
Run defaults to seed 7, 12 ms one-way latency, loss frequency 5, duplicate frequency 3, and MTU 92. You can run another scenario from the shell using the environment variables below. Test always runs the earlier behavioral cases and three pinned wire scenarios, independent of those exploratory settings. Its 8000 ms virtual budget advances instantly; high-loss experiments can legitimately exhaust the retry budget.
LAB_SEED=9001 LAB_LATENCY_MS=35 LAB_LOSS_EVERY=7 \ LAB_DUPLICATE_EVERY=2 LAB_MTU=76 /work/adverse-network 0 disables loss or duplication. MTU range: 68–1500. LAB_PACKET lines contain the guest program's actual Ethernet bytes.
The boundary you own
Your callbacks run as a real C program in RV64 Linux. /course/netlab.h supplies bounded Ethernet/IP/TCP encoding, checksum validation, a virtual clock, and packet capture. You own the transport state and sequence numbers. emit_tcp(c, flags, seq, ack, bytes, length) emits actual packet bytes; the browser's program trace decodes them. Test injects packets and timer events rather than inspecting source text. This is a deliberately bounded active-open, stop-and-wait TCP implementation, not a replacement for the kernel TCP stack.
snd_una: first unacknowledged byte snd_nxt: next unsent byte rcv_nxt: next peer byte expected peer_window: advertised capacity pending_seq/flags/len/pending[]: one segment awaiting ACK sent_at, rto, retries, timer_active: retransmission ownership delivered[] / delivered_len: bytes accepted by the application lab_now: deterministic clock in milliseconds
Your goal
Implement the complete bounded active-open TCP transport and move binary data in both directions through the deterministic adverse-network harness.
What the tests observe
- All previous transport invariants
- 93 binary bytes delivered exactly
- Duplicate/reordered peer data
- Seeded loss, latency, small MTU, complete close
Need a nudge?
Hint 1
Start with the handshake test, then add data, retries, windows, and close in that order. Run tests names the first broken ownership invariant.
Hint 2
The wire's peer acknowledges received bytes; advancing snd_nxt again during a retransmission or releasing pending data on a future ACK will corrupt the final stream.
Hint 3
The low MTU requires several sends. Return a partial count from tcp_send and retain each segment until its exact cumulative ACK. Duplicate/out-of-order peer bytes must still produce one onetwo stream.
Hint 4
Successful close needs FIN retransmission and TIME_WAIT. The first FIN disappears in lossy scenarios, and the peer can repeat its own FIN.
What happens inside Linux
This is a real, deliberately small transport state machine executed by Linux, with authentic TCP/IP frame serialization. It provides reliable ordered delivery under the bounded test scenarios. Production TCP also needs congestion control, RTT estimation, multiple outstanding segments, robust window sequencing, passive open, and many more adversarial validations.
Optional account sync. Exercises work without an account.