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
//! Connection admission barrier (post-allowlist).
//!
//! After the server admits a peer — its node-id is on the allowlist — it opens a bi-stream and
//! writes a single ADMIT byte; the client awaits it. This is **not** authentication:
//! the peer's node-id is already authenticated by iroh's QUIC/TLS handshake, and the allowlist is the
//! authorization gate. The ack exists only as a synchronization point so the **client** can cleanly
//! distinguish "admitted" from a deliberate server rejection (which closes the connection). Without
//! it a rejected client would re-dial in the reconnect loop forever instead of failing fast with the
//! server's close reason.
//!
//! Stream direction is deliberate: the **server opens** the bi-stream and the **client accepts** it —
//! inverting that deadlocks both sides on their `*_bi()` calls.
use io;
use Connection;
/// The single byte the server writes once a peer is authorized.
const ADMIT: u8 = 1;
/// Errors awaiting admission on the client.
/// Server side: signal admission after the allowlist check passes.
///
/// Fast in the common case (opening a QUIC stream and buffering one byte), but `open_bi()` can wait
/// on stream-flow-control credit, so a stalling client is bounded by the caller's own short timeout
/// (`koh serve`'s 3s admission deadline in `server::cli`), not relied on to never block.
pub async
/// Client side: await the server's admission ack. A closed connection (the server rejected us) or a
/// missing/unexpected byte surfaces as an error the caller turns into a clean "not authorized".
pub async