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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
//! TLS client for Seq.
//!
//! Wraps a connected `may::net::TcpStream` in a `rustls::ClientConnection`
//! and stores the result in the shared `STREAMS` registry as
//! `StreamKind::Tls`. Existing `net.tcp.read` / `net.tcp.write` /
//! `net.tcp.close` builtins dispatch over the `StreamKind` enum
//! transparently — the user upgrades a Socket and keeps using it.
//!
//! ## Surface
//!
//! `net.tls.client ( Socket String -- Socket Bool )` — consumes a
//! connected TCP socket and a hostname, returns the *same* Socket id
//! now pointing at a TLS-wrapped stream. The hostname drives SNI and
//! webpki certificate validation; trust roots come from `webpki-roots`.
//!
//! ## Handshake timing
//!
//! Eager: the handshake completes inside this builtin via
//! `conn.complete_io(&mut tcp)`. A bad cert, expired cert, hostname
//! mismatch, or any other TLS-layer error surfaces as
//! `(0, false)` — matching the way every other fallible Seq
//! networking word reports failure. A subsequent `net.tcp.read` reads
//! application data only.
//!
//! ## Known limitations (v1)
//!
//! - `net.tcp.close` on a TLS-wrapped socket is a *hard* close — the
//! underlying `TcpStream` is dropped without first sending the TLS
//! `close_notify` alert. RFC 5246 expects clients to send the alert
//! before closing; modern servers tolerate truncation but some older
//! stacks log it as a truncation-attack indicator. A graceful-shutdown
//! variant is a planned follow-up.
//! - No client-certificate authentication (mTLS).
//! - No caller-side ALPN selection — rustls defaults apply.
//! - No way to inspect the negotiated cipher / peer certificate from
//! Seq. Planned follow-ups once the four-layer stack stabilises.
use crateConn;
use crate;
use crate;
use crateValue;
use ServerName;
use ;
use ;
/// Process-wide TLS client config. Trust roots are the Mozilla CA
/// bundle shipped by `webpki-roots`; the `ring` crypto provider is
/// installed defensively here so we don't depend on rustls's
/// crate-features auto-install — if any transitive dep ever enables
/// `aws_lc_rs` alongside `ring`, the auto-install path would panic at
/// first use ("multiple default providers"). Cached for the process
/// lifetime — the `Arc<ClientConfig>` is cheap to clone into each
/// handshake.
static TLS_CONFIG: = new;
/// Upgrade a connected Socket to TLS.
///
/// Stack effect: `( Socket String -- Socket Bool )` — top of stack
/// is the hostname (String), with the existing TCP socket id beneath
/// it. On success, returns `(socket_id, true)` where `socket_id` is
/// the *same* id the caller passed in: the registry slot is upgraded
/// in place from `Tcp` to `Tls`, so any caller-side data structures
/// keyed on the socket id remain valid. On failure (empty hostname,
/// type mismatch, wrong-kind socket, handshake error, no slot found),
/// returns `(0, false)`; on the failure paths that already took the
/// stream out of the registry, the underlying socket is closed (the
/// `TcpStream` is dropped) and the slot is freed.
///
/// # Safety
/// Stack must have a String (hostname) on top of a Socket (Int).
pub unsafe extern "C"
/// Take the underlying TcpStream out of STREAMS at `id`, only if the
/// slot holds a `Tcp` variant. A `Tls` variant or empty slot
/// short-circuits to `None`; a wrong-kind variant is restored so
/// `tls.client` on a TLS socket doesn't accidentally destroy it.
///
/// On `Some` return, the slot at `id` is left holding `None` (i.e.
/// reserved for the caller). The caller MUST either reinstall a
/// value into that slot or call `free(id)`.
/// Build a fully-handshaked TLS stream over `tcp`. The TCP stream is
/// consumed regardless of outcome — on Err, it is dropped (which
/// closes the socket). The hostname is moved in: rustls's
/// `ServerName<'static>` takes an owned `String`, so threading the
/// caller's owned hostname through avoids a redundant clone.
/// Variant of `build_tls` exposed to the HTTP client. Returns the
/// handshaked stream already type-erased as `Conn` (a
/// `Box<dyn HttpStream + Send>`).
///
/// Why erase here: the `Box::new(stream) as Conn` cast emits the
/// vtable for `dyn HttpStream` over `StreamOwned<ClientConnection,
/// TcpStream>`, and *that* vtable references rustls's drop chain.
/// Keeping the cast inside `tls.rs` means the vtable is reachable
/// only via `dial_tls`, which is itself reachable only via the HTTP
/// client's HTTPS path. When no Seq program reaches that path,
/// `--gc-sections` strips the vtable and the rustls drop chain
/// disappears from the binary. The HTTP client never holds a
/// concretely-typed TLS stream — it only ever sees `Conn`.
pub
unsafe