69 lines
3.4 KiB
Markdown
69 lines
3.4 KiB
Markdown
# 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?
|