@amritk/nish-x86_64-linux 0.17.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +43 -25
- package/bin/nish +0 -0
- package/package.json +2 -2
- package/runtime/nish.d.ts +55 -5
- package/runtime/nish.h +231 -20
- package/runtime/nish.mjs +16 -0
- package/runtime/runtime-aes.c +490 -0
- package/runtime/runtime-cross.c +366 -0
- package/runtime/runtime-host.c +7 -6
- package/runtime/runtime-net.c +93 -34
- package/runtime/runtime-os.c +213 -15
- package/runtime/runtime-parallel.c +590 -107
- package/runtime/runtime-simd.c +203 -0
- package/runtime/runtime-wasm.c +16 -3
- package/runtime/runtime.c +89 -23
- package/runtime/shim.mjs +71 -1
- package/scripts/build.sh +225 -20
- package/std/README.md +86 -55
- package/std/bytes.ts +163 -0
- package/std/crypto/LICENSE-libsecp256k1 +19 -0
- package/std/crypto/aes.ts +238 -76
- package/std/crypto/chacha20poly1305.ts +43 -9
- package/std/crypto/ed25519.ts +840 -0
- package/std/crypto/hkdf.ts +304 -12
- package/std/crypto/hmac.ts +245 -53
- package/std/crypto/p256.ts +1376 -42
- package/std/crypto/x25519.ts +55 -37
- package/std/crypto/x509-random.ts +71 -0
- package/std/crypto/x509.ts +9 -9
- package/std/json-tokenizer.ts +1296 -0
- package/std/json-typed.ts +1014 -0
- package/std/json-value.ts +1163 -0
- package/std/json.ts +1412 -70
- package/std/net/buffer-pool.ts +151 -0
- package/std/net/hpack.ts +416 -112
- package/std/net/http-fields.ts +93 -0
- package/std/net/http1-server.ts +417 -55
- package/std/net/http1.ts +31 -6
- package/std/net/http2-tls.ts +112 -24
- package/std/net/http2.ts +333 -75
- package/std/net/http3-server.ts +231 -45
- package/std/net/http3.ts +187 -28
- package/std/net/prefork.ts +412 -0
- package/std/net/quic-conn-params.ts +86 -16
- package/std/net/quic-listener.ts +576 -219
- package/std/net/quic-packet.ts +443 -58
- package/std/net/quic-recovery.ts +361 -30
- package/std/net/quic-stream.ts +434 -28
- package/std/net/quic.ts +922 -206
- package/std/net/router.ts +676 -0
- package/std/net/tls/codec.ts +426 -27
- package/std/net/tls/record-server.ts +478 -132
- package/std/net/tls/record.ts +133 -42
- package/std/net/tls/schedule.ts +464 -55
- package/std/net/tls/ticket.ts +610 -0
- package/std/net/tls-tcp.ts +204 -57
- package/std/net/tls.ts +1132 -305
- package/std/net/url.ts +571 -0
- package/std/random.ts +94 -0
- package/std/text.ts +77 -0
- package/std/threads.ts +438 -14
package/std/net/tls-tcp.ts
CHANGED
|
@@ -26,13 +26,20 @@
|
|
|
26
26
|
* stops asking to be written. An event with the hang-up bit (4) goes to
|
|
27
27
|
* `readable`, which is where a closed or failed socket is noticed.
|
|
28
28
|
*
|
|
29
|
-
* **Slots,
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
29
|
+
* **Slots, built on first use; record buffers, borrowed.** The pool's size
|
|
30
|
+
* is a cap: the constructor builds no slot, and the first `accept` into a
|
|
31
|
+
* slot builds its handshake state and keys (TLS-3) and keeps them, so a pool
|
|
32
|
+
* sized for its peak costs at start-up only what does not depend on the
|
|
33
|
+
* size. `accept` hands the next connection the slot closed last, or failing
|
|
34
|
+
* that the next never used, and reuses it once the program `close`s it
|
|
35
|
+
* (WP34 N9). The record buffers — the bytes to send, the plaintext waiting
|
|
36
|
+
* for the program, the record being opened and the record being read — are
|
|
37
|
+
* borrowed from pools this server owns while a connection uses the slot, and
|
|
38
|
+
* given back zeroed (`BufferPool.giveSecret`) when it ends, so a free slot
|
|
39
|
+
* holds none of them ("What moves between connections" in
|
|
40
|
+
* `docs/security/tls.md`). When every slot is busy a new connection is
|
|
41
|
+
* accepted and closed at once, so the listener does not stay readable; the
|
|
42
|
+
* program sees `TLS_TCP_POOL_FULL`. Each slot keeps its own `TlsServer`, which `accept` restarts for the connection, so neither the
|
|
36
43
|
* handshake nor application data allocates anything that outlives a call:
|
|
37
44
|
* a thousand connections through one slot leave `Arena.mark()` where the
|
|
38
45
|
* first left it, under every suite (TLS-3 in `docs/security/tls.md`,
|
|
@@ -50,6 +57,15 @@
|
|
|
50
57
|
* borrows for the call, and `signatureInput` / `sign` hand the input out and
|
|
51
58
|
* take any signature back.
|
|
52
59
|
*
|
|
60
|
+
* **Resumption is opt-in, and its keys are the caller's.** After
|
|
61
|
+
* `enableTickets`, a slot whose interest says `TLS_RECORD_TICKET` waits on
|
|
62
|
+
* the program: in the handshake, `resume` reads the ClientHello's tickets
|
|
63
|
+
* under the current and previous ticket keys and a strike register the
|
|
64
|
+
* program lends for the call, and answers the hello resumed or in full; once
|
|
65
|
+
* the connection is open, `issue` seals it one ticket. The pool keeps no
|
|
66
|
+
* ticket key and no register of its own (`docs/security/tls.md`,
|
|
67
|
+
* "Resumption").
|
|
68
|
+
*
|
|
53
69
|
* `read`, `write` and `close` answer as `nish:net`'s calls do — a count, `0`
|
|
54
70
|
* at the end of the stream, `-11` to wait — so a program written against a
|
|
55
71
|
* plain socket moves over with the `slot` in place of the descriptor.
|
|
@@ -61,14 +77,16 @@
|
|
|
61
77
|
*/
|
|
62
78
|
import { Secret } from "nish:secret"
|
|
63
79
|
import { netClose, netRead, netWrite, tcpAccept } from "nish:net"
|
|
64
|
-
import { TlsServer, TlsServerConfig
|
|
80
|
+
import { TlsP256Signer, TlsServer, TlsServerConfig } from "nish/net/tls"
|
|
65
81
|
import { TLS_ALERT_INTERNAL_ERROR } from "nish/net/tls/codec"
|
|
66
82
|
import { TLS_MAX_RECORD } from "nish/net/tls/record"
|
|
83
|
+
import { TlsTicketKeyInfo, TlsTicketStrikes } from "nish/net/tls/ticket"
|
|
67
84
|
import {
|
|
68
85
|
TLS_RECORD_AGAIN,
|
|
69
86
|
TLS_RECORD_DONE,
|
|
70
87
|
TLS_RECORD_INVALID,
|
|
71
88
|
TLS_RECORD_STATE_FAILED,
|
|
89
|
+
TlsRecordPools,
|
|
72
90
|
TlsRecordServer,
|
|
73
91
|
} from "nish/net/tls/record-server"
|
|
74
92
|
|
|
@@ -95,57 +113,117 @@ const TLS_TCP_ADDRESS_SIZE: i32 = 18
|
|
|
95
113
|
*/
|
|
96
114
|
export class TlsTcpServer {
|
|
97
115
|
config: TlsServerConfig
|
|
98
|
-
/**
|
|
116
|
+
/**
|
|
117
|
+
* The connections built so far, slot `k`'s at `k`: one per slot ever
|
|
118
|
+
* accepted into. `connection` never adds to it; a slot never built reads
|
|
119
|
+
* `vacant` instead.
|
|
120
|
+
*/
|
|
99
121
|
connections: TlsRecordServer[]
|
|
100
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* Each slot's descriptor, or -1 while the slot is free, for the slots
|
|
124
|
+
* accepted into so far: its length is the high-water mark, and a slot past
|
|
125
|
+
* it has never been used.
|
|
126
|
+
*/
|
|
101
127
|
fds: i32[]
|
|
128
|
+
/**
|
|
129
|
+
* The slots closed since they were used, a stack whose top `accept` takes
|
|
130
|
+
* before it builds a slot past the high-water mark, so finding one costs
|
|
131
|
+
* the same with every slot free as with all but one busy.
|
|
132
|
+
*/
|
|
133
|
+
free: i32[]
|
|
102
134
|
/** Where the socket is read into before a connection takes the bytes: the largest record. */
|
|
103
135
|
scratch: u8[]
|
|
104
136
|
/** The last accepted peer's address, in `nish:net`'s 18-byte form. */
|
|
105
137
|
peer: u8[]
|
|
138
|
+
/** Signs every slot's CertificateVerify in `signP256`, one for the pool, keeping nothing per signature. */
|
|
139
|
+
signer: TlsP256Signer
|
|
106
140
|
/**
|
|
107
|
-
* Each slot's own copy of its connection's
|
|
108
|
-
*
|
|
141
|
+
* Each slot's own copy of its connection's server random: `TlsServer`
|
|
142
|
+
* keeps the array it is given and writes it into the ServerHello only once
|
|
143
|
+
* the ClientHello arrives, so the program's array may be refilled for the
|
|
144
|
+
* next one. The ephemeral key needs no copy here: `TlsServer.restart`
|
|
145
|
+
* copies it into the server's own `Secret` and wipes the array it was
|
|
146
|
+
* handed.
|
|
109
147
|
*/
|
|
110
|
-
|
|
148
|
+
randoms: u8[][]
|
|
149
|
+
/** How many slots the pool may hold, which `size` answers. */
|
|
150
|
+
slots: i32 = 1
|
|
151
|
+
/** Whether `enableTickets` has run, so a slot built after it resumes too. */
|
|
152
|
+
tickets: boolean = false
|
|
111
153
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
154
|
+
* What `connection` answers for every slot never built: one failed
|
|
155
|
+
* connection no slot holds and every such slot shares, so the slot reads
|
|
156
|
+
* as a free one does (no ALPN, not open) and never as another slot's live
|
|
157
|
+
* session. Its first read allocates it, once per server; it has no
|
|
158
|
+
* tickets, and a caller must not change it.
|
|
115
159
|
*/
|
|
116
|
-
|
|
160
|
+
vacant: TlsRecordServer | null = null
|
|
161
|
+
/**
|
|
162
|
+
* The pools every slot borrows its record buffers from, each with a
|
|
163
|
+
* ceiling of one per slot: `lent()` is 0 once every connection has ended,
|
|
164
|
+
* and `made()` is the most connections that were ever open at once.
|
|
165
|
+
*/
|
|
166
|
+
pools: TlsRecordPools
|
|
117
167
|
/** The listening socket, which the program made with `tcpListen` and still owns. */
|
|
118
168
|
listener: i32 = -1
|
|
119
169
|
|
|
120
170
|
/**
|
|
121
171
|
* A pool of `size` slots, at least one, serving `config` on `listener`, a
|
|
122
|
-
* socket `tcpListen` made.
|
|
172
|
+
* socket `tcpListen` made. No slot is built here: a slot's handshake state
|
|
173
|
+
* and its server random are allocated by the first `accept` into it and
|
|
174
|
+
* kept, and its record buffers are borrowed from `pools` while a
|
|
175
|
+
* connection uses them, so a pool sized for a peak costs at start-up only
|
|
176
|
+
* the read scratch, the signer and the empty pools.
|
|
123
177
|
*/
|
|
124
178
|
constructor(config: TlsServerConfig, listener: i32, size: i32) {
|
|
125
179
|
this.config = config
|
|
126
180
|
this.listener = listener
|
|
127
181
|
this.connections = []
|
|
128
182
|
this.fds = []
|
|
129
|
-
this.
|
|
183
|
+
this.free = []
|
|
130
184
|
this.randoms = []
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
for (let k: i32 = 0; k < slots; k++) {
|
|
134
|
-
// Each slot's own handshake, refused by `TlsServer` for its empty
|
|
135
|
-
// randomness, so the slot starts out failed until `accept` restarts it
|
|
136
|
-
// for a connection; every later connection reuses its buffers.
|
|
137
|
-
this.connections.push(new TlsRecordServer(new TlsServer(config, none, none)))
|
|
138
|
-
this.fds.push(TLS_TCP_FREE)
|
|
139
|
-
this.keys.push(new Array<u8>(TLS_TCP_KEY_SIZE))
|
|
140
|
-
this.randoms.push(new Array<u8>(TLS_TCP_KEY_SIZE))
|
|
141
|
-
}
|
|
185
|
+
this.slots = size < 1 ? 1 : size
|
|
186
|
+
this.pools = new TlsRecordPools(this.slots)
|
|
142
187
|
this.scratch = new Array<u8>(TLS_MAX_RECORD)
|
|
143
188
|
this.peer = new Array<u8>(TLS_TCP_ADDRESS_SIZE)
|
|
189
|
+
this.signer = new TlsP256Signer()
|
|
144
190
|
}
|
|
145
191
|
|
|
146
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* The next slot's connection and server random, for the slot built next.
|
|
194
|
+
* Called by `accept` alone, as the pool's high-water mark rises: slot `k`'s
|
|
195
|
+
* entry must sit at index `k` of `connections` and `randoms`. Its handshake
|
|
196
|
+
* is never given a ClientHello: `accept` restarts it for a connection with
|
|
197
|
+
* real randomness, and every later connection reuses its state.
|
|
198
|
+
*/
|
|
199
|
+
build(): TlsRecordServer {
|
|
200
|
+
const random: u8[] = new Array<u8>(TLS_TCP_KEY_SIZE)
|
|
201
|
+
this.randoms.push(random)
|
|
202
|
+
const conn: TlsRecordServer = this.make(random)
|
|
203
|
+
if (this.tickets) {
|
|
204
|
+
conn.tls.enableTickets()
|
|
205
|
+
}
|
|
206
|
+
this.connections.push(conn)
|
|
207
|
+
return conn
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* A connection over `random` that is marked failed without sealing an
|
|
212
|
+
* alert, so a stray call on it fails closed, and that borrows no buffer
|
|
213
|
+
* until a connection moves bytes through it.
|
|
214
|
+
*/
|
|
215
|
+
make(random: u8[]): TlsRecordServer {
|
|
216
|
+
// A placeholder key for a first handshake, which never runs.
|
|
217
|
+
const zeros: u8[] = new Array<u8>(TLS_TCP_KEY_SIZE)
|
|
218
|
+
const conn: TlsRecordServer = new TlsRecordServer(new TlsServer(this.config, random, zeros))
|
|
219
|
+
conn.borrowFrom(this.pools)
|
|
220
|
+
conn.state = TLS_RECORD_STATE_FAILED
|
|
221
|
+
return conn
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** How many slots the pool has, built or not. */
|
|
147
225
|
size(): i32 {
|
|
148
|
-
return
|
|
226
|
+
return this.slots
|
|
149
227
|
}
|
|
150
228
|
|
|
151
229
|
/** How many slots hold a connection. */
|
|
@@ -172,11 +250,22 @@ export class TlsTcpServer {
|
|
|
172
250
|
/**
|
|
173
251
|
* The connection in `slot`: its state, its handshake (`tls`: suite, ALPN,
|
|
174
252
|
* server name) and the alerts sent and received. A free slot answers the
|
|
175
|
-
* last connection it held.
|
|
253
|
+
* last connection it held. A slot never accepted into answers `vacant`,
|
|
254
|
+
* failed, as a free slot does, and builds no slot; a slot out of range
|
|
255
|
+
* names slot 0's.
|
|
176
256
|
*/
|
|
177
257
|
connection(slot: i32): TlsRecordServer {
|
|
178
|
-
const
|
|
179
|
-
|
|
258
|
+
const index: i32 = slot >= 0 && slot < this.slots ? slot : 0
|
|
259
|
+
if (index >= 0 && index < toI32(this.connections.length)) {
|
|
260
|
+
return this.connections[index]
|
|
261
|
+
}
|
|
262
|
+
const vacant: TlsRecordServer | null = this.vacant
|
|
263
|
+
if (vacant !== null) {
|
|
264
|
+
return vacant
|
|
265
|
+
}
|
|
266
|
+
const made: TlsRecordServer = this.make(new Array<u8>(TLS_TCP_KEY_SIZE))
|
|
267
|
+
this.vacant = made
|
|
268
|
+
return made
|
|
180
269
|
}
|
|
181
270
|
|
|
182
271
|
/**
|
|
@@ -202,20 +291,25 @@ export class TlsTcpServer {
|
|
|
202
291
|
if (fd < 0) {
|
|
203
292
|
return fd
|
|
204
293
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
294
|
+
// A slot closed before is taken first, then the next never used, so the
|
|
295
|
+
// first accepts take slots 0, 1, 2 ... and a pool that never fills never
|
|
296
|
+
// builds its last slots.
|
|
297
|
+
let slot: i32 = TLS_TCP_POOL_FULL
|
|
298
|
+
if (this.free.length > 0) {
|
|
299
|
+
slot = this.free[this.free.length - 1]
|
|
300
|
+
this.free.pop()
|
|
301
|
+
} else if (toI32(this.fds.length) < this.slots) {
|
|
302
|
+
slot = toI32(this.fds.length)
|
|
303
|
+
this.fds.push(TLS_TCP_FREE)
|
|
211
304
|
}
|
|
212
|
-
if (slot < 0) {
|
|
305
|
+
if (slot < 0 || slot >= toI32(this.fds.length)) {
|
|
213
306
|
netClose(fd)
|
|
214
307
|
return TLS_TCP_POOL_FULL
|
|
215
308
|
}
|
|
309
|
+
const conn: TlsRecordServer =
|
|
310
|
+
slot < toI32(this.connections.length) ? this.connections[slot] : this.build()
|
|
216
311
|
this.fds[slot] = fd
|
|
217
312
|
const random: u8[] = this.randoms[slot]
|
|
218
|
-
const key: u8[] = this.keys[slot]
|
|
219
313
|
for (
|
|
220
314
|
let k: i32 = 0;
|
|
221
315
|
k < TLS_TCP_KEY_SIZE && k < toI32(random.length) && k < toI32(serverRandom.length);
|
|
@@ -223,16 +317,8 @@ export class TlsTcpServer {
|
|
|
223
317
|
) {
|
|
224
318
|
random[k] = serverRandom[k]
|
|
225
319
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
k < TLS_TCP_KEY_SIZE && k < toI32(key.length) && k < toI32(ephemeralPrivate.length);
|
|
229
|
-
k++
|
|
230
|
-
) {
|
|
231
|
-
key[k] = ephemeralPrivate[k]
|
|
232
|
-
}
|
|
233
|
-
secureZero(ephemeralPrivate)
|
|
234
|
-
const conn: TlsRecordServer = this.connections[slot]
|
|
235
|
-
conn.tls.restart(random, key)
|
|
320
|
+
// `restart` copies the key into the server's own `Secret` and wipes this array.
|
|
321
|
+
conn.tls.restart(random, ephemeralPrivate)
|
|
236
322
|
conn.start(conn.tls)
|
|
237
323
|
return slot
|
|
238
324
|
}
|
|
@@ -277,8 +363,15 @@ export class TlsTcpServer {
|
|
|
277
363
|
return this.flush(slot)
|
|
278
364
|
}
|
|
279
365
|
|
|
280
|
-
/**
|
|
366
|
+
/**
|
|
367
|
+
* Writes the connection's output until the socket would block or it is all
|
|
368
|
+
* sent, and answers its `interest`; a slot never built answers
|
|
369
|
+
* `TLS_RECORD_DONE`.
|
|
370
|
+
*/
|
|
281
371
|
flush(slot: i32): i32 {
|
|
372
|
+
if (slot < 0 || slot >= toI32(this.fds.length) || slot >= toI32(this.connections.length)) {
|
|
373
|
+
return TLS_RECORD_DONE
|
|
374
|
+
}
|
|
282
375
|
const fd: i32 = this.fds[slot]
|
|
283
376
|
const conn: TlsRecordServer = this.connections[slot]
|
|
284
377
|
while (conn.outputEnd > conn.outputStart) {
|
|
@@ -315,8 +408,9 @@ export class TlsTcpServer {
|
|
|
315
408
|
|
|
316
409
|
/**
|
|
317
410
|
* Signs `slot`'s CertificateVerify with the P-256 private key `key` and
|
|
318
|
-
* hands it over, as `sign` does
|
|
319
|
-
*
|
|
411
|
+
* hands it over, as `sign` does, through the pool's `TlsP256Signer`, so a
|
|
412
|
+
* handshake's signature keeps nothing. The key is borrowed: the caller made
|
|
413
|
+
* the `Secret`, and wipes it. A malformed key fails the connection with
|
|
320
414
|
* `internal_error`.
|
|
321
415
|
*/
|
|
322
416
|
signP256(slot: i32, key: Secret<u8[]>): i32 {
|
|
@@ -324,7 +418,7 @@ export class TlsTcpServer {
|
|
|
324
418
|
if (input === null) {
|
|
325
419
|
return this.interest(slot)
|
|
326
420
|
}
|
|
327
|
-
const signature: u8[] | null =
|
|
421
|
+
const signature: u8[] | null = this.signer.sign(key, input)
|
|
328
422
|
if (signature === null) {
|
|
329
423
|
this.connections[slot].fail(TLS_ALERT_INTERNAL_ERROR)
|
|
330
424
|
return this.flush(slot)
|
|
@@ -332,6 +426,56 @@ export class TlsTcpServer {
|
|
|
332
426
|
return this.sign(slot, signature)
|
|
333
427
|
}
|
|
334
428
|
|
|
429
|
+
/**
|
|
430
|
+
* Turns session resumption on for every slot (`TlsServer.enableTickets`):
|
|
431
|
+
* from the next `accept`, a connection offering a ticket, or one that may
|
|
432
|
+
* be issued one, says `TLS_RECORD_TICKET` in its interest. A slot built
|
|
433
|
+
* later is built with them on.
|
|
434
|
+
*/
|
|
435
|
+
enableTickets(): void {
|
|
436
|
+
this.tickets = true
|
|
437
|
+
for (let k: i32 = 0; k < toI32(this.connections.length); k++) {
|
|
438
|
+
this.connections[k].tls.enableTickets()
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* While `slot`'s interest says `TLS_RECORD_TICKET` in the handshake: reads
|
|
444
|
+
* its ClientHello's tickets under `current` and `previous`, with what each
|
|
445
|
+
* `info` says of them, records the one it resumes in `strikes`, and sends
|
|
446
|
+
* the flight that answers the hello, resumed or in full
|
|
447
|
+
* (`TlsRecordServer.resume`). The keys and the register are borrowed for
|
|
448
|
+
* the call. Answers the slot's interest.
|
|
449
|
+
*/
|
|
450
|
+
resume(
|
|
451
|
+
slot: i32,
|
|
452
|
+
current: Secret<u8[]>,
|
|
453
|
+
currentInfo: TlsTicketKeyInfo,
|
|
454
|
+
previous: Secret<u8[]>,
|
|
455
|
+
previousInfo: TlsTicketKeyInfo,
|
|
456
|
+
strikes: TlsTicketStrikes,
|
|
457
|
+
now: i64
|
|
458
|
+
): i32 {
|
|
459
|
+
if (!this.holds(slot)) {
|
|
460
|
+
return TLS_RECORD_DONE
|
|
461
|
+
}
|
|
462
|
+
this.connections[slot].resume(current, currentInfo, previous, previousInfo, strikes, now)
|
|
463
|
+
return this.flush(slot)
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* While `slot`'s interest says `TLS_RECORD_TICKET` on an open connection:
|
|
468
|
+
* seals one ticket under the borrowed `key` and sends its
|
|
469
|
+
* NewSessionTicket (`TlsRecordServer.issue`). Answers the slot's interest.
|
|
470
|
+
*/
|
|
471
|
+
issue(slot: i32, key: Secret<u8[]>, info: TlsTicketKeyInfo, now: i64): i32 {
|
|
472
|
+
if (!this.holds(slot)) {
|
|
473
|
+
return TLS_RECORD_DONE
|
|
474
|
+
}
|
|
475
|
+
this.connections[slot].issue(key, info, now)
|
|
476
|
+
return this.flush(slot)
|
|
477
|
+
}
|
|
478
|
+
|
|
335
479
|
/**
|
|
336
480
|
* Application data from `slot`'s client into `buf[off .. off + len)`: the
|
|
337
481
|
* count, 0 at the end of its stream, -11 when nothing is waiting, -104 once
|
|
@@ -405,6 +549,9 @@ export class TlsTcpServer {
|
|
|
405
549
|
this.flush(slot)
|
|
406
550
|
netClose(this.fds[slot])
|
|
407
551
|
this.fds[slot] = TLS_TCP_FREE
|
|
552
|
+
this.free.push(slot)
|
|
408
553
|
conn.wipeKeys()
|
|
554
|
+
// Whatever the last flush could not send is dropped with its buffer.
|
|
555
|
+
conn.release()
|
|
409
556
|
}
|
|
410
557
|
}
|