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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! Opening the TCP socket, the mutual-TLS handshake and `HELLO`/`WELCOME` exchange,
//! and the settings UI's standalone "Test connection" operation built on top of it.
use ;
use crateWorkerSettings;
use ;
use ;
/// # Known cost, measured, and what was done about it
///
/// This function's full cost (three file reads, building a `rustls::ClientConfig`, TCP
/// connect, TLS 1.3 handshake, `HELLO`/`WELCOME`) measured end-to-end on loopback
/// against a real worker: ~2.5ms median, ~2.6ms mean, dominated by the TCP connect (1
/// RTT) and TLS handshake (1 more RTT) -- so on a link with `R` ms of RTT, expect
/// roughly this total plus `~2R` ms.
///
/// On loopback/LAN this is noise next to the render itself and the 600ms
/// `SETTLE_DEBOUNCE` gating every dispatch. But higher-latency links (a remote worker
/// over a slower connection) are a real deployment target, and on one of those `~2R` ms
/// per settle is a user-visible stall before the first `FRAME`, repeated on every
/// drag-then-pause. That is why `super::persistent::spawn_remote_connection` exists: it
/// lets `gui::remote::orchestrator` hold one connection open across a whole live session
/// and pay this cost once. `super::one_shot::spawn_remote_render` (this function's other
/// caller, along with [`test_connection`]) stays one connection per call, for callers
/// where that repetition doesn't apply.
///
/// Resolves `address` (a `host:port` string) and connects with a bounded deadline
/// ([`super::CONNECT_TIMEOUT`]), then configures the socket for a long-lived,
/// latency-sensitive, bidirectional protocol connection:
///
/// - `TCP_NODELAY` -- a `RenderRequest`/`CANCEL`/stream-event frame must never sit in
/// Nagle's buffer waiting for more data that isn't coming; this protocol's messages are
/// sent one at a time; not batched.
/// - OS-level TCP keepalive ([`super::KEEPALIVE_TIME`]/[`super::KEEPALIVE_INTERVAL`], via
/// the `socket2` crate -- `std::net::TcpStream` has no keepalive-tuning API of its own)
/// so a network-level dead peer is noticed by the kernel even while nothing above this
/// layer is trying to read or write.
///
/// # Errors
///
/// Any I/O error resolving `address` (including "no address found" for a string that
/// doesn't resolve to anything), connecting within [`super::CONNECT_TIMEOUT`], or
/// configuring the socket.
/// Connects to `worker.address` over mutual TLS (certificates from `worker.cert_dir`)
/// and performs the `HELLO`/`WELCOME` handshake, including
/// [`indicatrix_net::handshake::verify_compatible`]'s client-side defense-in-depth
/// check. Shared by `super::one_shot::run` (a full render), [`test_connection`]
/// (handshake only), and, `pub(crate)`, by `bridge::library::client` (the read-only
/// design-library protocol rides the same authenticated connection) -- so every caller
/// connects identically.
///
/// The returned stream carries [`super::WRITE_TIMEOUT`] for the rest of its life and,
/// past this function's [`super::HANDSHAKE_TIMEOUT`]-bounded read, no read timeout at
/// all -- callers set their own afterward (`super::one_shot::run`'s/
/// `super::persistent::run_connection`'s poll-timeout reads via
/// `super::stream_io::try_read_one_frame`, or `bridge::library::client`'s longer,
/// static one).
///
/// # `ErrorKind::WriteZero` is a real I/O failure here, not a partial-write retry signal
///
/// `rustls::Stream::write`'s `complete_io` can fail (a write timing out against
/// [`super::WRITE_TIMEOUT`]), but its public signature surfaces that as plain
/// `WriteZero` rather than the underlying `TimedOut`. Every write-error site in this
/// module (and `bridge::library::client`) already treats any error as fatal without
/// matching a specific `ErrorKind`, so this is handled correctly -- noted here so a
/// future reader chasing a `WriteZero` in a log doesn't go looking for an actual
/// zero-length write bug.
///
/// # Errors
///
/// See [`RemoteError`]'s variants.
/// The settings UI's "Test connection" operation: connect, handshake, report worker
/// identity/backend/build compatibility, then disconnect (simply by dropping the
/// stream when this returns) -- no render. Blocking; callers run this on their own
/// worker thread (see `gui::remote::setup_worker_callbacks`) and report the result back
/// to the UI thread themselves.
///
/// # Errors
///
/// See [`RemoteError`]'s variants.