///|
/// A 32-bit TCP sequence number.
///
/// Sequence numbers wrap, so they cannot be compared with `<`. Two numbers on
/// opposite sides of the wrap point are "close" to each other even though their
/// numeric distance is enormous, and an implementation that compares them as
/// plain integers works perfectly until the day it does not. All comparisons go
/// through `before`, which measures the distance in the wrapping space where
/// half the space is "ahead" and half is "behind".
pub(all) struct Seq {
value : UInt
} derive(Eq, Debug)
///|
/// Half of the sequence space, the boundary between "ahead" and "behind".
let seq_half : UInt = 0x80000000U
///|
pub fn Seq::of(value : UInt) -> Seq {
{ value, }
}
///|
/// True when `self` comes before `other` in the wrapping sequence space.
pub fn Seq::before(self : Seq, other : Seq) -> Bool {
let distance = other.value - self.value
distance > 0U && distance < seq_half
}
///|
/// True when `self` comes after `other`.
pub fn Seq::after(self : Seq, other : Seq) -> Bool {
other.before(self)
}
///|
/// Advance by `length` bytes, wrapping like real TCP.
pub fn Seq::advance(self : Seq, length : Int) -> Seq {
{ value: self.value + length.reinterpret_as_uint(), }
}
///|
/// Signed distance from `self` to `other`, in bytes.
pub fn Seq::distance_to(self : Seq, other : Seq) -> Int {
(other.value - self.value).reinterpret_as_int()
}
///|
pub fn Seq::to_string(self : Seq) -> String {
self.value.to_string()
}
///|
/// The control bits a segment carries.
pub(all) struct Flags {
syn : Bool
ack : Bool
fin : Bool
rst : Bool
} derive(Eq, Debug)
///|
/// A segment with no control bits set: a plain data segment.
pub fn Flags::data() -> Flags {
{ syn: false, ack: false, fin: false, rst: false, }
}
///|
pub fn Flags::syn() -> Flags {
{ syn: true, ack: false, fin: false, rst: false, }
}
///|
pub fn Flags::syn_ack() -> Flags {
{ syn: true, ack: true, fin: false, rst: false, }
}
///|
pub fn Flags::ack() -> Flags {
{ syn: false, ack: true, fin: false, rst: false, }
}
///|
pub fn Flags::fin_ack() -> Flags {
{ syn: false, ack: true, fin: true, rst: false, }
}
///|
/// How many sequence numbers this segment consumes. SYN and FIN each occupy one
/// position in the sequence space even though they carry no payload; forgetting
/// that is the classic off-by-one that makes a handshake appear to work and the
/// first data segment appear to be missing one byte.
pub fn Flags::sequence_length(self : Flags, payload : Int) -> Int {
let mut length = payload
if self.syn {
length = length + 1
}
if self.fin {
length = length + 1
}
length
}
///|
pub fn Flags::render(self : Flags) -> String {
let parts : Array[String] = []
if self.syn {
parts.push("SYN")
}
if self.ack {
parts.push("ACK")
}
if self.fin {
parts.push("FIN")
}
if self.rst {
parts.push("RST")
}
if parts.length() == 0 {
"DATA"
} else {
parts.join("+")
}
}
///|
/// A TCP segment.
///
/// `window` is what the sender of this segment is willing to receive from now
/// on, in bytes: flow control is carried on every segment, including pure ACKs,
/// so a receiver that frees buffer space can always tell the peer about it.
pub(all) struct Segment {
seq : Seq
ack : Seq
window : Int
flags : Flags
payload : Bytes
/// The identity of this segment for the purpose of loss.
///
/// It is derived from what the segment is — its starting sequence number and
/// how many times that segment has been sent — rather than from when it was
/// sent. A link that has decided to lose a packet identity would lose every
/// repetition of it, so the transmission count has to be part of the
/// identity; without it a lost segment could never be recovered.
///
/// Zero means "no identity", which is what acknowledgments carry: the same
/// acknowledgment is sent many times over, so it has no stable identity and
/// the link falls back to its own stream.
tag : UInt64
} derive(Debug)
///|
pub fn Segment::new(
seq : Seq,
ack : Seq,
window : Int,
flags : Flags,
payload : Bytes,
tag : UInt64,
) -> Segment {
{ seq, ack, window, flags, payload, tag, }
}
///|
/// A TCP header is 20 bytes when it carries no options. This simulator has no
/// options yet, so the number is exact rather than approximate.
pub fn header_bytes() -> Int {
20
}
///|
/// The number of bytes this segment occupies on the wire.
pub fn Segment::wire_size(self : Segment) -> Int {
header_bytes() + self.payload.length()
}
///|
/// Bytes of payload in this segment.
pub fn Segment::payload_length(self : Segment) -> Int {
self.payload.length()
}
///|
/// A compact label used in journals, for example `SYN+ACK seq=1000 ack=4001`.
pub fn Segment::label(self : Segment) -> String {
self.flags.render() +
" seq=" +
self.seq.to_string() +
" ack=" +
self.ack.to_string() +
" len=" +
self.payload.length().to_string() +
" win=" +
self.window.to_string()
}