The Handshake
Stardate 55169.9 ยท UES Magnanimous
Briefing
The other computer wants to talk properly now, and properly means framed messages: a fixed prefix, the message length, the message, and a checksum, pipes between. It will reject a frame with the wrong prefix, a length that does not match, or a checksum that does not add up, and it will say nothing about why, because it is a computer, and a computer from nineteen years in the future at that.
Chief T'Kala wants both directions: frame a message for sending, and unframe one for receiving, refusing anything malformed. Because the length is in the frame, a message may itself contain pipes and still come back whole. The checksum is the sum of the message's bytes, modulo 256, as two hex digits. Eight objectives. Lt. Skree has pointed out that if we get this wrong the other ship simply says nothing, "which is what it has mostly done, so we would not know". This is true and unhelpful.
Mission objectives
ARCHIE checks all eight every time you run diagnostics.
- โขchecksum: the byte sum modulo 256, as two lower-case hex digits
- โขchecksum: an empty message is 00
- โขframe: 'MAGN|<length>|<message>|<checksum>'
- โขunframe: a good frame gives back the message
- โขunframe: a message containing pipes survives the round trip
- โขunframe: a wrong prefix is refused
- โขunframe: a length that does not match is refused
- โขunframe: a corrupted checksum is refused
Objective
Three functions:
checksum(message): sum of the message's UTF-8 bytes modulo 256, as two lower-case hex digits, e.g."7f".frame(message):f"MAGN|{len(message)}|{message}|{checksum}", where the length is the number of characters.unframe(text): the message from a well-formed frame, orNoneif the prefix is notMAGN, the length field does not match the message, or the checksum does not match.
Press Run Diagnostics and I will tell you which objectives you actually met.
Objective
Three functions:
checksum(message: &str) -> String: sum of the message's UTF-8 bytes modulo 256, as two lower-case hex digits, e.g."7f".frame(message: &str) -> String:"MAGN|{length}|{message}|{checksum}", where the length is the number of characters.unframe(text: &str) -> Option<String>: the message from a well-formed frame, orNoneif the prefix is notMAGN, the length field does not match the message, or the checksum does not match.
Press Run Diagnostics and I will tell you which objectives you actually met.
Ask Commander Raghunathan for a hint
Split on the pipe at most three times, so the message keeps its own pipes: prefix, length, then the rest, and the checksum is the last field of the rest. Use the declared length to cut the message out of the rest exactly. Refuse on any check that fails, and only then recompute the checksum and compare.
Debrief
The handshake completes. The other computer sends one frame, checksum correct, and the message is a personnel file. Commander Priya Raghunathan. Shore leave: granted, 55170.3. Tomorrow. Filed nineteen years ago on a ship that had just replaced a manifold seal by hand, by a version of her who had four minutes to spare and used them for this. She has read it. She has said "oh". She has sat down.
Away mission: make it a real protocol. Write a tiny server that
accepts framed messages over a local socket (Python's socket, Rust's
std::net), unframes them, and replies with a framed acknowledgement, and a
client that sends three messages including one deliberately corrupted. Watch the server
refuse it. Then swap the checksum for a real hash and notice how little else changes.