reliable-transport/PROTOCOL.md
2026-10-19 13:24:25 -06:00

3.4 KiB

Stage 2: what crosses the wire

challenge.py speaks this for you. It is written down so that when something goes wrong you can tell a protocol mistake from a Go-Back-N or Selective Repeat mistake, which is the difference between "my JSON was wrong" and "my window logic was wrong". Only the second one is what this project is about.

There are two channels. Control is TCP and carries one JSON object per line. Data is UDP and carries exactly the packets packet.py builds, unchanged.

Control, on TCP 8422

client  {"msg": "hello", "challenge": "A-sr", "student": "tremaux"}
server  {"msg": "session", "challenge": "A-sr", "student": "tremaux",
         "udp_port": 8500, "bytes": 24000, "seconds": 90,
         "send": "the payload from payload_for(student), 24000 bytes"}
client  {"msg": "ready", "udp_port": 51234}
  ... the UDP transfer happens ...
server  {"msg": "result", "ok": true, "challenge": "A-sr",
         "flag": "CS4220-RT-A-sr-...", "detail": {...}}

challenge is one of A-gbn, A-sr, B-gbn, B-sr. student is your UCCS username in lowercase: it decides which payload you are asked for and which flag you get back, so a capture of someone else's session is no use to you.

udp_port in the session message is the port on the server to send to. udp_port in the ready message is the port your own socket is bound to, so the server knows where to send. Send ready only once your socket exists, because the server starts the moment it arrives.

On a refusal the server answers {"msg": "error", "detail": "..."} and closes. On a challenge that ran but did not complete it answers {"msg": "result", "ok": false, "reason": "...", "detail": {...}}. The reason is written to be useful: it says what the server saw, not just that you failed.

Data, on UDP

Exactly packet.py, with no additions:

type seq means
0 DATA which packet this is, from 0
1 ACK cumulative for -gbn ("I have everything before seq"), individual for -sr ("I have seq")
2 FIN how many data packets the sender sent
3 FINACK the receiver has everything and is closing

Two things to know:

  • A FINACK may carry a payload. packet.py has always allowed it and nothing else in this project uses it. In challenge A the server puts your flag there, so the flag arrives in band, on the data channel, as well as on the control channel. challenge.py keeps it for you and prints it in the trace as finack_payload.
  • The path is deliberately awkward. The server drops about 5% of what it sends, duplicates about 3%, and holds about 5% back to arrive late. This is the same set of impairments channel.py simulates offline, so a protocol that passes selfcheck.py should survive it. The seed comes from your student id, so your run is reproducible if you want to dispute a result.

What the server is, and is not

It is a correct implementation of the receiver and the sender for both protocols, written from P&D 2.5 and not from your code. That is the whole point of Stage 2: selfcheck.py tests your sender against your receiver, and two halves written by the same person can agree with each other about a mistake.

It is not a grader. It does not see your source, and it has no opinion about your style. It answers one question: does your half interoperate with a half you did not write?