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
131
132
133
134
135
//! **The version preface** (yog's `docs/REMOTE.md` §3, §3.2): *"each end
//! writes one frame ... before it reads the peer's."* Both write before either
//! reads, so neither waits on the other and there is no ordering rule to
//! remember. The frame carries two keys — `protocol`, the major, compared for
//! equality; and `edition`, what the writer can spell within it, discovered
//! and never compared.
//!
//! **This is why thrall exists as a separate program and it is not decoration.**
//! Until the four-component split one crate shipped both ends of every
//! connection and the wire could not skew. A foot is installed on a box the
//! engine's operator may not administer, upgraded on that box's own schedule —
//! so the day the two disagree about what a frame means is a day that will
//! arrive, and it must arrive as a sentence rather than as a gesture answered
//! wrongly.
//!
//! **thrall writes and confirms; it never admits.** A foot dials and is never
//! dialled, so there is exactly one half of the exchange here. The engine's
//! half — refusing a peer in band on the connection it opened — is the
//! server's, and a foot that carried it would be a foot that listens.
//!
//! **A mismatch is fail-closed and the refusal names both versions**, which is
//! REMOTE §3's requirement rather than a nicety: the sentence *is* the upgrade
//! prompt, so it must name a number an operator can act on. There is no
//! negotiation, no version list and no compat shim — negotiation is the
//! mechanism that makes every later version carry every earlier one's shape
//! forever, and the operator who installed both ends can upgrade the older one.
//!
//! **And a preface that ARRIVED is told apart from one that never did**
//! (bl-5d62). REMOTE §3 collapses them on the *engine's* side, and rightly: a
//! peer of the wrong version and a peer that hung up mid-preface are both peers
//! it cannot serve, so one sentence answers both. A foot is deciding a
//! different question — whether dialling again could help — and there the two
//! part. A frame this end read and could not agree with is a fact about the two
//! *binaries*: it will say the same thing on every dial until somebody installs
//! a new one, so it is [`Failure::Skew`] and it ends the channel. A preface that
//! never came is an engine restarting, a socket dying, a box waking up — the
//! wire, [`Failure::Wire`], and dialled again. The SENTENCE stays one sentence
//! either way; what differs is only what this foot does next.
//!
//! Under the old reading a foot that met a version bump wrote a line into its
//! operator's journal every minute forever, and one that met a restarting
//! engine was indistinguishable from it.
use ;
use ;
use ;
/// The engine's three numbers, vendored.
pub use ;
/// The preface's first key: the major, compared for equality.
const KEY: &str = "protocol";
/// Its second key (REMOTE §3.2): what the peer can spell within that major.
/// Unlike [`KEY`] it is never compared — an edition is discovered, not agreed.
const EDITION_KEY: &str = "edition";
/// What a peer that stated no version is called in the sentence. An unversioned
/// build, a frame that is not an object, a frame without the key and a peer
/// that hung up mid-preface are one case on purpose: none of them can be
/// served, and four sentences for one outcome is four sentences.
const UNSTATED: &str = "no version";
/// Write this build's preface: the major, and the edition beside it. Called
/// before this end reads, which is what makes the exchange deadlock-free
/// without an ordering rule.
///
/// **Both ends write the edition** (REMOTE §3.2), so the key is stated even
/// though nothing at the far end has to read it — a peer that ignores it is
/// exercising rule 1, which is the same rule this end keeps on the way back.
/// Read the engine's preface and refuse a mismatch — as the one `Err(String)`
/// every other thing that can go wrong with this transport already arrives as,
/// so nothing above here carries a case for it.
///
/// **What it answers is the engine's EDITION** (REMOTE §3.2): the fact that
/// says which post-floor fields that engine can spell. A foot reads no
/// post-floor field today — every path in its vendored ledger is at or under
/// the floor — so nothing above gates on the answer yet; it is decoded here
/// rather than ignored because the defaulting is the rule, and a rule nothing
/// returns is a rule nothing can test.
/// **The peer's edition, defaulted at the [`FLOOR`]** — for an absent key, and
/// for a value that is not an edition.
///
/// The absent case is REMOTE §3.2's rule; the unreadable case takes the same
/// answer rather than a refusal, because the fail-closed equality is the
/// MAJOR's and this key is not part of it. Reading a garbled edition as the
/// floor credits the peer with the least it can be spelling, which is the
/// direction that cannot invent a capability.
/// **The peer's preface frame, if one came at all.** `None` is the wire: a read
/// that failed, or a stream that ended where a frame belongs. Anything this
/// end managed to read is a frame the peer deliberately wrote, whatever it
/// says.
/// The refusal: both versions, and what to do about it.