Core Question
Core Question
What does a TCP segment actually carry, and what makes a combination of flags and payload nonsensical before anyone even looks at what state the connection is in?
Outcome
Outcome
By the end of this session, the learner should be able to:
- name the five fields that make up a
Segment - explain why
flagsis afrozenset[str]instead of five booleans or a bitmask - list every way
validate_segment()can reject a segment, and in what order the checks run - explain why "RST carrying a payload" is treated as invalid rather than merely unusual
Read Order
Read Order
- Read
Segment - Read
is_syn/is_ack/is_fin/is_rst - Read
flags_label() - Read
SegmentValidity - Read
validate_segment() - Run
examples/tcp/session_01_walkthrough.py
Read It Like Code
Read It Like Code
Segment(
seq,
ack,
flags,
payload_len,
window,
)Fields That Matter
Fields That Matter
| Field | Why it matters |
|---|---|
seq | The sequence number of the first byte of payload this segment carries (or the control-flag position if there is no payload). |
ack | What the sender has received so far, valid only when the ACK flag is set. |
flags | A frozenset[str] of control bits, e.g. {"SYN", "ACK"}. A set, not five separate booleans, because "which flags are present" is one fact, not five. |
payload_len | How many bytes of data ride along. Zero for pure control segments. |
window | The sender's advertised receive window at the moment this segment was sent. |
Decision Flow
Decision Flow
flags not subset of FLAG_NAMES -> BadFlagName SYN and FIN both present -> SynFinTogether payload_len < 0 -> NegativeLength payload_len > 0 and RST present -> PayloadWithoutSeqMeaning otherwise -> Valid
Reading Lens
Reading Lens
The important move in this session is to stop thinking of a segment as "a packet with some flags on it" and start asking:
- which flags are present, and does that combination mean anything?
- does the payload agree with what the flags say this segment is for?
- is this check about the segment alone, or does it need the connection's state too?
Notice that validate_segment() never looks at a ConnectionState. Everything it checks is a fact about the segment by itself — state-dependent legality is Session 02's problem, not this one's.
Toy Model Boundary
Toy Model Boundary
Real TCP segments carry a checksum, a data offset, options (MSS, window scaling, SACK, timestamps), and urgent-pointer plumbing tied to the URG flag. This toy keeps only the five fields that the rest of the course actually reasons about: seq, ack, flags, payload_len, window. FLAG_NAMES is deliberately just {SYN, ACK, FIN, RST} — no URG, no PSH, no ECE/CWR — because those four are what drive every state transition in Session 02.
payload_len is an integer count, not real bytes. The toy never constructs an actual payload buffer, because the reading target here is what the length means, not how to move bytes.
Code Landmarks
Code Landmarks
Segment
A frozen dataclass. Once built, a segment cannot be mutated — which matters because Session 02 passes segments around and builds replies from their fields without ever needing to worry that a segment changed underneath it.
is_syn / is_ack / is_fin / is_rst
Four one-line predicates, each just a membership test on flags. Small enough to not need comments, and every other module in this track calls them instead of touching segment.flags directly.
flags_label()
Renders flags in "the conventional wire order" (SYN, ACK, FIN, RST), not set-iteration order. A frozenset has no order of its own — this function is where the human-readable rendering imposes one.
validate_segment()
The main reading target. Four early-return checks, evaluated in a fixed sequence. Notice the check order: an unknown flag is rejected before the SYN+FIN check even runs, and negative length is rejected before the RST-payload check.
Failure Questions
Failure Questions
Use the source file to answer these:
- A segment has
flags=frozenset({"SYN", "FIN", "URG"}). WhichSegmentValiditycomes back, and why does that check win over the SYN+FIN check? - Why is
payload_len < 0treated as a distinct validity outcome frompayload_len > 0on an RST, instead of being folded into the same check? - Is a segment with
flags=frozenset()andpayload_len=0valid? Tracevalidate_segment()to confirm. - Does
validate_segment()reject a segment withackset but no ACK flag present? Read the function body to be sure, not the docstring. - Why does an RST with
payload_len=0pass validation, but the same RST withpayload_len=1fail?
Walkthrough
Walkthrough
Run this:
PYTHONPATH=src python3 examples/tcp/session_01_walkthrough.py
The walkthrough builds one valid control segment, one valid data segment, and one segment for each of the four ways validate_segment() can reject input, then checks flags_label() renders in wire order.
Done When
Done When
The learner can say all of the following without looking at notes:
- "A segment is five fields — flags is a set of names, not a bitmask I have to decode."
- "Validity is checked before state; SYN+FIN together is always wrong, no matter what state the connection is in."
- "An RST carrying a payload is rejected because a reset has no sequence meaning for data it claims to carry."
References
References
- RFC 9293 Section 3.1 (Header Format)
- RFC 9293 Section 3.4 (Sequence Numbers — payload/control-flag sequence semantics)
- RFC 9293 Section 3.8.6 (Managing the Window — the
windowfield this segment carries)
Continue