The first Rust implementation of the Licklider Transmission Protocol (LTP, RFC 5326) — the retransmission-based reliable transport NASA uses between planets.
⚠️ Experimental — not flight software. A faithful, well-tested implementation intended for research, testbeds, and as the missing LTP convergence layer for the Rust DTN ecosystem — not for operational spacecraft.
LTP is the standard convergence layer under the Bundle Protocol (BPv7, RFC 9171) in delay-tolerant networks: links with round-trip times of minutes to hours, scheduled intermittent connectivity, and possibly one-way channels. That means no handshakes, no negotiation, massive concurrent state retention, and retransmission timers that are suspended during known link outages.
Named after J. C. R. Licklider, who imagined an "Intergalactic Computer Network".
licklider-core is a sans-I/O protocol engine — no sockets, no clocks, no
threads, no async. You feed it events with an explicit timestamp and drain its
outputs; it is a pure state machine. This is the quinn-proto / smoltcp / str0m
pattern, and it is what makes interplanetary-scale testing tractable: a
40-minute Earth–Mars round trip is simulated by advancing a mock clock, so the
full retransmission and outage-suspension logic runs in milliseconds.
flowchart LR
subgraph driver["driver (licklider-udp / simulator / your runtime)"]
SOCK[UDP socket / SimLink]:::io
CLOCK[clock]:::io
APP[client service]:::io
end
subgraph core["licklider-core::Engine — pure state, no I/O"]
direction TB
SESS[session tables]
TT[timer wheel\nsingle deadline]
Q[per-peer queues]
end
SOCK -- "handle_input(now, Segment)" --> core
CLOCK -- "handle_timeout(now)" --> core
APP -- "request_transmission(now, …) → SessionId" --> core
core -- "poll_output(now) → Transmit" --> SOCK
core -- "poll_output(now) → Notice" --> APP
core -- "next_timeout() → Option<Timestamp>" --> CLOCK
classDef io fill:#eef;
| Crate | What it is |
|---|---|
licklider-core |
The sans-I/O engine: SDNV + segment codec, sender/receiver state machines (RFC 5326 §8), timers with outage suspend/resume (§6.5/§6.6). One dependency: bytes. |
licklider-udp |
Tokio UDP link service, wire-compatible with NASA ION's udplso/udplsi: one LTP segment per datagram, port 1113 (IANA ltp-deepspace). |
licklider-cli |
licklider send / licklider recv file transfer with built-in link impairment. |
licklider-sim |
Deterministic two-engine link simulator (virtual clock, seeded loss/dup/reorder, contact plans). The Mars test lives here. Not published. |
| licklider | ION-DTN | HDTN | Unibo-LTP | |
|---|---|---|---|---|
| Language | Rust | C | C++ | C |
| License | MIT OR Apache-2.0 | various (NASA OSA) | NASA OSA | GPL-2.0+ |
| Sans-I/O core | ✅ | ❌ | ❌ | ❌ |
| Async-agnostic | ✅ (core has no runtime) | ❌ | ❌ | ❌ |
| Fuzzed | ✅ (cargo-fuzz, decoder + stateful engine) |
❌ | partial | ❌ |
| Flight-used | ❌ (experimental) | ✅ | ❌ | ❌ |
$ licklider recv --listen 127.0.0.1:1113 --engine 2 --peer 1@127.0.0.1:1114 --out got.bin &
$ licklider send file.bin --to 2@127.0.0.1:1113 --engine 1 --listen 127.0.0.1:1114 \
--red all --impair loss=0.3,dup=0.05,seed=7
INFO sending block bytes=200000 red_len=200000 to=127.0.0.1:1113
INFO session started sid=1/2523736422
INFO initial transmission complete
INFO ✓ transmission complete (red part acknowledged)
$ cmp file.bin got.bin && echo identical
identicalA 200 KB block delivered byte-identically over a link dropping 30 % of
datagrams and duplicating 5 %, purely through LTP checkpoint/report/
retransmission — no external netem required.
cargo test -p licklider-sim --test mars --release -- --nocapture transfers a
10 MiB block across a 4- or 20-minute one-way-light-time link with hour-long
contacts, three-hour outages, and 5 % loss, and prints:
MARS[20min] owlt=20min block=10MiB mtu=1400
complete in 3 contact cycle(s), virtual 8.7h
DS tx 8056 (566 rxmt, 7.6%), RS 36, RA 34
outage emissions: 0 ✓
Zero segments are emitted during an outage; retransmission timers are suspended across the dark and resumed on the next contact — LTP's defining behavior, and the whole reason for the sans-I/O + virtual-clock design.
Every MUST / SHOULD / MAY of RFC 5326 §3–§8, and each of its internal procedures, is tracked in docs/rfc5326-checklist.md against the implementing function and the covering test. Local implementation choices are recorded in DECISIONS.md. Architecture and state diagrams are in docs/ARCHITECTURE.md.
- RFC 5327 authentication — extensions are parsed and skipped only (the cookie extension is prohibited by CCSDS 734.1-B-1 anyway).
- LTP Service Data Aggregation (client service ID 2).
- CCSDS AOS / Encapsulation framing — a
LinkServiceboundary is designed for it; v0.1 ships UDP only. - Session persistence across restarts — in-memory only.
- Congestion control — LTP has none by design; rate control is the link layer's responsibility.
MIT OR Apache-2.0, at your option.