1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! # koh-ssp — State Synchronization Protocol
//!
//! A faithful Rust port of mosh's SSP, retargeted onto QUIC unreliable datagrams.
//!
//! The protocol's only job is to bring the peer to the *latest* version of an
//! authoritative object. Intermediate states are collapsed and discarded — if the
//! object changed 100 times in 40ms, only the final state is transmitted. This is the
//! source of mosh's instant recovery, lossy-link responsiveness, and absence of
//! head-of-line blocking.
//!
//! ## What this module is (and isn't)
//!
//! [`Transport`] is a **pure state machine**. It owns no sockets, no clock, no async.
//! The caller (the iroh driver, or a test harness) supplies the current time in
//! milliseconds and the path RTT, calls [`Transport::tick`] to get datagrams to send,
//! and feeds inbound datagrams to [`Transport::recv`]. This makes the whole protocol
//! deterministically testable under simulated loss/latency/reordering — see [`testkit`].
//!
//! ## The transport-layer division of labor (vs. mosh)
//!
//! QUIC/iroh subsumes mosh's UDP framing, OCB crypto, key exchange, roaming, NAT
//! traversal, heartbeats, and RTT measurement. This module keeps only what lives *above*
//! the wire: the `sent_states`/`received_states` collapse logic, the `tick()` send
//! scheduler, the seq/ack/throwaway envelope, and fragmentation (in [`wire`](crate::wire)).
use DeserializeOwned;
use Serialize;
pub use RttEstimator;
pub use ;
/// `u64::MAX` doubles as both the "never" deadline and the shutdown state sentinel,
/// exactly as mosh uses `uint64_t(-1)`.
pub const NEVER: u64 = u64MAX;
/// The state number that signals a clean shutdown (`uint64_t(-1)` in mosh).
pub const SHUTDOWN_SENTINEL: u64 = u64MAX;
// --- scheduler constants (mosh `transportsender.h`, milliseconds) ---
// `pub(crate)`: internal SSP tuning knobs, referenced only within `src/ssp`; not public API.
/// Floor on the inter-frame interval.
pub const SEND_INTERVAL_MIN: u64 = 20;
/// Ceiling on the inter-frame interval.
pub const SEND_INTERVAL_MAX: u64 = 250;
/// Interval between empty keep-alive acks when otherwise idle.
pub const ACK_INTERVAL: u64 = 3000;
/// Delay before a coalesced data-ack is flushed.
pub const ACK_DELAY: u64 = 100;
/// Minimum coalescing window for a burst of new input before sending.
pub const SEND_MINDELAY: u64 = 8;
/// Stop retransmitting if the peer has been silent this long (it may be roaming).
pub const ACTIVE_RETRY_TIMEOUT: u64 = 10_000;
/// Shutdown sentinel resends before giving up.
pub const SHUTDOWN_RETRIES: u32 = 16;
/// `sent_states` queue cap; the 16th-from-end is dropped when exceeded.
pub const SENT_STATES_CAP: usize = 32;
/// Hard ceiling on the number of retained `received_states` (anti-accumulation).
///
/// Inbound states beyond this are refused outright (not merely rate-limited), so a hostile peer
/// that pins `old_num`/`throwaway_num` to prevent collapse cannot grow the list without bound
/// (KOH-01). The per-state-type [`SyncState::RECEIVE_BUDGET_UNITS`] is the companion byte bound.
pub const RECEIVED_STATES_CAP: usize = 1024;
/// A synchronizable object: the unit the protocol keeps in sync.
///
/// Implementors are the screen ([`terminal`](crate::terminal)) and the user-input stream
/// ([`input`](crate::input)). The contract mirrors mosh's `MyState`/`RemoteState`:
///
/// - [`diff_from`](SyncState::diff_from): produce the delta that transforms `base` into `self`.
/// - [`apply`](SyncState::apply): mutate `self` by applying a delta.
/// - [`subtract_prefix`](SyncState::subtract_prefix): physically drop an already-acked
/// prefix from storage (an optimization; the default no-op is always *correct* because
/// diffs are computed from explicit base states).
///
/// ## The round-trip law every implementor must satisfy
///
/// The delta goes *base → self*, so for any `base, target`:
/// `let mut c = base.clone(); c.apply(&target.diff_from(&base)); assert_eq!(c, target);`