/src/h2o/deps/quicly/lib/quicly.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2017 Fastly, Kazuho Oku |
3 | | * |
4 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | * of this software and associated documentation files (the "Software"), to |
6 | | * deal in the Software without restriction, including without limitation the |
7 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
8 | | * sell copies of the Software, and to permit persons to whom the Software is |
9 | | * furnished to do so, subject to the following conditions: |
10 | | * |
11 | | * The above copyright notice and this permission notice shall be included in |
12 | | * all copies or substantial portions of the Software. |
13 | | * |
14 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
19 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
20 | | * IN THE SOFTWARE. |
21 | | */ |
22 | | #include <assert.h> |
23 | | #include <inttypes.h> |
24 | | #include <netinet/in.h> |
25 | | #include <pthread.h> |
26 | | #include <stdarg.h> |
27 | | #include <stdio.h> |
28 | | #include <stdlib.h> |
29 | | #include <sys/socket.h> |
30 | | #include <sys/time.h> |
31 | | #include "khash.h" |
32 | | #include "quicly.h" |
33 | | #include "quicly/defaults.h" |
34 | | #include "quicly/sentmap.h" |
35 | | #include "quicly/frame.h" |
36 | | #include "quicly/streambuf.h" |
37 | | #include "quicly/cc.h" |
38 | | #if QUICLY_USE_DTRACE |
39 | | #include "quicly-probes.h" |
40 | | #endif |
41 | | #include "quicly/retire_cid.h" |
42 | | |
43 | 0 | #define QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_FINAL 0x39 |
44 | 0 | #define QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_DRAFT 0xffa5 |
45 | | #define QUICLY_TRANSPORT_PARAMETER_ID_ORIGINAL_CONNECTION_ID 0 |
46 | | #define QUICLY_TRANSPORT_PARAMETER_ID_MAX_IDLE_TIMEOUT 1 |
47 | | #define QUICLY_TRANSPORT_PARAMETER_ID_STATELESS_RESET_TOKEN 2 |
48 | | #define QUICLY_TRANSPORT_PARAMETER_ID_MAX_UDP_PAYLOAD_SIZE 3 |
49 | | #define QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_DATA 4 |
50 | | #define QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL 5 |
51 | | #define QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE 6 |
52 | | #define QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_UNI 7 |
53 | | #define QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAMS_BIDI 8 |
54 | | #define QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAMS_UNI 9 |
55 | | #define QUICLY_TRANSPORT_PARAMETER_ID_ACK_DELAY_EXPONENT 10 |
56 | | #define QUICLY_TRANSPORT_PARAMETER_ID_MAX_ACK_DELAY 11 |
57 | | #define QUICLY_TRANSPORT_PARAMETER_ID_DISABLE_ACTIVE_MIGRATION 12 |
58 | | #define QUICLY_TRANSPORT_PARAMETER_ID_PREFERRED_ADDRESS 13 |
59 | | #define QUICLY_TRANSPORT_PARAMETER_ID_ACTIVE_CONNECTION_ID_LIMIT 14 |
60 | | #define QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_SOURCE_CONNECTION_ID 15 |
61 | | #define QUICLY_TRANSPORT_PARAMETER_ID_RETRY_SOURCE_CONNECTION_ID 16 |
62 | | #define QUICLY_TRANSPORT_PARAMETER_ID_MAX_DATAGRAM_FRAME_SIZE 0x20 |
63 | | #define QUICLY_TRANSPORT_PARAMETER_ID_MIN_ACK_DELAY 0xff03de1a |
64 | | |
65 | | /** |
66 | | * maximum size of token that quicly accepts |
67 | | */ |
68 | 0 | #define QUICLY_MAX_TOKEN_LEN 512 |
69 | | /** |
70 | | * sends ACK bundled with PING, when number of gaps in the ack queue reaches or exceeds this threshold. This value should be much |
71 | | * smaller than QUICLY_MAX_RANGES. |
72 | | */ |
73 | 0 | #define QUICLY_NUM_ACK_BLOCKS_TO_INDUCE_ACKACK 8 |
74 | | |
75 | | KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *) |
76 | | |
77 | | #if QUICLY_USE_TRACER |
78 | 0 | #define QUICLY_TRACER(label, conn, ...) QUICLY_TRACER_##label(conn, __VA_ARGS__) |
79 | | #else |
80 | | #define QUICLY_TRACER(...) |
81 | | #endif |
82 | | |
83 | | #if QUICLY_USE_DTRACE |
84 | | #define QUICLY_PROBE(label, conn, ...) \ |
85 | | do { \ |
86 | | quicly_conn_t *_conn = (conn); \ |
87 | | if (PTLS_UNLIKELY(QUICLY_##label##_ENABLED()) && !ptls_skip_tracing(_conn->crypto.tls)) \ |
88 | | QUICLY_##label(_conn, __VA_ARGS__); \ |
89 | | QUICLY_TRACER(label, _conn, __VA_ARGS__); \ |
90 | | } while (0) |
91 | | #else |
92 | 0 | #define QUICLY_PROBE(label, conn, ...) QUICLY_TRACER(label, conn, __VA_ARGS__) |
93 | | #endif |
94 | | #define QUICLY_PROBE_HEXDUMP(s, l) \ |
95 | | ({ \ |
96 | | size_t _l = (l); \ |
97 | | ptls_hexdump(alloca(_l * 2 + 1), (s), _l); \ |
98 | | }) |
99 | | #define QUICLY_PROBE_ESCAPE_UNSAFE_STRING(s, l) \ |
100 | | ({ \ |
101 | | size_t _l = (l); \ |
102 | | quicly_escape_unsafe_string(alloca(_l * 4 + 1), (s), _l); \ |
103 | | }) |
104 | | |
105 | | struct st_quicly_cipher_context_t { |
106 | | ptls_aead_context_t *aead; |
107 | | ptls_cipher_context_t *header_protection; |
108 | | }; |
109 | | |
110 | | struct st_quicly_pending_path_challenge_t { |
111 | | struct st_quicly_pending_path_challenge_t *next; |
112 | | uint8_t is_response; |
113 | | uint8_t data[QUICLY_PATH_CHALLENGE_DATA_LEN]; |
114 | | }; |
115 | | |
116 | | struct st_quicly_pn_space_t { |
117 | | /** |
118 | | * acks to be sent to remote peer |
119 | | */ |
120 | | quicly_ranges_t ack_queue; |
121 | | /** |
122 | | * time at when the largest pn in the ack_queue has been received (or INT64_MAX if none) |
123 | | */ |
124 | | int64_t largest_pn_received_at; |
125 | | /** |
126 | | * |
127 | | */ |
128 | | uint64_t next_expected_packet_number; |
129 | | /** |
130 | | * number of ACK-eliciting packets that have not been ACKed yet |
131 | | */ |
132 | | uint32_t unacked_count; |
133 | | /** |
134 | | * maximum number of ACK-eliciting packets to be queued before sending an ACK |
135 | | */ |
136 | | uint32_t packet_tolerance; |
137 | | /** |
138 | | * boolean indicating if reorder should NOT trigger an immediate ack |
139 | | */ |
140 | | uint8_t ignore_order; |
141 | | }; |
142 | | |
143 | | struct st_quicly_handshake_space_t { |
144 | | struct st_quicly_pn_space_t super; |
145 | | struct { |
146 | | struct st_quicly_cipher_context_t ingress; |
147 | | struct st_quicly_cipher_context_t egress; |
148 | | } cipher; |
149 | | uint16_t largest_ingress_udp_payload_size; |
150 | | }; |
151 | | |
152 | | struct st_quicly_application_space_t { |
153 | | struct st_quicly_pn_space_t super; |
154 | | struct { |
155 | | struct { |
156 | | struct { |
157 | | ptls_cipher_context_t *zero_rtt, *one_rtt; |
158 | | } header_protection; |
159 | | ptls_aead_context_t *aead[2]; /* 0-RTT uses aead[1], 1-RTT uses aead[key_phase] */ |
160 | | uint8_t secret[PTLS_MAX_DIGEST_SIZE]; |
161 | | struct { |
162 | | uint64_t prepared; |
163 | | uint64_t decrypted; |
164 | | } key_phase; |
165 | | } ingress; |
166 | | struct { |
167 | | struct st_quicly_cipher_context_t key; |
168 | | uint8_t secret[PTLS_MAX_DIGEST_SIZE]; |
169 | | uint64_t key_phase; |
170 | | struct { |
171 | | /** |
172 | | * PN at which key update was initiated. Set to UINT64_MAX once key update is acked. |
173 | | */ |
174 | | uint64_t last; |
175 | | /** |
176 | | * PN at which key update should be initiated. Set to UINT64_MAX when key update cannot be initiated. |
177 | | */ |
178 | | uint64_t next; |
179 | | } key_update_pn; |
180 | | } egress; |
181 | | } cipher; |
182 | | int one_rtt_writable; |
183 | | }; |
184 | | |
185 | | struct st_quicly_conn_t { |
186 | | struct _st_quicly_conn_public_t super; |
187 | | /** |
188 | | * the initial context |
189 | | */ |
190 | | struct st_quicly_handshake_space_t *initial; |
191 | | /** |
192 | | * the handshake context |
193 | | */ |
194 | | struct st_quicly_handshake_space_t *handshake; |
195 | | /** |
196 | | * 0-RTT and 1-RTT context |
197 | | */ |
198 | | struct st_quicly_application_space_t *application; |
199 | | /** |
200 | | * hashtable of streams |
201 | | */ |
202 | | khash_t(quicly_stream_t) * streams; |
203 | | /** |
204 | | * |
205 | | */ |
206 | | struct { |
207 | | /** |
208 | | * |
209 | | */ |
210 | | struct { |
211 | | uint64_t bytes_consumed; |
212 | | quicly_maxsender_t sender; |
213 | | } max_data; |
214 | | /** |
215 | | * |
216 | | */ |
217 | | struct { |
218 | | quicly_maxsender_t uni, bidi; |
219 | | } max_streams; |
220 | | /** |
221 | | * |
222 | | */ |
223 | | struct { |
224 | | uint64_t next_sequence; |
225 | | } ack_frequency; |
226 | | } ingress; |
227 | | /** |
228 | | * |
229 | | */ |
230 | | struct { |
231 | | /** |
232 | | * loss recovery |
233 | | */ |
234 | | quicly_loss_t loss; |
235 | | /** |
236 | | * next or the currently encoding packet number |
237 | | */ |
238 | | uint64_t packet_number; |
239 | | /** |
240 | | * next PN to be skipped |
241 | | */ |
242 | | uint64_t next_pn_to_skip; |
243 | | /** |
244 | | * |
245 | | */ |
246 | | uint16_t max_udp_payload_size; |
247 | | /** |
248 | | * valid if state is CLOSING |
249 | | */ |
250 | | struct { |
251 | | uint16_t error_code; |
252 | | uint64_t frame_type; /* UINT64_MAX if application close */ |
253 | | const char *reason_phrase; |
254 | | unsigned long num_packets_received; |
255 | | } connection_close; |
256 | | /** |
257 | | * |
258 | | */ |
259 | | struct { |
260 | | uint64_t permitted; |
261 | | uint64_t sent; |
262 | | } max_data; |
263 | | /** |
264 | | * |
265 | | */ |
266 | | struct { |
267 | | struct st_quicly_max_streams_t { |
268 | | uint64_t count; |
269 | | quicly_maxsender_t blocked_sender; |
270 | | } uni, bidi; |
271 | | } max_streams; |
272 | | /** |
273 | | * |
274 | | */ |
275 | | struct { |
276 | | struct st_quicly_pending_path_challenge_t *head, **tail_ref; |
277 | | } path_challenge; |
278 | | /** |
279 | | * |
280 | | */ |
281 | | struct { |
282 | | uint64_t generation; |
283 | | uint64_t max_acked; |
284 | | uint32_t num_inflight; |
285 | | } new_token; |
286 | | /** |
287 | | * |
288 | | */ |
289 | | struct { |
290 | | int64_t update_at; |
291 | | uint64_t sequence; |
292 | | } ack_frequency; |
293 | | /** |
294 | | * |
295 | | */ |
296 | | int64_t last_retransmittable_sent_at; |
297 | | /** |
298 | | * when to send an ACK, or other frames used for managing the connection |
299 | | */ |
300 | | int64_t send_ack_at; |
301 | | /** |
302 | | * congestion control |
303 | | */ |
304 | | quicly_cc_t cc; |
305 | | /** |
306 | | * things to be sent at the stream-level, that are not governed by the stream scheduler |
307 | | */ |
308 | | struct { |
309 | | /** |
310 | | * list of blocked streams (sorted in ascending order of stream_ids) |
311 | | */ |
312 | | struct { |
313 | | quicly_linklist_t uni; |
314 | | quicly_linklist_t bidi; |
315 | | } blocked; |
316 | | /** |
317 | | * list of streams with pending control data (e.g., RESET_STREAM) |
318 | | */ |
319 | | quicly_linklist_t control; |
320 | | } pending_streams; |
321 | | /** |
322 | | * send state for DATA_BLOCKED frame that corresponds to the current value of `conn->egress.max_data.permitted` |
323 | | */ |
324 | | quicly_sender_state_t data_blocked; |
325 | | /** |
326 | | * bit vector indicating if there's any pending crypto data (the insignificant 4 bits), or other non-stream data |
327 | | */ |
328 | | uint8_t pending_flows; |
329 | 0 | #define QUICLY_PENDING_FLOW_NEW_TOKEN_BIT (1 << 5) |
330 | 0 | #define QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT (1 << 6) |
331 | | /** |
332 | | * is there a pending NEW_CONNECTION_ID or RETIRE_CONNECTION_ID frame? |
333 | | * |
334 | | * This single bit represents two frame types, to keep `pending_flows` within 8 bits, and to reduce `if` branch in `do_send` |
335 | | * function. If we had two separate bits, we would have to check each bit separately in `do_send` function. Given NEW_CONNECTION_ID |
336 | | * and RETIRE_CONNECTION_ID frames are expected to be rarely sent, folding two types into a single bit makes sense. |
337 | | */ |
338 | 0 | #define QUICLY_PENDING_FLOW_CID_FRAME_BIT (1 << 7) |
339 | | /** |
340 | | * pending RETIRE_CONNECTION_ID frames to be sent |
341 | | */ |
342 | | quicly_retire_cid_set_t retire_cid; |
343 | | /** |
344 | | * payload of DATAGRAM frames to be sent |
345 | | */ |
346 | | struct { |
347 | | ptls_iovec_t payloads[10]; |
348 | | size_t count; |
349 | | } datagram_frame_payloads; |
350 | | /** |
351 | | * delivery rate estimator |
352 | | */ |
353 | | quicly_ratemeter_t ratemeter; |
354 | | } egress; |
355 | | /** |
356 | | * crypto data |
357 | | */ |
358 | | struct { |
359 | | ptls_t *tls; |
360 | | ptls_handshake_properties_t handshake_properties; |
361 | | struct { |
362 | | ptls_raw_extension_t ext[3]; |
363 | | ptls_buffer_t buf; |
364 | | } transport_params; |
365 | | unsigned async_in_progress : 1; |
366 | | } crypto; |
367 | | /** |
368 | | * token (if the token is a Retry token can be determined by consulting the length of retry_scid) |
369 | | */ |
370 | | ptls_iovec_t token; |
371 | | /** |
372 | | * len=UINT8_MAX if Retry was not used, use client_received_retry() to check |
373 | | */ |
374 | | quicly_cid_t retry_scid; |
375 | | /** |
376 | | * |
377 | | */ |
378 | | struct { |
379 | | /** |
380 | | * The moment when the idle timeout fires (including the additional 3 PTO). The value is set to INT64_MAX while the |
381 | | * handshake is in progress. |
382 | | */ |
383 | | int64_t at; |
384 | | /** |
385 | | * idle timeout |
386 | | */ |
387 | | uint8_t should_rearm_on_send : 1; |
388 | | } idle_timeout; |
389 | | /** |
390 | | * records the time when this connection was created |
391 | | */ |
392 | | int64_t created_at; |
393 | | /** |
394 | | * structure to hold various data used internally |
395 | | */ |
396 | | struct { |
397 | | /** |
398 | | * This value holds current time that remains constant while quicly functions that deal with time are running. Only |
399 | | * available when the lock is held using `lock_now`. |
400 | | */ |
401 | | int64_t now; |
402 | | /** |
403 | | * |
404 | | */ |
405 | | uint8_t lock_count; |
406 | | struct { |
407 | | /** |
408 | | * This cache is used to concatenate acked ranges of streams before processing them, reducing the frequency of function |
409 | | * calls to `quicly_sendstate_t` and to the application-level send window management callbacks. This approach works, |
410 | | * because in most cases acks will contain contiguous ranges of a single stream. |
411 | | */ |
412 | | struct { |
413 | | /** |
414 | | * set to INT64_MIN when the cache is invalid |
415 | | */ |
416 | | quicly_stream_id_t stream_id; |
417 | | quicly_sendstate_sent_t args; |
418 | | } active_acked_cache; |
419 | | } on_ack_stream; |
420 | | } stash; |
421 | | }; |
422 | | |
423 | | #if QUICLY_USE_TRACER |
424 | | #include "quicly-tracer.h" |
425 | | #endif |
426 | | |
427 | | struct st_quicly_handle_payload_state_t { |
428 | | const uint8_t *src, *const end; |
429 | | size_t epoch; |
430 | | uint64_t frame_type; |
431 | | }; |
432 | | |
433 | | struct st_ptls_salt_t { |
434 | | uint8_t initial[20]; |
435 | | struct { |
436 | | uint8_t key[PTLS_AES128_KEY_SIZE]; |
437 | | uint8_t iv[PTLS_AESGCM_IV_SIZE]; |
438 | | } retry; |
439 | | }; |
440 | | |
441 | | static void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len); |
442 | | |
443 | | static const quicly_stream_callbacks_t crypto_stream_callbacks = {quicly_streambuf_destroy, quicly_streambuf_egress_shift, |
444 | | quicly_streambuf_egress_emit, NULL, crypto_stream_receive}; |
445 | | |
446 | | static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, int is_enc, size_t epoch, const void *secret); |
447 | | static int initiate_close(quicly_conn_t *conn, int err, uint64_t frame_type, const char *reason_phrase); |
448 | | static int handle_close(quicly_conn_t *conn, int err, uint64_t frame_type, ptls_iovec_t reason_phrase); |
449 | | static int discard_sentmap_by_epoch(quicly_conn_t *conn, unsigned ack_epochs); |
450 | | |
451 | | quicly_cid_plaintext_t quicly_cid_plaintext_invalid = {.node_id = UINT64_MAX, .thread_id = 0xffffff}; |
452 | | |
453 | | static const quicly_transport_parameters_t default_transport_params = {.max_udp_payload_size = QUICLY_DEFAULT_MAX_UDP_PAYLOAD_SIZE, |
454 | | .ack_delay_exponent = QUICLY_DEFAULT_ACK_DELAY_EXPONENT, |
455 | | .max_ack_delay = QUICLY_DEFAULT_MAX_ACK_DELAY, |
456 | | .min_ack_delay_usec = UINT64_MAX, |
457 | | .active_connection_id_limit = |
458 | | QUICLY_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT}; |
459 | | |
460 | | static const struct st_ptls_salt_t *get_salt(uint32_t protocol_version) |
461 | 0 | { |
462 | 0 | static const struct st_ptls_salt_t |
463 | 0 | v1 = {.initial = {0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, |
464 | 0 | 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}, |
465 | 0 | .retry = {.key = {0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e}, |
466 | 0 | .iv = {0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}}}, |
467 | 0 | draft29 = {.initial = {0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, |
468 | 0 | 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}, |
469 | 0 | .retry = {.key = {0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, |
470 | 0 | 0xe1}, |
471 | 0 | .iv = {0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c}}}, |
472 | 0 | draft27 = { |
473 | 0 | .initial = {0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, |
474 | 0 | 0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02}, |
475 | 0 | .retry = {.key = {0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21, 0x33, 0xc8, 0x41, 0xe4, 0x04, 0x3d, 0xf2, 0x7d, 0x44, 0x30}, |
476 | 0 | .iv = {0x4d, 0x16, 0x11, 0xd0, 0x55, 0x13, 0xa5, 0x52, 0xc5, 0x87, 0xd5, 0x75}}}; |
477 | |
|
478 | 0 | switch (protocol_version) { |
479 | 0 | case QUICLY_PROTOCOL_VERSION_1: |
480 | 0 | return &v1; |
481 | 0 | case QUICLY_PROTOCOL_VERSION_DRAFT29: |
482 | 0 | return &draft29; |
483 | 0 | case QUICLY_PROTOCOL_VERSION_DRAFT27: |
484 | 0 | return &draft27; |
485 | 0 | break; |
486 | 0 | default: |
487 | 0 | return NULL; |
488 | 0 | } |
489 | 0 | } |
490 | | |
491 | | static void lock_now(quicly_conn_t *conn, int is_reentrant) |
492 | 0 | { |
493 | 0 | if (conn->stash.now == 0) { |
494 | 0 | assert(conn->stash.lock_count == 0); |
495 | 0 | conn->stash.now = conn->super.ctx->now->cb(conn->super.ctx->now); |
496 | 0 | } else { |
497 | 0 | assert(is_reentrant && "caller must be reentrant"); |
498 | 0 | assert(conn->stash.lock_count != 0); |
499 | 0 | } |
500 | | |
501 | 0 | ++conn->stash.lock_count; |
502 | 0 | } |
503 | | |
504 | | static void unlock_now(quicly_conn_t *conn) |
505 | 0 | { |
506 | 0 | assert(conn->stash.now != 0); |
507 | | |
508 | 0 | if (--conn->stash.lock_count == 0) |
509 | 0 | conn->stash.now = 0; |
510 | 0 | } |
511 | | |
512 | | static void set_address(quicly_address_t *addr, struct sockaddr *sa) |
513 | 0 | { |
514 | 0 | if (sa == NULL) { |
515 | 0 | addr->sa.sa_family = AF_UNSPEC; |
516 | 0 | return; |
517 | 0 | } |
518 | | |
519 | 0 | switch (sa->sa_family) { |
520 | 0 | case AF_UNSPEC: |
521 | 0 | addr->sa.sa_family = AF_UNSPEC; |
522 | 0 | break; |
523 | 0 | case AF_INET: |
524 | 0 | addr->sin = *(struct sockaddr_in *)sa; |
525 | 0 | break; |
526 | 0 | case AF_INET6: |
527 | 0 | addr->sin6 = *(struct sockaddr_in6 *)sa; |
528 | 0 | break; |
529 | 0 | default: |
530 | 0 | memset(addr, 0xff, sizeof(*addr)); |
531 | 0 | assert(!"unexpected address type"); |
532 | 0 | break; |
533 | 0 | } |
534 | 0 | } |
535 | | |
536 | | static ptls_cipher_suite_t *get_aes128gcmsha256(quicly_context_t *ctx) |
537 | 0 | { |
538 | 0 | ptls_cipher_suite_t **cs; |
539 | |
|
540 | 0 | for (cs = ctx->tls->cipher_suites;; ++cs) { |
541 | 0 | assert(cs != NULL); |
542 | 0 | if ((*cs)->id == PTLS_CIPHER_SUITE_AES_128_GCM_SHA256) |
543 | 0 | break; |
544 | 0 | } |
545 | 0 | return *cs; |
546 | 0 | } |
547 | | |
548 | | static inline uint8_t get_epoch(uint8_t first_byte) |
549 | 0 | { |
550 | 0 | if (!QUICLY_PACKET_IS_LONG_HEADER(first_byte)) |
551 | 0 | return QUICLY_EPOCH_1RTT; |
552 | | |
553 | 0 | switch (first_byte & QUICLY_PACKET_TYPE_BITMASK) { |
554 | 0 | case QUICLY_PACKET_TYPE_INITIAL: |
555 | 0 | return QUICLY_EPOCH_INITIAL; |
556 | 0 | case QUICLY_PACKET_TYPE_HANDSHAKE: |
557 | 0 | return QUICLY_EPOCH_HANDSHAKE; |
558 | 0 | case QUICLY_PACKET_TYPE_0RTT: |
559 | 0 | return QUICLY_EPOCH_0RTT; |
560 | 0 | default: |
561 | 0 | assert(!"FIXME"); |
562 | 0 | } |
563 | 0 | } |
564 | | |
565 | | static ptls_aead_context_t *create_retry_aead(quicly_context_t *ctx, uint32_t protocol_version, int is_enc) |
566 | 0 | { |
567 | 0 | const struct st_ptls_salt_t *salt = get_salt(protocol_version); |
568 | 0 | assert(salt != NULL); |
569 | | |
570 | 0 | ptls_cipher_suite_t *algo = get_aes128gcmsha256(ctx); |
571 | 0 | ptls_aead_context_t *aead = ptls_aead_new_direct(algo->aead, is_enc, salt->retry.key, salt->retry.iv); |
572 | 0 | assert(aead != NULL); |
573 | 0 | return aead; |
574 | 0 | } |
575 | | |
576 | | static void dispose_cipher(struct st_quicly_cipher_context_t *ctx) |
577 | 0 | { |
578 | 0 | ptls_aead_free(ctx->aead); |
579 | 0 | ptls_cipher_free(ctx->header_protection); |
580 | 0 | } |
581 | | |
582 | | static void clear_datagram_frame_payloads(quicly_conn_t *conn) |
583 | 0 | { |
584 | 0 | for (size_t i = 0; i != conn->egress.datagram_frame_payloads.count; ++i) { |
585 | 0 | free(conn->egress.datagram_frame_payloads.payloads[i].base); |
586 | 0 | conn->egress.datagram_frame_payloads.payloads[i] = ptls_iovec_init(NULL, 0); |
587 | 0 | } |
588 | 0 | conn->egress.datagram_frame_payloads.count = 0; |
589 | 0 | } |
590 | | |
591 | | static int is_retry(quicly_conn_t *conn) |
592 | 0 | { |
593 | 0 | return conn->retry_scid.len != UINT8_MAX; |
594 | 0 | } |
595 | | |
596 | | static int needs_cid_auth(quicly_conn_t *conn) |
597 | 0 | { |
598 | 0 | switch (conn->super.version) { |
599 | 0 | case QUICLY_PROTOCOL_VERSION_1: |
600 | 0 | case QUICLY_PROTOCOL_VERSION_DRAFT29: |
601 | 0 | return 1; |
602 | 0 | default: |
603 | 0 | return 0; |
604 | 0 | } |
605 | 0 | } |
606 | | |
607 | | static int64_t get_sentmap_expiration_time(quicly_conn_t *conn) |
608 | 0 | { |
609 | 0 | return quicly_loss_get_sentmap_expiration_time(&conn->egress.loss, conn->super.remote.transport_params.max_ack_delay); |
610 | 0 | } |
611 | | |
612 | | static void ack_frequency_set_next_update_at(quicly_conn_t *conn) |
613 | 0 | { |
614 | 0 | if (conn->super.remote.transport_params.min_ack_delay_usec != UINT64_MAX) |
615 | 0 | conn->egress.ack_frequency.update_at = conn->stash.now + get_sentmap_expiration_time(conn); |
616 | 0 | } |
617 | | |
618 | | size_t quicly_decode_packet(quicly_context_t *ctx, quicly_decoded_packet_t *packet, const uint8_t *datagram, size_t datagram_size, |
619 | | size_t *off) |
620 | 0 | { |
621 | 0 | const uint8_t *src = datagram, *src_end = datagram + datagram_size; |
622 | |
|
623 | 0 | assert(*off <= datagram_size); |
624 | | |
625 | 0 | packet->octets = ptls_iovec_init(src + *off, datagram_size - *off); |
626 | 0 | if (packet->octets.len < 2) |
627 | 0 | goto Error; |
628 | 0 | packet->datagram_size = *off == 0 ? datagram_size : 0; |
629 | 0 | packet->token = ptls_iovec_init(NULL, 0); |
630 | 0 | packet->decrypted.pn = UINT64_MAX; |
631 | | |
632 | | /* move the cursor to the second byte */ |
633 | 0 | src += *off + 1; |
634 | |
|
635 | 0 | if (QUICLY_PACKET_IS_LONG_HEADER(packet->octets.base[0])) { |
636 | | /* long header */ |
637 | 0 | uint64_t rest_length; |
638 | 0 | if (src_end - src < 5) |
639 | 0 | goto Error; |
640 | 0 | packet->version = quicly_decode32(&src); |
641 | 0 | packet->cid.dest.encrypted.len = *src++; |
642 | 0 | if (src_end - src < packet->cid.dest.encrypted.len + 1) |
643 | 0 | goto Error; |
644 | 0 | packet->cid.dest.encrypted.base = (uint8_t *)src; |
645 | 0 | src += packet->cid.dest.encrypted.len; |
646 | 0 | packet->cid.src.len = *src++; |
647 | 0 | if (src_end - src < packet->cid.src.len) |
648 | 0 | goto Error; |
649 | 0 | packet->cid.src.base = (uint8_t *)src; |
650 | 0 | src += packet->cid.src.len; |
651 | 0 | switch (packet->octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) { |
652 | 0 | case QUICLY_PACKET_TYPE_INITIAL: |
653 | 0 | case QUICLY_PACKET_TYPE_0RTT: |
654 | 0 | if (ctx->cid_encryptor == NULL || packet->cid.dest.encrypted.len == 0 || |
655 | 0 | ctx->cid_encryptor->decrypt_cid(ctx->cid_encryptor, &packet->cid.dest.plaintext, packet->cid.dest.encrypted.base, |
656 | 0 | packet->cid.dest.encrypted.len) == SIZE_MAX) |
657 | 0 | packet->cid.dest.plaintext = quicly_cid_plaintext_invalid; |
658 | 0 | packet->cid.dest.might_be_client_generated = 1; |
659 | 0 | break; |
660 | 0 | default: |
661 | 0 | if (ctx->cid_encryptor != NULL) { |
662 | 0 | if (packet->cid.dest.encrypted.len == 0) |
663 | 0 | goto Error; |
664 | 0 | if (ctx->cid_encryptor->decrypt_cid(ctx->cid_encryptor, &packet->cid.dest.plaintext, |
665 | 0 | packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len) == SIZE_MAX) |
666 | 0 | goto Error; |
667 | 0 | } else { |
668 | 0 | packet->cid.dest.plaintext = quicly_cid_plaintext_invalid; |
669 | 0 | } |
670 | 0 | packet->cid.dest.might_be_client_generated = 0; |
671 | 0 | break; |
672 | 0 | } |
673 | 0 | switch (packet->version) { |
674 | 0 | case QUICLY_PROTOCOL_VERSION_1: |
675 | 0 | case QUICLY_PROTOCOL_VERSION_DRAFT29: |
676 | 0 | case QUICLY_PROTOCOL_VERSION_DRAFT27: |
677 | | /* these are the recognized versions, and they share the same packet header format */ |
678 | 0 | if ((packet->octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) == QUICLY_PACKET_TYPE_RETRY) { |
679 | | /* retry */ |
680 | 0 | if (src_end - src <= PTLS_AESGCM_TAG_SIZE) |
681 | 0 | goto Error; |
682 | 0 | packet->token = ptls_iovec_init(src, src_end - src - PTLS_AESGCM_TAG_SIZE); |
683 | 0 | src += packet->token.len; |
684 | 0 | packet->encrypted_off = src - packet->octets.base; |
685 | 0 | } else { |
686 | | /* coalescible long header packet */ |
687 | 0 | if ((packet->octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) == QUICLY_PACKET_TYPE_INITIAL) { |
688 | | /* initial has a token */ |
689 | 0 | uint64_t token_len; |
690 | 0 | if ((token_len = quicly_decodev(&src, src_end)) == UINT64_MAX) |
691 | 0 | goto Error; |
692 | 0 | if (src_end - src < token_len) |
693 | 0 | goto Error; |
694 | 0 | packet->token = ptls_iovec_init(src, token_len); |
695 | 0 | src += token_len; |
696 | 0 | } |
697 | 0 | if ((rest_length = quicly_decodev(&src, src_end)) == UINT64_MAX) |
698 | 0 | goto Error; |
699 | 0 | if (rest_length < 1) |
700 | 0 | goto Error; |
701 | 0 | if (src_end - src < rest_length) |
702 | 0 | goto Error; |
703 | 0 | packet->encrypted_off = src - packet->octets.base; |
704 | 0 | packet->octets.len = packet->encrypted_off + rest_length; |
705 | 0 | } |
706 | 0 | break; |
707 | 0 | default: |
708 | | /* VN packet or packets of unknown version cannot be parsed. `encrypted_off` is set to the first byte after SCID. */ |
709 | 0 | packet->encrypted_off = src - packet->octets.base; |
710 | 0 | } |
711 | 0 | packet->_is_stateless_reset_cached = QUICLY__DECODED_PACKET_CACHED_NOT_STATELESS_RESET; |
712 | 0 | } else { |
713 | | /* short header */ |
714 | 0 | if (ctx->cid_encryptor != NULL) { |
715 | 0 | if (src_end - src < QUICLY_MAX_CID_LEN_V1) |
716 | 0 | goto Error; |
717 | 0 | size_t local_cidl = ctx->cid_encryptor->decrypt_cid(ctx->cid_encryptor, &packet->cid.dest.plaintext, src, 0); |
718 | 0 | if (local_cidl == SIZE_MAX) |
719 | 0 | goto Error; |
720 | 0 | packet->cid.dest.encrypted = ptls_iovec_init(src, local_cidl); |
721 | 0 | src += local_cidl; |
722 | 0 | } else { |
723 | 0 | packet->cid.dest.encrypted = ptls_iovec_init(NULL, 0); |
724 | 0 | packet->cid.dest.plaintext = quicly_cid_plaintext_invalid; |
725 | 0 | } |
726 | 0 | packet->cid.dest.might_be_client_generated = 0; |
727 | 0 | packet->cid.src = ptls_iovec_init(NULL, 0); |
728 | 0 | packet->version = 0; |
729 | 0 | packet->encrypted_off = src - packet->octets.base; |
730 | 0 | packet->_is_stateless_reset_cached = QUICLY__DECODED_PACKET_CACHED_MAYBE_STATELESS_RESET; |
731 | 0 | } |
732 | | |
733 | 0 | *off += packet->octets.len; |
734 | 0 | return packet->octets.len; |
735 | | |
736 | 0 | Error: |
737 | 0 | return SIZE_MAX; |
738 | 0 | } |
739 | | |
740 | | uint64_t quicly_determine_packet_number(uint32_t truncated, size_t num_bits, uint64_t expected) |
741 | 0 | { |
742 | 0 | uint64_t win = (uint64_t)1 << num_bits, candidate = (expected & ~(win - 1)) | truncated; |
743 | |
|
744 | 0 | if (candidate + win / 2 <= expected) |
745 | 0 | return candidate + win; |
746 | 0 | if (candidate > expected + win / 2 && candidate >= win) |
747 | 0 | return candidate - win; |
748 | 0 | return candidate; |
749 | 0 | } |
750 | | |
751 | | static void assert_consistency(quicly_conn_t *conn, int timer_must_be_in_future) |
752 | 0 | { |
753 | 0 | if (conn->super.state >= QUICLY_STATE_CLOSING) { |
754 | 0 | assert(!timer_must_be_in_future || conn->stash.now < conn->egress.send_ack_at); |
755 | 0 | return; |
756 | 0 | } |
757 | | |
758 | 0 | if (conn->egress.loss.sentmap.bytes_in_flight != 0 || conn->super.remote.address_validation.send_probe) { |
759 | 0 | assert(conn->egress.loss.alarm_at != INT64_MAX); |
760 | 0 | } else { |
761 | 0 | assert(conn->egress.loss.loss_time == INT64_MAX); |
762 | 0 | } |
763 | | /* Allow timers not in the future when the remote peer is not yet validated, since we may not be able to send packets even when |
764 | | * timers fire. */ |
765 | 0 | if (timer_must_be_in_future && conn->super.remote.address_validation.validated) |
766 | 0 | assert(conn->stash.now < conn->egress.loss.alarm_at); |
767 | 0 | } |
768 | | |
769 | | static int on_invalid_ack(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
770 | 0 | { |
771 | 0 | if (acked) |
772 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
773 | 0 | return 0; |
774 | 0 | } |
775 | | |
776 | | static uint64_t calc_next_pn_to_skip(ptls_context_t *tlsctx, uint64_t next_pn, uint32_t cwnd, uint64_t mtu) |
777 | 0 | { |
778 | 0 | static __thread struct { |
779 | 0 | uint32_t values[8]; |
780 | 0 | size_t off; |
781 | 0 | } cached_rand; |
782 | |
|
783 | 0 | if (cached_rand.off == 0) { |
784 | 0 | tlsctx->random_bytes(cached_rand.values, sizeof(cached_rand.values)); |
785 | 0 | cached_rand.off = PTLS_ELEMENTSOF(cached_rand.values); |
786 | 0 | } |
787 | | |
788 | | /* on average, skip one PN per every min(256 packets, 8 * CWND) */ |
789 | 0 | uint32_t packet_cwnd = cwnd / mtu; |
790 | 0 | if (packet_cwnd < 32) |
791 | 0 | packet_cwnd = 32; |
792 | 0 | uint64_t skip_after = cached_rand.values[--cached_rand.off] % (16 * packet_cwnd); |
793 | 0 | return next_pn + 1 + skip_after; |
794 | 0 | } |
795 | | |
796 | | static void init_max_streams(struct st_quicly_max_streams_t *m) |
797 | 0 | { |
798 | 0 | m->count = 0; |
799 | 0 | quicly_maxsender_init(&m->blocked_sender, -1); |
800 | 0 | } |
801 | | |
802 | | static int update_max_streams(struct st_quicly_max_streams_t *m, uint64_t count) |
803 | 0 | { |
804 | 0 | if (count > (uint64_t)1 << 60) |
805 | 0 | return QUICLY_TRANSPORT_ERROR_STREAM_LIMIT; |
806 | | |
807 | 0 | if (m->count < count) { |
808 | 0 | m->count = count; |
809 | 0 | if (m->blocked_sender.max_acked < count) |
810 | 0 | m->blocked_sender.max_acked = count; |
811 | 0 | } |
812 | |
|
813 | 0 | return 0; |
814 | 0 | } |
815 | | |
816 | | int quicly_connection_is_ready(quicly_conn_t *conn) |
817 | 0 | { |
818 | 0 | return conn->application != NULL; |
819 | 0 | } |
820 | | |
821 | | static int stream_is_destroyable(quicly_stream_t *stream) |
822 | 0 | { |
823 | 0 | if (!quicly_recvstate_transfer_complete(&stream->recvstate)) |
824 | 0 | return 0; |
825 | 0 | if (!quicly_sendstate_transfer_complete(&stream->sendstate)) |
826 | 0 | return 0; |
827 | 0 | switch (stream->_send_aux.reset_stream.sender_state) { |
828 | 0 | case QUICLY_SENDER_STATE_NONE: |
829 | 0 | case QUICLY_SENDER_STATE_ACKED: |
830 | 0 | break; |
831 | 0 | default: |
832 | 0 | return 0; |
833 | 0 | } |
834 | 0 | return 1; |
835 | 0 | } |
836 | | |
837 | | static void sched_stream_control(quicly_stream_t *stream) |
838 | 0 | { |
839 | 0 | assert(stream->stream_id >= 0); |
840 | | |
841 | 0 | if (!quicly_linklist_is_linked(&stream->_send_aux.pending_link.control)) |
842 | 0 | quicly_linklist_insert(stream->conn->egress.pending_streams.control.prev, &stream->_send_aux.pending_link.control); |
843 | 0 | } |
844 | | |
845 | | static void resched_stream_data(quicly_stream_t *stream) |
846 | 0 | { |
847 | 0 | if (stream->stream_id < 0) { |
848 | 0 | assert(-4 <= stream->stream_id); |
849 | 0 | uint8_t mask = 1 << -(1 + stream->stream_id); |
850 | 0 | if (stream->sendstate.pending.num_ranges != 0) { |
851 | 0 | stream->conn->egress.pending_flows |= mask; |
852 | 0 | } else { |
853 | 0 | stream->conn->egress.pending_flows &= ~mask; |
854 | 0 | } |
855 | 0 | return; |
856 | 0 | } |
857 | | |
858 | | /* do nothing if blocked */ |
859 | 0 | if (stream->streams_blocked) |
860 | 0 | return; |
861 | | |
862 | 0 | quicly_stream_scheduler_t *scheduler = stream->conn->super.ctx->stream_scheduler; |
863 | 0 | scheduler->update_state(scheduler, stream); |
864 | 0 | } |
865 | | |
866 | | static int should_send_max_data(quicly_conn_t *conn) |
867 | 0 | { |
868 | 0 | return quicly_maxsender_should_send_max(&conn->ingress.max_data.sender, conn->ingress.max_data.bytes_consumed, |
869 | 0 | (uint32_t)conn->super.ctx->transport_params.max_data, 512); |
870 | 0 | } |
871 | | |
872 | | static int should_send_max_stream_data(quicly_stream_t *stream) |
873 | 0 | { |
874 | 0 | if (stream->recvstate.eos != UINT64_MAX) |
875 | 0 | return 0; |
876 | 0 | return quicly_maxsender_should_send_max(&stream->_send_aux.max_stream_data_sender, stream->recvstate.data_off, |
877 | 0 | stream->_recv_aux.window, 512); |
878 | 0 | } |
879 | | |
880 | | int quicly_stream_sync_sendbuf(quicly_stream_t *stream, int activate) |
881 | 0 | { |
882 | 0 | int ret; |
883 | |
|
884 | 0 | if (activate) { |
885 | 0 | if ((ret = quicly_sendstate_activate(&stream->sendstate)) != 0) |
886 | 0 | return ret; |
887 | 0 | } |
888 | | |
889 | 0 | resched_stream_data(stream); |
890 | 0 | return 0; |
891 | 0 | } |
892 | | |
893 | | void quicly_stream_sync_recvbuf(quicly_stream_t *stream, size_t shift_amount) |
894 | 0 | { |
895 | 0 | stream->recvstate.data_off += shift_amount; |
896 | 0 | if (stream->stream_id >= 0) { |
897 | 0 | if (should_send_max_stream_data(stream)) |
898 | 0 | sched_stream_control(stream); |
899 | 0 | } |
900 | 0 | } |
901 | | |
902 | | static int schedule_path_challenge_frame(quicly_conn_t *conn, int is_response, const uint8_t *data) |
903 | 0 | { |
904 | 0 | struct st_quicly_pending_path_challenge_t *pending; |
905 | |
|
906 | 0 | if ((pending = malloc(sizeof(struct st_quicly_pending_path_challenge_t))) == NULL) |
907 | 0 | return PTLS_ERROR_NO_MEMORY; |
908 | | |
909 | 0 | pending->next = NULL; |
910 | 0 | pending->is_response = is_response; |
911 | 0 | memcpy(pending->data, data, QUICLY_PATH_CHALLENGE_DATA_LEN); |
912 | |
|
913 | 0 | *conn->egress.path_challenge.tail_ref = pending; |
914 | 0 | conn->egress.path_challenge.tail_ref = &pending->next; |
915 | 0 | return 0; |
916 | 0 | } |
917 | | |
918 | | /** |
919 | | * calculate how many CIDs we provide to the remote peer |
920 | | */ |
921 | | static size_t local_cid_size(const quicly_conn_t *conn) |
922 | 0 | { |
923 | 0 | PTLS_BUILD_ASSERT(QUICLY_LOCAL_ACTIVE_CONNECTION_ID_LIMIT < SIZE_MAX / sizeof(uint64_t)); |
924 | | |
925 | | /* if we don't have an encryptor, the only CID we issue is the one we send during handshake */ |
926 | 0 | if (conn->super.ctx->cid_encryptor == NULL) |
927 | 0 | return 1; |
928 | | |
929 | 0 | uint64_t capacity = conn->super.remote.transport_params.active_connection_id_limit; |
930 | 0 | if (capacity > QUICLY_LOCAL_ACTIVE_CONNECTION_ID_LIMIT) |
931 | 0 | capacity = QUICLY_LOCAL_ACTIVE_CONNECTION_ID_LIMIT; |
932 | 0 | return capacity; |
933 | 0 | } |
934 | | |
935 | | /** |
936 | | * set up an internal record to send RETIRE_CONNECTION_ID frame later |
937 | | */ |
938 | | static void schedule_retire_connection_id_frame(quicly_conn_t *conn, uint64_t sequence) |
939 | 0 | { |
940 | 0 | quicly_retire_cid_push(&conn->egress.retire_cid, sequence); |
941 | 0 | conn->egress.pending_flows |= QUICLY_PENDING_FLOW_CID_FRAME_BIT; |
942 | 0 | } |
943 | | |
944 | | static int write_crypto_data(quicly_conn_t *conn, ptls_buffer_t *tlsbuf, size_t epoch_offsets[5]) |
945 | 0 | { |
946 | 0 | size_t epoch; |
947 | 0 | int ret; |
948 | |
|
949 | 0 | if (tlsbuf->off == 0) |
950 | 0 | return 0; |
951 | | |
952 | 0 | for (epoch = 0; epoch < 4; ++epoch) { |
953 | 0 | size_t len = epoch_offsets[epoch + 1] - epoch_offsets[epoch]; |
954 | 0 | if (len == 0) |
955 | 0 | continue; |
956 | 0 | quicly_stream_t *stream = quicly_get_stream(conn, -(quicly_stream_id_t)(1 + epoch)); |
957 | 0 | assert(stream != NULL); |
958 | 0 | if ((ret = quicly_streambuf_egress_write(stream, tlsbuf->base + epoch_offsets[epoch], len)) != 0) |
959 | 0 | return ret; |
960 | 0 | } |
961 | | |
962 | 0 | return 0; |
963 | 0 | } |
964 | | |
965 | | static void crypto_handshake(quicly_conn_t *conn, size_t in_epoch, ptls_iovec_t input) |
966 | 0 | { |
967 | 0 | ptls_buffer_t output; |
968 | 0 | size_t epoch_offsets[5] = {0}; |
969 | |
|
970 | 0 | assert(!conn->crypto.async_in_progress); |
971 | | |
972 | 0 | ptls_buffer_init(&output, "", 0); |
973 | |
|
974 | 0 | int handshake_result = ptls_handle_message(conn->crypto.tls, &output, epoch_offsets, in_epoch, input.base, input.len, |
975 | 0 | &conn->crypto.handshake_properties); |
976 | 0 | QUICLY_PROBE(CRYPTO_HANDSHAKE, conn, conn->stash.now, handshake_result); |
977 | 0 | QUICLY_LOG_CONN(crypto_handshake, conn, { PTLS_LOG_ELEMENT_SIGNED(ret, handshake_result); }); |
978 | 0 | switch (handshake_result) { |
979 | 0 | case 0: |
980 | 0 | case PTLS_ERROR_IN_PROGRESS: |
981 | 0 | break; |
982 | 0 | case PTLS_ERROR_ASYNC_OPERATION: |
983 | 0 | assert(conn->super.ctx->async_handshake != NULL && |
984 | 0 | "async handshake is used but the quicly_context_t::async_handshake is NULL"); |
985 | 0 | conn->crypto.async_in_progress = 1; |
986 | 0 | conn->super.ctx->async_handshake->cb(conn->super.ctx->async_handshake, conn->crypto.tls); |
987 | 0 | break; |
988 | 0 | default: |
989 | 0 | initiate_close(conn, |
990 | 0 | PTLS_ERROR_GET_CLASS(handshake_result) == PTLS_ERROR_CLASS_SELF_ALERT ? handshake_result |
991 | 0 | : QUICLY_TRANSPORT_ERROR_INTERNAL, |
992 | 0 | QUICLY_FRAME_TYPE_CRYPTO, NULL); |
993 | 0 | goto Exit; |
994 | 0 | } |
995 | | /* drop 0-RTT write key if 0-RTT is rejected by remote peer */ |
996 | 0 | if (conn->application != NULL && !conn->application->one_rtt_writable && |
997 | 0 | conn->application->cipher.egress.key.aead != NULL) { |
998 | 0 | assert(quicly_is_client(conn)); |
999 | 0 | if (conn->crypto.handshake_properties.client.early_data_acceptance == PTLS_EARLY_DATA_REJECTED) { |
1000 | 0 | dispose_cipher(&conn->application->cipher.egress.key); |
1001 | 0 | conn->application->cipher.egress.key = (struct st_quicly_cipher_context_t){NULL}; |
1002 | | /* retire all packets with ack_epoch == 3; they are all 0-RTT packets */ |
1003 | 0 | int ret; |
1004 | 0 | if ((ret = discard_sentmap_by_epoch(conn, 1u << QUICLY_EPOCH_1RTT)) != 0) { |
1005 | 0 | initiate_close(conn, ret, QUICLY_FRAME_TYPE_CRYPTO, NULL); |
1006 | 0 | goto Exit; |
1007 | 0 | } |
1008 | 0 | } |
1009 | 0 | } |
1010 | | |
1011 | 0 | write_crypto_data(conn, &output, epoch_offsets); |
1012 | |
|
1013 | 0 | Exit: |
1014 | 0 | ptls_buffer_dispose(&output); |
1015 | 0 | } |
1016 | | |
1017 | | void crypto_stream_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len) |
1018 | 0 | { |
1019 | 0 | quicly_conn_t *conn = stream->conn; |
1020 | 0 | ptls_iovec_t input; |
1021 | | |
1022 | | /* store input */ |
1023 | 0 | if (quicly_streambuf_ingress_receive(stream, off, src, len) != 0) |
1024 | 0 | return; |
1025 | | |
1026 | | /* While the server generates the handshake signature asynchronously, clients would not send additional messages. They cannot |
1027 | | * generate Finished. They would not send Certificate / CertificateVerify before authenticating the server identity. */ |
1028 | 0 | if (conn->crypto.async_in_progress) { |
1029 | 0 | initiate_close(conn, PTLS_ALERT_UNEXPECTED_MESSAGE, QUICLY_FRAME_TYPE_CRYPTO, NULL); |
1030 | 0 | return; |
1031 | 0 | } |
1032 | | |
1033 | | /* feed the input into TLS, send result */ |
1034 | 0 | if ((input = quicly_streambuf_ingress_get(stream)).len != 0) { |
1035 | 0 | size_t in_epoch = -(1 + stream->stream_id); |
1036 | 0 | crypto_handshake(conn, in_epoch, input); |
1037 | 0 | quicly_streambuf_ingress_shift(stream, input.len); |
1038 | 0 | } |
1039 | 0 | } |
1040 | | |
1041 | | quicly_conn_t *quicly_resume_handshake(ptls_t *tls) |
1042 | 0 | { |
1043 | 0 | quicly_conn_t *conn; |
1044 | |
|
1045 | 0 | if ((conn = *ptls_get_data_ptr(tls)) == NULL) { |
1046 | | /* QUIC connection has been closed while TLS async operation was inflight. */ |
1047 | 0 | ptls_free(tls); |
1048 | 0 | return NULL; |
1049 | 0 | } |
1050 | | |
1051 | 0 | assert(conn->crypto.async_in_progress); |
1052 | 0 | conn->crypto.async_in_progress = 0; |
1053 | |
|
1054 | 0 | if (conn->super.state >= QUICLY_STATE_CLOSING) |
1055 | 0 | return conn; |
1056 | | |
1057 | 0 | crypto_handshake(conn, 0, ptls_iovec_init(NULL, 0)); |
1058 | 0 | return conn; |
1059 | 0 | } |
1060 | | |
1061 | | static void init_stream_properties(quicly_stream_t *stream, uint32_t initial_max_stream_data_local, |
1062 | | uint64_t initial_max_stream_data_remote) |
1063 | 0 | { |
1064 | 0 | int is_client = quicly_is_client(stream->conn); |
1065 | |
|
1066 | 0 | if (quicly_stream_has_send_side(is_client, stream->stream_id)) { |
1067 | 0 | quicly_sendstate_init(&stream->sendstate); |
1068 | 0 | } else { |
1069 | 0 | quicly_sendstate_init_closed(&stream->sendstate); |
1070 | 0 | } |
1071 | 0 | if (quicly_stream_has_receive_side(is_client, stream->stream_id)) { |
1072 | 0 | quicly_recvstate_init(&stream->recvstate); |
1073 | 0 | } else { |
1074 | 0 | quicly_recvstate_init_closed(&stream->recvstate); |
1075 | 0 | } |
1076 | 0 | stream->streams_blocked = 0; |
1077 | |
|
1078 | 0 | stream->_send_aux.max_stream_data = initial_max_stream_data_remote; |
1079 | 0 | stream->_send_aux.stop_sending.sender_state = QUICLY_SENDER_STATE_NONE; |
1080 | 0 | stream->_send_aux.stop_sending.error_code = 0; |
1081 | 0 | stream->_send_aux.reset_stream.sender_state = QUICLY_SENDER_STATE_NONE; |
1082 | 0 | stream->_send_aux.reset_stream.error_code = 0; |
1083 | 0 | quicly_maxsender_init(&stream->_send_aux.max_stream_data_sender, initial_max_stream_data_local); |
1084 | 0 | stream->_send_aux.blocked = QUICLY_SENDER_STATE_NONE; |
1085 | 0 | quicly_linklist_init(&stream->_send_aux.pending_link.control); |
1086 | 0 | quicly_linklist_init(&stream->_send_aux.pending_link.default_scheduler); |
1087 | |
|
1088 | 0 | stream->_recv_aux.window = initial_max_stream_data_local; |
1089 | | |
1090 | | /* Set the number of max ranges to be capable of handling following case: |
1091 | | * * every one of the two packets being sent are lost |
1092 | | * * average size of a STREAM frame found in a packet is >= ~512 bytes, or small STREAM frame is sent for every other stream |
1093 | | * being opened (e.g., sending QPACK encoder/decoder stream frame for each HTTP/3 request) |
1094 | | * See also: the doc-comment on `_recv_aux.max_ranges`. |
1095 | | */ |
1096 | 0 | uint32_t fragments_minmax = (uint32_t)(stream->conn->super.ctx->transport_params.max_streams_uni + |
1097 | 0 | stream->conn->super.ctx->transport_params.max_streams_bidi); |
1098 | 0 | if (fragments_minmax < 63) |
1099 | 0 | fragments_minmax = 63; |
1100 | 0 | if ((stream->_recv_aux.max_ranges = initial_max_stream_data_local / 1024) < fragments_minmax) |
1101 | 0 | stream->_recv_aux.max_ranges = fragments_minmax; |
1102 | 0 | } |
1103 | | |
1104 | | static void dispose_stream_properties(quicly_stream_t *stream) |
1105 | 0 | { |
1106 | 0 | quicly_sendstate_dispose(&stream->sendstate); |
1107 | 0 | quicly_recvstate_dispose(&stream->recvstate); |
1108 | 0 | quicly_maxsender_dispose(&stream->_send_aux.max_stream_data_sender); |
1109 | 0 | quicly_linklist_unlink(&stream->_send_aux.pending_link.control); |
1110 | 0 | quicly_linklist_unlink(&stream->_send_aux.pending_link.default_scheduler); |
1111 | 0 | } |
1112 | | |
1113 | | static quicly_stream_t *open_stream(quicly_conn_t *conn, uint64_t stream_id, uint32_t initial_max_stream_data_local, |
1114 | | uint64_t initial_max_stream_data_remote) |
1115 | 0 | { |
1116 | 0 | quicly_stream_t *stream; |
1117 | |
|
1118 | 0 | if ((stream = malloc(sizeof(*stream))) == NULL) |
1119 | 0 | return NULL; |
1120 | 0 | stream->conn = conn; |
1121 | 0 | stream->stream_id = stream_id; |
1122 | 0 | stream->callbacks = NULL; |
1123 | 0 | stream->data = NULL; |
1124 | |
|
1125 | 0 | int r; |
1126 | 0 | khiter_t iter = kh_put(quicly_stream_t, conn->streams, stream_id, &r); |
1127 | 0 | assert(iter != kh_end(conn->streams)); |
1128 | 0 | kh_val(conn->streams, iter) = stream; |
1129 | |
|
1130 | 0 | init_stream_properties(stream, initial_max_stream_data_local, initial_max_stream_data_remote); |
1131 | |
|
1132 | 0 | return stream; |
1133 | 0 | } |
1134 | | |
1135 | | static struct st_quicly_conn_streamgroup_state_t *get_streamgroup_state(quicly_conn_t *conn, quicly_stream_id_t stream_id) |
1136 | 0 | { |
1137 | 0 | if (quicly_is_client(conn) == quicly_stream_is_client_initiated(stream_id)) { |
1138 | 0 | return quicly_stream_is_unidirectional(stream_id) ? &conn->super.local.uni : &conn->super.local.bidi; |
1139 | 0 | } else { |
1140 | 0 | return quicly_stream_is_unidirectional(stream_id) ? &conn->super.remote.uni : &conn->super.remote.bidi; |
1141 | 0 | } |
1142 | 0 | } |
1143 | | |
1144 | | static int should_send_max_streams(quicly_conn_t *conn, int uni) |
1145 | 0 | { |
1146 | 0 | uint64_t concurrency; |
1147 | 0 | quicly_maxsender_t *maxsender; |
1148 | 0 | struct st_quicly_conn_streamgroup_state_t *group; |
1149 | |
|
1150 | 0 | #define INIT_VARS(type) \ |
1151 | 0 | do { \ |
1152 | 0 | concurrency = conn->super.ctx->transport_params.max_streams_##type; \ |
1153 | 0 | maxsender = &conn->ingress.max_streams.type; \ |
1154 | 0 | group = &conn->super.remote.type; \ |
1155 | 0 | } while (0) |
1156 | 0 | if (uni) { |
1157 | 0 | INIT_VARS(uni); |
1158 | 0 | } else { |
1159 | 0 | INIT_VARS(bidi); |
1160 | 0 | } |
1161 | 0 | #undef INIT_VARS |
1162 | |
|
1163 | 0 | if (concurrency == 0) |
1164 | 0 | return 0; |
1165 | | |
1166 | 0 | if (!quicly_maxsender_should_send_max(maxsender, group->next_stream_id / 4, group->num_streams, 768)) |
1167 | 0 | return 0; |
1168 | | |
1169 | 0 | return 1; |
1170 | 0 | } |
1171 | | |
1172 | | static void destroy_stream(quicly_stream_t *stream, int err) |
1173 | 0 | { |
1174 | 0 | quicly_conn_t *conn = stream->conn; |
1175 | |
|
1176 | 0 | QUICLY_PROBE(STREAM_ON_DESTROY, conn, conn->stash.now, stream, err); |
1177 | 0 | QUICLY_LOG_CONN(stream_on_destroy, conn, { |
1178 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
1179 | 0 | PTLS_LOG_ELEMENT_SIGNED(err, err); |
1180 | 0 | }); |
1181 | | |
1182 | 0 | if (stream->callbacks != NULL) |
1183 | 0 | stream->callbacks->on_destroy(stream, err); |
1184 | |
|
1185 | 0 | khiter_t iter = kh_get(quicly_stream_t, conn->streams, stream->stream_id); |
1186 | 0 | assert(iter != kh_end(conn->streams)); |
1187 | 0 | kh_del(quicly_stream_t, conn->streams, iter); |
1188 | |
|
1189 | 0 | if (stream->stream_id < 0) { |
1190 | 0 | size_t epoch = -(1 + stream->stream_id); |
1191 | 0 | stream->conn->egress.pending_flows &= ~(uint8_t)(1 << epoch); |
1192 | 0 | } else { |
1193 | 0 | struct st_quicly_conn_streamgroup_state_t *group = get_streamgroup_state(conn, stream->stream_id); |
1194 | 0 | --group->num_streams; |
1195 | 0 | } |
1196 | |
|
1197 | 0 | dispose_stream_properties(stream); |
1198 | |
|
1199 | 0 | if (conn->application != NULL) { |
1200 | | /* The function is normally invoked when receiving a packet, therefore just setting send_ack_at to zero is sufficient to |
1201 | | * trigger the emission of the MAX_STREAMS frame. FWIW, the only case the function is invoked when not receiving a packet is |
1202 | | * when the connection is being closed. In such case, the change will not have any bad side effects. |
1203 | | */ |
1204 | 0 | if (should_send_max_streams(conn, quicly_stream_is_unidirectional(stream->stream_id))) |
1205 | 0 | conn->egress.send_ack_at = 0; |
1206 | 0 | } |
1207 | |
|
1208 | 0 | free(stream); |
1209 | 0 | } |
1210 | | |
1211 | | static void destroy_all_streams(quicly_conn_t *conn, int err, int including_crypto_streams) |
1212 | 0 | { |
1213 | 0 | quicly_stream_t *stream; |
1214 | 0 | kh_foreach_value(conn->streams, stream, { |
1215 | | /* TODO do we need to send reset signals to open streams? */ |
1216 | 0 | if (including_crypto_streams || stream->stream_id >= 0) |
1217 | 0 | destroy_stream(stream, err); |
1218 | 0 | }); |
1219 | 0 | assert(quicly_num_streams(conn) == 0); |
1220 | 0 | } |
1221 | | |
1222 | | int quicly_foreach_stream(quicly_conn_t *conn, void *thunk, int (*cb)(void *thunk, quicly_stream_t *stream)) |
1223 | 0 | { |
1224 | 0 | quicly_stream_t *stream; |
1225 | 0 | kh_foreach_value(conn->streams, stream, { |
1226 | 0 | if (stream->stream_id >= 0) { |
1227 | 0 | int ret = cb(thunk, stream); |
1228 | 0 | if (ret != 0) |
1229 | 0 | return ret; |
1230 | 0 | } |
1231 | 0 | }); |
1232 | 0 | return 0; |
1233 | 0 | } |
1234 | | |
1235 | | quicly_stream_t *quicly_get_stream(quicly_conn_t *conn, quicly_stream_id_t stream_id) |
1236 | 0 | { |
1237 | 0 | khiter_t iter = kh_get(quicly_stream_t, conn->streams, stream_id); |
1238 | 0 | if (iter != kh_end(conn->streams)) |
1239 | 0 | return kh_val(conn->streams, iter); |
1240 | 0 | return NULL; |
1241 | 0 | } |
1242 | | |
1243 | | ptls_t *quicly_get_tls(quicly_conn_t *conn) |
1244 | 0 | { |
1245 | 0 | return conn->crypto.tls; |
1246 | 0 | } |
1247 | | |
1248 | | uint32_t quicly_num_streams_by_group(quicly_conn_t *conn, int uni, int locally_initiated) |
1249 | 0 | { |
1250 | 0 | int server_initiated = quicly_is_client(conn) != locally_initiated; |
1251 | 0 | struct st_quicly_conn_streamgroup_state_t *state = get_streamgroup_state(conn, uni * 2 + server_initiated); |
1252 | 0 | return state->num_streams; |
1253 | 0 | } |
1254 | | |
1255 | | int quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats) |
1256 | 0 | { |
1257 | | /* copy the pre-built stats fields */ |
1258 | 0 | memcpy(stats, &conn->super.stats, sizeof(conn->super.stats)); |
1259 | | |
1260 | | /* set or generate the non-pre-built stats fields here */ |
1261 | 0 | stats->rtt = conn->egress.loss.rtt; |
1262 | 0 | stats->loss_thresholds = conn->egress.loss.thresholds; |
1263 | 0 | stats->cc = conn->egress.cc; |
1264 | 0 | quicly_ratemeter_report(&conn->egress.ratemeter, &stats->delivery_rate); |
1265 | 0 | stats->num_sentmap_packets_largest = conn->egress.loss.sentmap.num_packets_largest; |
1266 | 0 | stats->handshake_confirmed_msec = conn->super.stats.handshake_confirmed_msec; |
1267 | |
|
1268 | 0 | return 0; |
1269 | 0 | } |
1270 | | |
1271 | | int quicly_get_delivery_rate(quicly_conn_t *conn, quicly_rate_t *delivery_rate) |
1272 | 0 | { |
1273 | 0 | quicly_ratemeter_report(&conn->egress.ratemeter, delivery_rate); |
1274 | 0 | return 0; |
1275 | 0 | } |
1276 | | |
1277 | | quicly_stream_id_t quicly_get_ingress_max_streams(quicly_conn_t *conn, int uni) |
1278 | 0 | { |
1279 | 0 | quicly_maxsender_t *maxsender = uni ? &conn->ingress.max_streams.uni : &conn->ingress.max_streams.bidi; |
1280 | 0 | return maxsender->max_committed; |
1281 | 0 | } |
1282 | | |
1283 | | void quicly_get_max_data(quicly_conn_t *conn, uint64_t *send_permitted, uint64_t *sent, uint64_t *consumed) |
1284 | 0 | { |
1285 | 0 | if (send_permitted != NULL) |
1286 | 0 | *send_permitted = conn->egress.max_data.permitted; |
1287 | 0 | if (sent != NULL) |
1288 | 0 | *sent = conn->egress.max_data.sent; |
1289 | 0 | if (consumed != NULL) |
1290 | 0 | *consumed = conn->ingress.max_data.bytes_consumed; |
1291 | 0 | } |
1292 | | |
1293 | | static void update_idle_timeout(quicly_conn_t *conn, int is_in_receive) |
1294 | 0 | { |
1295 | 0 | if (!is_in_receive && !conn->idle_timeout.should_rearm_on_send) |
1296 | 0 | return; |
1297 | | |
1298 | | /* calculate the minimum of the two max_idle_timeout */ |
1299 | 0 | int64_t idle_msec = INT64_MAX; |
1300 | 0 | if (conn->initial == NULL && conn->handshake == NULL && conn->super.remote.transport_params.max_idle_timeout != 0) |
1301 | 0 | idle_msec = conn->super.remote.transport_params.max_idle_timeout; |
1302 | 0 | if (conn->super.ctx->transport_params.max_idle_timeout != 0 && conn->super.ctx->transport_params.max_idle_timeout < idle_msec) |
1303 | 0 | idle_msec = conn->super.ctx->transport_params.max_idle_timeout; |
1304 | |
|
1305 | 0 | if (idle_msec == INT64_MAX) |
1306 | 0 | return; |
1307 | | |
1308 | 0 | uint32_t three_pto = 3 * quicly_rtt_get_pto(&conn->egress.loss.rtt, conn->super.ctx->transport_params.max_ack_delay, |
1309 | 0 | conn->egress.loss.conf->min_pto); |
1310 | 0 | conn->idle_timeout.at = conn->stash.now + (idle_msec > three_pto ? idle_msec : three_pto); |
1311 | 0 | conn->idle_timeout.should_rearm_on_send = is_in_receive; |
1312 | 0 | } |
1313 | | |
1314 | | static int scheduler_can_send(quicly_conn_t *conn) |
1315 | 0 | { |
1316 | | /* invoke the scheduler only when we are able to send stream data; skipping STATE_ACCEPTING is important as the application |
1317 | | * would not have setup data pointer. */ |
1318 | 0 | switch (conn->super.state) { |
1319 | 0 | case QUICLY_STATE_FIRSTFLIGHT: |
1320 | 0 | case QUICLY_STATE_CONNECTED: |
1321 | 0 | break; |
1322 | 0 | default: |
1323 | 0 | return 0; |
1324 | 0 | } |
1325 | | |
1326 | | /* scheduler would never have data to send, until application keys become available */ |
1327 | 0 | if (conn->application == NULL) |
1328 | 0 | return 0; |
1329 | | |
1330 | 0 | int conn_is_saturated = !(conn->egress.max_data.sent < conn->egress.max_data.permitted); |
1331 | 0 | return conn->super.ctx->stream_scheduler->can_send(conn->super.ctx->stream_scheduler, conn, conn_is_saturated); |
1332 | 0 | } |
1333 | | |
1334 | | static void update_send_alarm(quicly_conn_t *conn, int can_send_stream_data, int is_after_send) |
1335 | 0 | { |
1336 | 0 | int has_outstanding = conn->egress.loss.sentmap.bytes_in_flight != 0 || conn->super.remote.address_validation.send_probe, |
1337 | 0 | handshake_is_in_progress = conn->initial != NULL || conn->handshake != NULL; |
1338 | 0 | quicly_loss_update_alarm(&conn->egress.loss, conn->stash.now, conn->egress.last_retransmittable_sent_at, has_outstanding, |
1339 | 0 | can_send_stream_data, handshake_is_in_progress, conn->egress.max_data.sent, is_after_send); |
1340 | 0 | } |
1341 | | |
1342 | | /** |
1343 | | * Updates the send alarm and adjusts the delivery rate estimator. This function is called from the receive path. From the sendp |
1344 | | * path, `update_send_alarm` is called directly. |
1345 | | */ |
1346 | | static void setup_next_send(quicly_conn_t *conn) |
1347 | 0 | { |
1348 | 0 | int can_send_stream_data = scheduler_can_send(conn); |
1349 | |
|
1350 | 0 | update_send_alarm(conn, can_send_stream_data, 0); |
1351 | | |
1352 | | /* When the flow becomes application-limited due to receiving some information, stop collecting delivery rate samples. */ |
1353 | 0 | if (!can_send_stream_data) |
1354 | 0 | quicly_ratemeter_not_cwnd_limited(&conn->egress.ratemeter, conn->egress.packet_number); |
1355 | 0 | } |
1356 | | |
1357 | | static int create_handshake_flow(quicly_conn_t *conn, size_t epoch) |
1358 | 0 | { |
1359 | 0 | quicly_stream_t *stream; |
1360 | 0 | int ret; |
1361 | |
|
1362 | 0 | if ((stream = open_stream(conn, -(quicly_stream_id_t)(1 + epoch), 65536, 65536)) == NULL) |
1363 | 0 | return PTLS_ERROR_NO_MEMORY; |
1364 | 0 | if ((ret = quicly_streambuf_create(stream, sizeof(quicly_streambuf_t))) != 0) { |
1365 | 0 | destroy_stream(stream, ret); |
1366 | 0 | return ret; |
1367 | 0 | } |
1368 | 0 | stream->callbacks = &crypto_stream_callbacks; |
1369 | |
|
1370 | 0 | return 0; |
1371 | 0 | } |
1372 | | |
1373 | | static void destroy_handshake_flow(quicly_conn_t *conn, size_t epoch) |
1374 | 0 | { |
1375 | 0 | quicly_stream_t *stream = quicly_get_stream(conn, -(quicly_stream_id_t)(1 + epoch)); |
1376 | 0 | if (stream != NULL) |
1377 | 0 | destroy_stream(stream, 0); |
1378 | 0 | } |
1379 | | |
1380 | | static struct st_quicly_pn_space_t *alloc_pn_space(size_t sz, uint32_t packet_tolerance) |
1381 | 0 | { |
1382 | 0 | struct st_quicly_pn_space_t *space; |
1383 | |
|
1384 | 0 | if ((space = malloc(sz)) == NULL) |
1385 | 0 | return NULL; |
1386 | | |
1387 | 0 | quicly_ranges_init(&space->ack_queue); |
1388 | 0 | space->largest_pn_received_at = INT64_MAX; |
1389 | 0 | space->next_expected_packet_number = 0; |
1390 | 0 | space->unacked_count = 0; |
1391 | 0 | space->packet_tolerance = packet_tolerance; |
1392 | 0 | space->ignore_order = 0; |
1393 | 0 | if (sz != sizeof(*space)) |
1394 | 0 | memset((uint8_t *)space + sizeof(*space), 0, sz - sizeof(*space)); |
1395 | |
|
1396 | 0 | return space; |
1397 | 0 | } |
1398 | | |
1399 | | static void do_free_pn_space(struct st_quicly_pn_space_t *space) |
1400 | 0 | { |
1401 | 0 | quicly_ranges_clear(&space->ack_queue); |
1402 | 0 | free(space); |
1403 | 0 | } |
1404 | | |
1405 | | static int record_pn(quicly_ranges_t *ranges, uint64_t pn, int *is_out_of_order) |
1406 | 0 | { |
1407 | 0 | int ret; |
1408 | |
|
1409 | 0 | *is_out_of_order = 0; |
1410 | |
|
1411 | 0 | if (ranges->num_ranges != 0) { |
1412 | | /* fast path that is taken when we receive a packet in-order */ |
1413 | 0 | if (ranges->ranges[ranges->num_ranges - 1].end == pn) { |
1414 | 0 | ranges->ranges[ranges->num_ranges - 1].end = pn + 1; |
1415 | 0 | return 0; |
1416 | 0 | } |
1417 | 0 | *is_out_of_order = 1; |
1418 | 0 | } |
1419 | | |
1420 | | /* slow path; we add, then remove the oldest ranges when the number of ranges exceed the maximum */ |
1421 | 0 | if ((ret = quicly_ranges_add(ranges, pn, pn + 1)) != 0) |
1422 | 0 | return ret; |
1423 | 0 | if (ranges->num_ranges > QUICLY_MAX_ACK_BLOCKS) |
1424 | 0 | quicly_ranges_drop_by_range_indices(ranges, ranges->num_ranges - QUICLY_MAX_ACK_BLOCKS, ranges->num_ranges); |
1425 | |
|
1426 | 0 | return 0; |
1427 | 0 | } |
1428 | | |
1429 | | static int record_receipt(struct st_quicly_pn_space_t *space, uint64_t pn, int is_ack_only, int64_t now, int64_t *send_ack_at) |
1430 | 0 | { |
1431 | 0 | int ret, ack_now, is_out_of_order; |
1432 | |
|
1433 | 0 | if ((ret = record_pn(&space->ack_queue, pn, &is_out_of_order)) != 0) |
1434 | 0 | goto Exit; |
1435 | | |
1436 | 0 | ack_now = is_out_of_order && !space->ignore_order && !is_ack_only; |
1437 | | |
1438 | | /* update largest_pn_received_at (TODO implement deduplication at an earlier moment?) */ |
1439 | 0 | if (space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end == pn + 1) |
1440 | 0 | space->largest_pn_received_at = now; |
1441 | | |
1442 | | /* if the received packet is ack-eliciting, update / schedule transmission of ACK */ |
1443 | 0 | if (!is_ack_only) { |
1444 | 0 | space->unacked_count++; |
1445 | 0 | if (space->unacked_count >= space->packet_tolerance) |
1446 | 0 | ack_now = 1; |
1447 | 0 | } |
1448 | |
|
1449 | 0 | if (ack_now) { |
1450 | 0 | *send_ack_at = now; |
1451 | 0 | } else if (*send_ack_at == INT64_MAX && space->unacked_count != 0) { |
1452 | 0 | *send_ack_at = now + QUICLY_DELAYED_ACK_TIMEOUT; |
1453 | 0 | } |
1454 | |
|
1455 | 0 | ret = 0; |
1456 | 0 | Exit: |
1457 | 0 | return ret; |
1458 | 0 | } |
1459 | | |
1460 | | static void free_handshake_space(struct st_quicly_handshake_space_t **space) |
1461 | 0 | { |
1462 | 0 | if (*space != NULL) { |
1463 | 0 | if ((*space)->cipher.ingress.aead != NULL) |
1464 | 0 | dispose_cipher(&(*space)->cipher.ingress); |
1465 | 0 | if ((*space)->cipher.egress.aead != NULL) |
1466 | 0 | dispose_cipher(&(*space)->cipher.egress); |
1467 | 0 | do_free_pn_space(&(*space)->super); |
1468 | 0 | *space = NULL; |
1469 | 0 | } |
1470 | 0 | } |
1471 | | |
1472 | | static int setup_cipher(quicly_conn_t *conn, size_t epoch, int is_enc, ptls_cipher_context_t **hp_ctx, |
1473 | | ptls_aead_context_t **aead_ctx, ptls_aead_algorithm_t *aead, ptls_hash_algorithm_t *hash, |
1474 | | const void *secret) |
1475 | 0 | { |
1476 | | /* quicly_accept builds cipher before instantiating a connection. In such case, we use the default crypto engine */ |
1477 | 0 | quicly_crypto_engine_t *engine = conn != NULL ? conn->super.ctx->crypto_engine : &quicly_default_crypto_engine; |
1478 | |
|
1479 | 0 | return engine->setup_cipher(engine, conn, epoch, is_enc, hp_ctx, aead_ctx, aead, hash, secret); |
1480 | 0 | } |
1481 | | |
1482 | | static int setup_handshake_space_and_flow(quicly_conn_t *conn, size_t epoch) |
1483 | 0 | { |
1484 | 0 | struct st_quicly_handshake_space_t **space = epoch == QUICLY_EPOCH_INITIAL ? &conn->initial : &conn->handshake; |
1485 | 0 | if ((*space = (void *)alloc_pn_space(sizeof(struct st_quicly_handshake_space_t), 1)) == NULL) |
1486 | 0 | return PTLS_ERROR_NO_MEMORY; |
1487 | 0 | return create_handshake_flow(conn, epoch); |
1488 | 0 | } |
1489 | | |
1490 | | static void free_application_space(struct st_quicly_application_space_t **space) |
1491 | 0 | { |
1492 | 0 | if (*space != NULL) { |
1493 | 0 | #define DISPOSE_INGRESS(label, func) \ |
1494 | 0 | if ((*space)->cipher.ingress.label != NULL) \ |
1495 | 0 | func((*space)->cipher.ingress.label) |
1496 | 0 | DISPOSE_INGRESS(header_protection.zero_rtt, ptls_cipher_free); |
1497 | 0 | DISPOSE_INGRESS(header_protection.one_rtt, ptls_cipher_free); |
1498 | 0 | DISPOSE_INGRESS(aead[0], ptls_aead_free); |
1499 | 0 | DISPOSE_INGRESS(aead[1], ptls_aead_free); |
1500 | 0 | #undef DISPOSE_INGRESS |
1501 | 0 | if ((*space)->cipher.egress.key.aead != NULL) |
1502 | 0 | dispose_cipher(&(*space)->cipher.egress.key); |
1503 | 0 | ptls_clear_memory((*space)->cipher.egress.secret, sizeof((*space)->cipher.egress.secret)); |
1504 | 0 | do_free_pn_space(&(*space)->super); |
1505 | 0 | *space = NULL; |
1506 | 0 | } |
1507 | 0 | } |
1508 | | |
1509 | | static int setup_application_space(quicly_conn_t *conn) |
1510 | 0 | { |
1511 | 0 | if ((conn->application = |
1512 | 0 | (void *)alloc_pn_space(sizeof(struct st_quicly_application_space_t), QUICLY_DEFAULT_PACKET_TOLERANCE)) == NULL) |
1513 | 0 | return PTLS_ERROR_NO_MEMORY; |
1514 | | |
1515 | | /* prohibit key-update until receiving an ACK for an 1-RTT packet */ |
1516 | 0 | conn->application->cipher.egress.key_update_pn.last = 0; |
1517 | 0 | conn->application->cipher.egress.key_update_pn.next = UINT64_MAX; |
1518 | |
|
1519 | 0 | return create_handshake_flow(conn, QUICLY_EPOCH_1RTT); |
1520 | 0 | } |
1521 | | |
1522 | | static int discard_handshake_context(quicly_conn_t *conn, size_t epoch) |
1523 | 0 | { |
1524 | 0 | int ret; |
1525 | |
|
1526 | 0 | assert(epoch == QUICLY_EPOCH_INITIAL || epoch == QUICLY_EPOCH_HANDSHAKE); |
1527 | | |
1528 | 0 | if ((ret = discard_sentmap_by_epoch(conn, 1u << epoch)) != 0) |
1529 | 0 | return ret; |
1530 | 0 | destroy_handshake_flow(conn, epoch); |
1531 | 0 | if (epoch == QUICLY_EPOCH_HANDSHAKE) { |
1532 | 0 | assert(conn->stash.now != 0); |
1533 | 0 | conn->super.stats.handshake_confirmed_msec = conn->stash.now - conn->created_at; |
1534 | 0 | } |
1535 | 0 | free_handshake_space(epoch == QUICLY_EPOCH_INITIAL ? &conn->initial : &conn->handshake); |
1536 | |
|
1537 | 0 | return 0; |
1538 | 0 | } |
1539 | | |
1540 | | static int apply_remote_transport_params(quicly_conn_t *conn) |
1541 | 0 | { |
1542 | 0 | int ret; |
1543 | |
|
1544 | 0 | conn->egress.max_data.permitted = conn->super.remote.transport_params.max_data; |
1545 | 0 | if ((ret = update_max_streams(&conn->egress.max_streams.uni, conn->super.remote.transport_params.max_streams_uni)) != 0) |
1546 | 0 | return ret; |
1547 | 0 | if ((ret = update_max_streams(&conn->egress.max_streams.bidi, conn->super.remote.transport_params.max_streams_bidi)) != 0) |
1548 | 0 | return ret; |
1549 | | |
1550 | 0 | return 0; |
1551 | 0 | } |
1552 | | |
1553 | | static int update_1rtt_key(quicly_conn_t *conn, ptls_cipher_suite_t *cipher, int is_enc, ptls_aead_context_t **aead, |
1554 | | uint8_t *secret) |
1555 | 0 | { |
1556 | 0 | uint8_t new_secret[PTLS_MAX_DIGEST_SIZE]; |
1557 | 0 | ptls_aead_context_t *new_aead = NULL; |
1558 | 0 | int ret; |
1559 | | |
1560 | | /* generate next AEAD key */ |
1561 | 0 | if ((ret = ptls_hkdf_expand_label(cipher->hash, new_secret, cipher->hash->digest_size, |
1562 | 0 | ptls_iovec_init(secret, cipher->hash->digest_size), "quic ku", ptls_iovec_init(NULL, 0), |
1563 | 0 | NULL)) != 0) |
1564 | 0 | goto Exit; |
1565 | 0 | if ((ret = setup_cipher(conn, QUICLY_EPOCH_1RTT, is_enc, NULL, &new_aead, cipher->aead, cipher->hash, new_secret)) != 0) |
1566 | 0 | goto Exit; |
1567 | | |
1568 | | /* success! update AEAD and secret */ |
1569 | 0 | if (*aead != NULL) |
1570 | 0 | ptls_aead_free(*aead); |
1571 | 0 | *aead = new_aead; |
1572 | 0 | new_aead = NULL; |
1573 | 0 | memcpy(secret, new_secret, cipher->hash->digest_size); |
1574 | |
|
1575 | 0 | ret = 0; |
1576 | 0 | Exit: |
1577 | 0 | if (new_aead != NULL) |
1578 | 0 | ptls_aead_free(new_aead); |
1579 | 0 | ptls_clear_memory(new_secret, cipher->hash->digest_size); |
1580 | 0 | return ret; |
1581 | 0 | } |
1582 | | |
1583 | | static int update_1rtt_egress_key(quicly_conn_t *conn) |
1584 | 0 | { |
1585 | 0 | struct st_quicly_application_space_t *space = conn->application; |
1586 | 0 | ptls_cipher_suite_t *cipher = ptls_get_cipher(conn->crypto.tls); |
1587 | 0 | int ret; |
1588 | | |
1589 | | /* generate next AEAD key, and increment key phase if it succeeds */ |
1590 | 0 | if ((ret = update_1rtt_key(conn, cipher, 1, &space->cipher.egress.key.aead, space->cipher.egress.secret)) != 0) |
1591 | 0 | return ret; |
1592 | 0 | ++space->cipher.egress.key_phase; |
1593 | | |
1594 | | /* signal that we are waiting for an ACK */ |
1595 | 0 | space->cipher.egress.key_update_pn.last = conn->egress.packet_number; |
1596 | 0 | space->cipher.egress.key_update_pn.next = UINT64_MAX; |
1597 | |
|
1598 | 0 | QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE, conn, conn->stash.now, space->cipher.egress.key_phase, |
1599 | 0 | QUICLY_PROBE_HEXDUMP(space->cipher.egress.secret, cipher->hash->digest_size)); |
1600 | 0 | QUICLY_LOG_CONN(crypto_send_key_update, conn, { |
1601 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.egress.key_phase); |
1602 | 0 | PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(secret, space->cipher.egress.secret, cipher->hash->digest_size); |
1603 | 0 | }); |
1604 | | |
1605 | 0 | return 0; |
1606 | 0 | } |
1607 | | |
1608 | | static int received_key_update(quicly_conn_t *conn, uint64_t newly_decrypted_key_phase) |
1609 | 0 | { |
1610 | 0 | struct st_quicly_application_space_t *space = conn->application; |
1611 | |
|
1612 | 0 | assert(space->cipher.ingress.key_phase.decrypted < newly_decrypted_key_phase); |
1613 | 0 | assert(newly_decrypted_key_phase <= space->cipher.ingress.key_phase.prepared); |
1614 | | |
1615 | 0 | space->cipher.ingress.key_phase.decrypted = newly_decrypted_key_phase; |
1616 | |
|
1617 | 0 | QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE, conn, conn->stash.now, space->cipher.ingress.key_phase.decrypted, |
1618 | 0 | QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, ptls_get_cipher(conn->crypto.tls)->hash->digest_size)); |
1619 | 0 | QUICLY_LOG_CONN(crypto_receive_key_update, conn, { |
1620 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.decrypted); |
1621 | 0 | PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(secret, space->cipher.ingress.secret, |
1622 | 0 | ptls_get_cipher(conn->crypto.tls)->hash->digest_size); |
1623 | 0 | }); |
1624 | | |
1625 | 0 | if (space->cipher.egress.key_phase < space->cipher.ingress.key_phase.decrypted) { |
1626 | 0 | return update_1rtt_egress_key(conn); |
1627 | 0 | } else { |
1628 | 0 | return 0; |
1629 | 0 | } |
1630 | 0 | } |
1631 | | |
1632 | | static inline void update_open_count(quicly_context_t *ctx, ssize_t delta) |
1633 | 0 | { |
1634 | 0 | if (ctx->update_open_count != NULL) |
1635 | 0 | ctx->update_open_count->cb(ctx->update_open_count, delta); |
1636 | 0 | } |
1637 | | |
1638 | | void quicly_free(quicly_conn_t *conn) |
1639 | 0 | { |
1640 | 0 | lock_now(conn, 0); |
1641 | |
|
1642 | 0 | QUICLY_PROBE(FREE, conn, conn->stash.now); |
1643 | 0 | QUICLY_LOG_CONN(free, conn, {}); |
1644 | | |
1645 | | #if QUICLY_USE_DTRACE |
1646 | | if (QUICLY_CONN_STATS_ENABLED()) { |
1647 | | quicly_stats_t stats; |
1648 | | quicly_get_stats(conn, &stats); |
1649 | | QUICLY_PROBE(CONN_STATS, conn, conn->stash.now, &stats, sizeof(stats)); |
1650 | | // TODO: emit stats with QUICLY_LOG_CONN() |
1651 | | } |
1652 | | #endif |
1653 | 0 | destroy_all_streams(conn, 0, 1); |
1654 | 0 | update_open_count(conn->super.ctx, -1); |
1655 | 0 | clear_datagram_frame_payloads(conn); |
1656 | |
|
1657 | 0 | quicly_maxsender_dispose(&conn->ingress.max_data.sender); |
1658 | 0 | quicly_maxsender_dispose(&conn->ingress.max_streams.uni); |
1659 | 0 | quicly_maxsender_dispose(&conn->ingress.max_streams.bidi); |
1660 | 0 | while (conn->egress.path_challenge.head != NULL) { |
1661 | 0 | struct st_quicly_pending_path_challenge_t *pending = conn->egress.path_challenge.head; |
1662 | 0 | conn->egress.path_challenge.head = pending->next; |
1663 | 0 | free(pending); |
1664 | 0 | } |
1665 | 0 | quicly_loss_dispose(&conn->egress.loss); |
1666 | |
|
1667 | 0 | kh_destroy(quicly_stream_t, conn->streams); |
1668 | |
|
1669 | 0 | assert(!quicly_linklist_is_linked(&conn->egress.pending_streams.blocked.uni)); |
1670 | 0 | assert(!quicly_linklist_is_linked(&conn->egress.pending_streams.blocked.bidi)); |
1671 | 0 | assert(!quicly_linklist_is_linked(&conn->egress.pending_streams.control)); |
1672 | 0 | assert(!quicly_linklist_is_linked(&conn->super._default_scheduler.active)); |
1673 | 0 | assert(!quicly_linklist_is_linked(&conn->super._default_scheduler.blocked)); |
1674 | | |
1675 | 0 | free_handshake_space(&conn->initial); |
1676 | 0 | free_handshake_space(&conn->handshake); |
1677 | 0 | free_application_space(&conn->application); |
1678 | |
|
1679 | 0 | ptls_buffer_dispose(&conn->crypto.transport_params.buf); |
1680 | 0 | if (conn->crypto.async_in_progress) { |
1681 | | /* When async signature generation is inflight, `ptls_free` will be called from `quicly_resume_handshake` laterwards. */ |
1682 | 0 | *ptls_get_data_ptr(conn->crypto.tls) = NULL; |
1683 | 0 | } else { |
1684 | 0 | ptls_free(conn->crypto.tls); |
1685 | 0 | } |
1686 | |
|
1687 | 0 | unlock_now(conn); |
1688 | |
|
1689 | 0 | free(conn->token.base); |
1690 | 0 | free(conn); |
1691 | 0 | } |
1692 | | |
1693 | | static int setup_initial_key(struct st_quicly_cipher_context_t *ctx, ptls_cipher_suite_t *cs, const void *master_secret, |
1694 | | const char *label, int is_enc, quicly_conn_t *conn) |
1695 | 0 | { |
1696 | 0 | uint8_t aead_secret[PTLS_MAX_DIGEST_SIZE]; |
1697 | 0 | int ret; |
1698 | |
|
1699 | 0 | if ((ret = ptls_hkdf_expand_label(cs->hash, aead_secret, cs->hash->digest_size, |
1700 | 0 | ptls_iovec_init(master_secret, cs->hash->digest_size), label, ptls_iovec_init(NULL, 0), |
1701 | 0 | NULL)) != 0) |
1702 | 0 | goto Exit; |
1703 | 0 | if ((ret = setup_cipher(conn, QUICLY_EPOCH_INITIAL, is_enc, &ctx->header_protection, &ctx->aead, cs->aead, cs->hash, |
1704 | 0 | aead_secret)) != 0) |
1705 | 0 | goto Exit; |
1706 | | |
1707 | 0 | Exit: |
1708 | 0 | ptls_clear_memory(aead_secret, sizeof(aead_secret)); |
1709 | 0 | return ret; |
1710 | 0 | } |
1711 | | |
1712 | | /** |
1713 | | * @param conn maybe NULL when called by quicly_accept |
1714 | | */ |
1715 | | static int setup_initial_encryption(ptls_cipher_suite_t *cs, struct st_quicly_cipher_context_t *ingress, |
1716 | | struct st_quicly_cipher_context_t *egress, ptls_iovec_t cid, int is_client, ptls_iovec_t salt, |
1717 | | quicly_conn_t *conn) |
1718 | 0 | { |
1719 | 0 | static const char *labels[2] = {"client in", "server in"}; |
1720 | 0 | uint8_t secret[PTLS_MAX_DIGEST_SIZE]; |
1721 | 0 | int ret; |
1722 | | |
1723 | | /* extract master secret */ |
1724 | 0 | if ((ret = ptls_hkdf_extract(cs->hash, secret, salt, cid)) != 0) |
1725 | 0 | goto Exit; |
1726 | | |
1727 | | /* create aead contexts */ |
1728 | 0 | if (ingress != NULL && (ret = setup_initial_key(ingress, cs, secret, labels[is_client], 0, conn)) != 0) |
1729 | 0 | goto Exit; |
1730 | 0 | if (egress != NULL && (ret = setup_initial_key(egress, cs, secret, labels[!is_client], 1, conn)) != 0) { |
1731 | 0 | if (ingress != NULL) |
1732 | 0 | dispose_cipher(ingress); |
1733 | 0 | goto Exit; |
1734 | 0 | } |
1735 | | |
1736 | 0 | Exit: |
1737 | 0 | ptls_clear_memory(secret, sizeof(secret)); |
1738 | 0 | return ret; |
1739 | 0 | } |
1740 | | |
1741 | | static int reinstall_initial_encryption(quicly_conn_t *conn, int err_code_if_unknown_version) |
1742 | 0 | { |
1743 | 0 | const struct st_ptls_salt_t *salt; |
1744 | | |
1745 | | /* get salt */ |
1746 | 0 | if ((salt = get_salt(conn->super.version)) == NULL) |
1747 | 0 | return err_code_if_unknown_version; |
1748 | | |
1749 | | /* dispose existing context */ |
1750 | 0 | dispose_cipher(&conn->initial->cipher.ingress); |
1751 | 0 | dispose_cipher(&conn->initial->cipher.egress); |
1752 | | |
1753 | | /* setup encryption context */ |
1754 | 0 | return setup_initial_encryption( |
1755 | 0 | get_aes128gcmsha256(conn->super.ctx), &conn->initial->cipher.ingress, &conn->initial->cipher.egress, |
1756 | 0 | ptls_iovec_init(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len), 1, |
1757 | 0 | ptls_iovec_init(salt->initial, sizeof(salt->initial)), NULL); |
1758 | 0 | } |
1759 | | |
1760 | | static int apply_stream_frame(quicly_stream_t *stream, quicly_stream_frame_t *frame) |
1761 | 0 | { |
1762 | 0 | int ret; |
1763 | |
|
1764 | 0 | QUICLY_PROBE(STREAM_RECEIVE, stream->conn, stream->conn->stash.now, stream, frame->offset, frame->data.len); |
1765 | 0 | QUICLY_LOG_CONN(stream_receive, stream->conn, { |
1766 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
1767 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(off, frame->offset); |
1768 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(len, frame->data.len); |
1769 | 0 | }); |
1770 | | |
1771 | 0 | if (quicly_recvstate_transfer_complete(&stream->recvstate)) |
1772 | 0 | return 0; |
1773 | | |
1774 | | /* flow control */ |
1775 | 0 | if (stream->stream_id >= 0) { |
1776 | | /* STREAMs */ |
1777 | 0 | uint64_t max_stream_data = frame->offset + frame->data.len; |
1778 | 0 | if ((int64_t)stream->_recv_aux.window < (int64_t)max_stream_data - (int64_t)stream->recvstate.data_off) |
1779 | 0 | return QUICLY_TRANSPORT_ERROR_FLOW_CONTROL; |
1780 | 0 | if (stream->recvstate.received.ranges[stream->recvstate.received.num_ranges - 1].end < max_stream_data) { |
1781 | 0 | uint64_t newly_received = |
1782 | 0 | max_stream_data - stream->recvstate.received.ranges[stream->recvstate.received.num_ranges - 1].end; |
1783 | 0 | if (stream->conn->ingress.max_data.bytes_consumed + newly_received > |
1784 | 0 | stream->conn->ingress.max_data.sender.max_committed) |
1785 | 0 | return QUICLY_TRANSPORT_ERROR_FLOW_CONTROL; |
1786 | 0 | stream->conn->ingress.max_data.bytes_consumed += newly_received; |
1787 | | /* FIXME send MAX_DATA if necessary */ |
1788 | 0 | } |
1789 | 0 | } else { |
1790 | | /* CRYPTO streams; maybe add different limit for 1-RTT CRYPTO? */ |
1791 | 0 | if (frame->offset + frame->data.len > stream->conn->super.ctx->max_crypto_bytes) |
1792 | 0 | return QUICLY_TRANSPORT_ERROR_CRYPTO_BUFFER_EXCEEDED; |
1793 | 0 | } |
1794 | | |
1795 | | /* update recvbuf */ |
1796 | 0 | size_t apply_len = frame->data.len; |
1797 | 0 | if ((ret = quicly_recvstate_update(&stream->recvstate, frame->offset, &apply_len, frame->is_fin, |
1798 | 0 | stream->_recv_aux.max_ranges)) != 0) |
1799 | 0 | return ret; |
1800 | | |
1801 | 0 | if (apply_len != 0 || quicly_recvstate_transfer_complete(&stream->recvstate)) { |
1802 | 0 | uint64_t buf_offset = frame->offset + frame->data.len - apply_len - stream->recvstate.data_off; |
1803 | 0 | const void *apply_src = frame->data.base + frame->data.len - apply_len; |
1804 | 0 | QUICLY_PROBE(STREAM_ON_RECEIVE, stream->conn, stream->conn->stash.now, stream, (size_t)buf_offset, apply_src, apply_len); |
1805 | 0 | QUICLY_LOG_CONN(stream_on_receive, stream->conn, { |
1806 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
1807 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(off, buf_offset); |
1808 | 0 | PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(src, apply_src, apply_len); |
1809 | 0 | }); |
1810 | 0 | stream->callbacks->on_receive(stream, (size_t)buf_offset, apply_src, apply_len); |
1811 | 0 | if (stream->conn->super.state >= QUICLY_STATE_CLOSING) |
1812 | 0 | return QUICLY_ERROR_IS_CLOSING; |
1813 | 0 | } |
1814 | | |
1815 | 0 | if (should_send_max_stream_data(stream)) |
1816 | 0 | sched_stream_control(stream); |
1817 | |
|
1818 | 0 | if (stream_is_destroyable(stream)) |
1819 | 0 | destroy_stream(stream, 0); |
1820 | |
|
1821 | 0 | return 0; |
1822 | 0 | } |
1823 | | |
1824 | | int quicly_encode_transport_parameter_list(ptls_buffer_t *buf, const quicly_transport_parameters_t *params, |
1825 | | const quicly_cid_t *original_dcid, const quicly_cid_t *initial_scid, |
1826 | | const quicly_cid_t *retry_scid, const void *stateless_reset_token, size_t expand_by) |
1827 | 0 | { |
1828 | 0 | int ret; |
1829 | |
|
1830 | 0 | #define PUSH_TP(buf, id, block) \ |
1831 | 0 | do { \ |
1832 | 0 | ptls_buffer_push_quicint((buf), (id)); \ |
1833 | 0 | ptls_buffer_push_block((buf), -1, block); \ |
1834 | 0 | } while (0) |
1835 | |
|
1836 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_MAX_UDP_PAYLOAD_SIZE, |
1837 | 0 | { ptls_buffer_push_quicint(buf, params->max_udp_payload_size); }); |
1838 | 0 | if (params->max_stream_data.bidi_local != 0) |
1839 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, |
1840 | 0 | { ptls_buffer_push_quicint(buf, params->max_stream_data.bidi_local); }); |
1841 | 0 | if (params->max_stream_data.bidi_remote != 0) |
1842 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, |
1843 | 0 | { ptls_buffer_push_quicint(buf, params->max_stream_data.bidi_remote); }); |
1844 | 0 | if (params->max_stream_data.uni != 0) |
1845 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_UNI, |
1846 | 0 | { ptls_buffer_push_quicint(buf, params->max_stream_data.uni); }); |
1847 | 0 | if (params->max_data != 0) |
1848 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_DATA, { ptls_buffer_push_quicint(buf, params->max_data); }); |
1849 | 0 | if (params->max_idle_timeout != 0) |
1850 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_MAX_IDLE_TIMEOUT, { ptls_buffer_push_quicint(buf, params->max_idle_timeout); }); |
1851 | 0 | if (original_dcid != NULL) |
1852 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_ORIGINAL_CONNECTION_ID, |
1853 | 0 | { ptls_buffer_pushv(buf, original_dcid->cid, original_dcid->len); }); |
1854 | 0 | if (initial_scid != NULL) |
1855 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_SOURCE_CONNECTION_ID, |
1856 | 0 | { ptls_buffer_pushv(buf, initial_scid->cid, initial_scid->len); }); |
1857 | 0 | if (retry_scid != NULL) |
1858 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_RETRY_SOURCE_CONNECTION_ID, |
1859 | 0 | { ptls_buffer_pushv(buf, retry_scid->cid, retry_scid->len); }); |
1860 | 0 | if (stateless_reset_token != NULL) |
1861 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_STATELESS_RESET_TOKEN, |
1862 | 0 | { ptls_buffer_pushv(buf, stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN); }); |
1863 | 0 | if (params->max_streams_bidi != 0) |
1864 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAMS_BIDI, |
1865 | 0 | { ptls_buffer_push_quicint(buf, params->max_streams_bidi); }); |
1866 | 0 | if (params->max_streams_uni != 0) |
1867 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAMS_UNI, |
1868 | 0 | { ptls_buffer_push_quicint(buf, params->max_streams_uni); }); |
1869 | 0 | if (QUICLY_LOCAL_ACK_DELAY_EXPONENT != QUICLY_DEFAULT_ACK_DELAY_EXPONENT) |
1870 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_ACK_DELAY_EXPONENT, |
1871 | 0 | { ptls_buffer_push_quicint(buf, QUICLY_LOCAL_ACK_DELAY_EXPONENT); }); |
1872 | 0 | if (QUICLY_LOCAL_MAX_ACK_DELAY != QUICLY_DEFAULT_MAX_ACK_DELAY) |
1873 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_MAX_ACK_DELAY, { ptls_buffer_push_quicint(buf, QUICLY_LOCAL_MAX_ACK_DELAY); }); |
1874 | 0 | if (params->min_ack_delay_usec != UINT64_MAX) { |
1875 | | /* TODO consider the value we should advertise. */ |
1876 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_MIN_ACK_DELAY, |
1877 | 0 | { ptls_buffer_push_quicint(buf, QUICLY_LOCAL_MAX_ACK_DELAY * 1000 /* in microseconds */); }); |
1878 | 0 | } |
1879 | 0 | if (params->disable_active_migration) |
1880 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_DISABLE_ACTIVE_MIGRATION, {}); |
1881 | 0 | if (QUICLY_LOCAL_ACTIVE_CONNECTION_ID_LIMIT != QUICLY_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) |
1882 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_ACTIVE_CONNECTION_ID_LIMIT, |
1883 | 0 | { ptls_buffer_push_quicint(buf, QUICLY_LOCAL_ACTIVE_CONNECTION_ID_LIMIT); }); |
1884 | 0 | if (params->max_datagram_frame_size != 0) |
1885 | 0 | PUSH_TP(buf, QUICLY_TRANSPORT_PARAMETER_ID_MAX_DATAGRAM_FRAME_SIZE, |
1886 | 0 | { ptls_buffer_push_quicint(buf, params->max_datagram_frame_size); }); |
1887 | | /* if requested, add a greasing TP of 1 MTU size so that CH spans across multiple packets */ |
1888 | 0 | if (expand_by != 0) { |
1889 | 0 | PUSH_TP(buf, 31 * 100 + 27, { |
1890 | 0 | if ((ret = ptls_buffer_reserve(buf, expand_by)) != 0) |
1891 | 0 | goto Exit; |
1892 | 0 | memset(buf->base + buf->off, 0, expand_by); |
1893 | 0 | buf->off += expand_by; |
1894 | 0 | }); |
1895 | 0 | } |
1896 | | |
1897 | 0 | #undef PUSH_TP |
1898 | | |
1899 | 0 | ret = 0; |
1900 | 0 | Exit: |
1901 | 0 | return ret; |
1902 | 0 | } |
1903 | | |
1904 | | /** |
1905 | | * sentinel used for indicating that the corresponding TP should be ignored |
1906 | | */ |
1907 | | static const quicly_cid_t _tp_cid_ignore; |
1908 | 0 | #define tp_cid_ignore (*(quicly_cid_t *)&_tp_cid_ignore) |
1909 | | |
1910 | | int quicly_decode_transport_parameter_list(quicly_transport_parameters_t *params, quicly_cid_t *original_dcid, |
1911 | | quicly_cid_t *initial_scid, quicly_cid_t *retry_scid, void *stateless_reset_token, |
1912 | | const uint8_t *src, const uint8_t *end) |
1913 | 0 | { |
1914 | | /* When non-negative, tp_index contains the literal position within the list of transport parameters recognized by this function. |
1915 | | * That index is being used to find duplicates using a 64-bit bitmap (found_bits). When the transport parameter is being processed, |
1916 | | * tp_index is set to -1. */ |
1917 | 0 | #define DECODE_TP(_id, block) \ |
1918 | 0 | do { \ |
1919 | 0 | if (tp_index >= 0) { \ |
1920 | 0 | if (id == (_id)) { \ |
1921 | 0 | if ((found_bits & ((uint64_t)1 << tp_index)) != 0) { \ |
1922 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; \ |
1923 | 0 | goto Exit; \ |
1924 | 0 | } \ |
1925 | 0 | found_bits |= (uint64_t)1 << tp_index; \ |
1926 | 0 | {block} tp_index = -1; \ |
1927 | 0 | } else { \ |
1928 | 0 | ++tp_index; \ |
1929 | 0 | } \ |
1930 | 0 | } \ |
1931 | 0 | } while (0) |
1932 | 0 | #define DECODE_CID_TP(_id, dest) \ |
1933 | 0 | DECODE_TP(_id, { \ |
1934 | 0 | size_t cidl = end - src; \ |
1935 | 0 | if (cidl > QUICLY_MAX_CID_LEN_V1) { \ |
1936 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; \ |
1937 | 0 | goto Exit; \ |
1938 | 0 | } \ |
1939 | 0 | if (dest == NULL) { \ |
1940 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; \ |
1941 | 0 | goto Exit; \ |
1942 | 0 | } else if (dest != &tp_cid_ignore) { \ |
1943 | 0 | quicly_set_cid(dest, ptls_iovec_init(src, cidl)); \ |
1944 | 0 | } \ |
1945 | 0 | src = end; \ |
1946 | 0 | }); |
1947 | |
|
1948 | 0 | uint64_t found_bits = 0; |
1949 | 0 | int ret; |
1950 | | |
1951 | | /* set parameters to their default values */ |
1952 | 0 | *params = default_transport_params; |
1953 | | |
1954 | | /* Set optional parameters to UINT8_MAX. It is used to as a sentinel for detecting missing TPs. */ |
1955 | 0 | if (original_dcid != NULL && original_dcid != &tp_cid_ignore) |
1956 | 0 | original_dcid->len = UINT8_MAX; |
1957 | 0 | if (initial_scid != NULL && initial_scid != &tp_cid_ignore) |
1958 | 0 | initial_scid->len = UINT8_MAX; |
1959 | 0 | if (retry_scid != NULL && retry_scid != &tp_cid_ignore) |
1960 | 0 | retry_scid->len = UINT8_MAX; |
1961 | | |
1962 | | /* decode the parameters block */ |
1963 | 0 | while (src != end) { |
1964 | 0 | uint64_t id; |
1965 | 0 | if ((id = quicly_decodev(&src, end)) == UINT64_MAX) { |
1966 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
1967 | 0 | goto Exit; |
1968 | 0 | } |
1969 | 0 | int tp_index = 0; |
1970 | 0 | ptls_decode_open_block(src, end, -1, { |
1971 | 0 | DECODE_CID_TP(QUICLY_TRANSPORT_PARAMETER_ID_ORIGINAL_CONNECTION_ID, original_dcid); |
1972 | 0 | DECODE_CID_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_SOURCE_CONNECTION_ID, initial_scid); |
1973 | 0 | DECODE_CID_TP(QUICLY_TRANSPORT_PARAMETER_ID_RETRY_SOURCE_CONNECTION_ID, retry_scid); |
1974 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_MAX_UDP_PAYLOAD_SIZE, { |
1975 | 0 | uint64_t v; |
1976 | 0 | if ((v = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
1977 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
1978 | 0 | goto Exit; |
1979 | 0 | } |
1980 | 0 | if (v < 1200) { |
1981 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
1982 | 0 | goto Exit; |
1983 | 0 | } |
1984 | 0 | if (v > UINT16_MAX) |
1985 | 0 | v = UINT16_MAX; |
1986 | 0 | params->max_udp_payload_size = (uint16_t)v; |
1987 | 0 | }); |
1988 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, { |
1989 | 0 | if ((params->max_stream_data.bidi_local = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
1990 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
1991 | 0 | goto Exit; |
1992 | 0 | } |
1993 | 0 | }); |
1994 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, { |
1995 | 0 | if ((params->max_stream_data.bidi_remote = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
1996 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
1997 | 0 | goto Exit; |
1998 | 0 | } |
1999 | 0 | }); |
2000 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_UNI, { |
2001 | 0 | if ((params->max_stream_data.uni = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2002 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2003 | 0 | goto Exit; |
2004 | 0 | } |
2005 | 0 | }); |
2006 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_DATA, { |
2007 | 0 | if ((params->max_data = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2008 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2009 | 0 | goto Exit; |
2010 | 0 | } |
2011 | 0 | }); |
2012 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_STATELESS_RESET_TOKEN, { |
2013 | 0 | if (!(stateless_reset_token != NULL && end - src == QUICLY_STATELESS_RESET_TOKEN_LEN)) { |
2014 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2015 | 0 | goto Exit; |
2016 | 0 | } |
2017 | 0 | memcpy(stateless_reset_token, src, QUICLY_STATELESS_RESET_TOKEN_LEN); |
2018 | 0 | src = end; |
2019 | 0 | }); |
2020 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_MAX_IDLE_TIMEOUT, { |
2021 | 0 | if ((params->max_idle_timeout = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2022 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2023 | 0 | goto Exit; |
2024 | 0 | } |
2025 | 0 | }); |
2026 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAMS_BIDI, { |
2027 | 0 | if ((params->max_streams_bidi = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2028 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2029 | 0 | goto Exit; |
2030 | 0 | } |
2031 | 0 | }); |
2032 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAMS_UNI, { |
2033 | 0 | if ((params->max_streams_uni = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2034 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2035 | 0 | goto Exit; |
2036 | 0 | } |
2037 | 0 | }); |
2038 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_ACK_DELAY_EXPONENT, { |
2039 | 0 | uint64_t v; |
2040 | 0 | if ((v = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2041 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2042 | 0 | goto Exit; |
2043 | 0 | } |
2044 | 0 | if (v > 20) { |
2045 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2046 | 0 | goto Exit; |
2047 | 0 | } |
2048 | 0 | params->ack_delay_exponent = (uint8_t)v; |
2049 | 0 | }); |
2050 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_MAX_ACK_DELAY, { |
2051 | 0 | uint64_t v; |
2052 | 0 | if ((v = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2053 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2054 | 0 | goto Exit; |
2055 | 0 | } |
2056 | 0 | if (v >= 16384) { /* "values of 2^14 or greater are invalid" */ |
2057 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2058 | 0 | goto Exit; |
2059 | 0 | } |
2060 | 0 | params->max_ack_delay = (uint16_t)v; |
2061 | 0 | }); |
2062 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_MIN_ACK_DELAY, { |
2063 | 0 | if ((params->min_ack_delay_usec = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2064 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2065 | 0 | goto Exit; |
2066 | 0 | } |
2067 | 0 | if (params->min_ack_delay_usec >= 16777216) { /* "values of 2^24 or greater are invalid" */ |
2068 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2069 | 0 | goto Exit; |
2070 | 0 | } |
2071 | 0 | }); |
2072 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_ACTIVE_CONNECTION_ID_LIMIT, { |
2073 | 0 | uint64_t v; |
2074 | 0 | if ((v = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2075 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2076 | 0 | goto Exit; |
2077 | 0 | } |
2078 | 0 | if (v < QUICLY_MIN_ACTIVE_CONNECTION_ID_LIMIT) { |
2079 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2080 | 0 | goto Exit; |
2081 | 0 | } |
2082 | 0 | params->active_connection_id_limit = v; |
2083 | 0 | }); |
2084 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_DISABLE_ACTIVE_MIGRATION, { params->disable_active_migration = 1; }); |
2085 | 0 | DECODE_TP(QUICLY_TRANSPORT_PARAMETER_ID_MAX_DATAGRAM_FRAME_SIZE, { |
2086 | 0 | uint64_t v; |
2087 | 0 | if ((v = ptls_decode_quicint(&src, end)) == UINT64_MAX) { |
2088 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2089 | 0 | goto Exit; |
2090 | 0 | } |
2091 | 0 | if (v > UINT16_MAX) |
2092 | 0 | v = UINT16_MAX; |
2093 | 0 | params->max_datagram_frame_size = (uint16_t)v; |
2094 | 0 | }); |
2095 | | /* skip unknown extension */ |
2096 | 0 | if (tp_index >= 0) |
2097 | 0 | src = end; |
2098 | 0 | }); |
2099 | 0 | } |
2100 | | |
2101 | | /* check consistency between the transport parameters */ |
2102 | 0 | if (params->min_ack_delay_usec != UINT64_MAX) { |
2103 | 0 | if (params->min_ack_delay_usec > params->max_ack_delay * 1000) { |
2104 | 0 | ret = QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
2105 | 0 | goto Exit; |
2106 | 0 | } |
2107 | 0 | } |
2108 | | |
2109 | | /* check the absence of CIDs */ |
2110 | 0 | if ((original_dcid != NULL && original_dcid->len == UINT8_MAX) || (initial_scid != NULL && initial_scid->len == UINT8_MAX) || |
2111 | 0 | (retry_scid != NULL && retry_scid->len == UINT8_MAX)) { |
2112 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2113 | 0 | goto Exit; |
2114 | 0 | } |
2115 | | |
2116 | 0 | ret = 0; |
2117 | 0 | Exit: |
2118 | 0 | if (ret == PTLS_ALERT_DECODE_ERROR) |
2119 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2120 | 0 | return ret; |
2121 | |
|
2122 | 0 | #undef DECODE_TP |
2123 | 0 | #undef DECODE_CID_TP |
2124 | 0 | } |
2125 | | |
2126 | | static uint16_t get_transport_parameters_extension_id(uint32_t quic_version) |
2127 | 0 | { |
2128 | 0 | switch (quic_version) { |
2129 | 0 | case QUICLY_PROTOCOL_VERSION_DRAFT27: |
2130 | 0 | case QUICLY_PROTOCOL_VERSION_DRAFT29: |
2131 | 0 | return QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_DRAFT; |
2132 | 0 | default: |
2133 | 0 | return QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_FINAL; |
2134 | 0 | } |
2135 | 0 | } |
2136 | | |
2137 | | static int collect_transport_parameters(ptls_t *tls, struct st_ptls_handshake_properties_t *properties, uint16_t type) |
2138 | 0 | { |
2139 | 0 | quicly_conn_t *conn = (void *)((char *)properties - offsetof(quicly_conn_t, crypto.handshake_properties)); |
2140 | 0 | return type == get_transport_parameters_extension_id(conn->super.version); |
2141 | 0 | } |
2142 | | |
2143 | | static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol_version, const char *server_name, |
2144 | | struct sockaddr *remote_addr, struct sockaddr *local_addr, ptls_iovec_t *remote_cid, |
2145 | | const quicly_cid_plaintext_t *local_cid, ptls_handshake_properties_t *handshake_properties, |
2146 | | void *appdata, uint32_t initcwnd) |
2147 | 0 | { |
2148 | 0 | ptls_t *tls = NULL; |
2149 | 0 | quicly_conn_t *conn; |
2150 | | |
2151 | | /* consistency checks */ |
2152 | 0 | assert(remote_addr != NULL && remote_addr->sa_family != AF_UNSPEC); |
2153 | 0 | if (ctx->transport_params.max_datagram_frame_size != 0) |
2154 | 0 | assert(ctx->receive_datagram_frame != NULL); |
2155 | | |
2156 | | /* create TLS context */ |
2157 | 0 | if ((tls = ptls_new(ctx->tls, server_name == NULL)) == NULL) |
2158 | 0 | return NULL; |
2159 | 0 | if (server_name != NULL && ptls_set_server_name(tls, server_name, strlen(server_name)) != 0) { |
2160 | 0 | ptls_free(tls); |
2161 | 0 | return NULL; |
2162 | 0 | } |
2163 | | |
2164 | | /* allocate memory and start creating QUIC context */ |
2165 | 0 | if ((conn = malloc(sizeof(*conn))) == NULL) { |
2166 | 0 | ptls_free(tls); |
2167 | 0 | return NULL; |
2168 | 0 | } |
2169 | 0 | memset(conn, 0, sizeof(*conn)); |
2170 | 0 | conn->super.ctx = ctx; |
2171 | 0 | conn->super.data = appdata; |
2172 | 0 | lock_now(conn, 0); |
2173 | 0 | conn->created_at = conn->stash.now; |
2174 | 0 | conn->super.stats.handshake_confirmed_msec = UINT64_MAX; |
2175 | 0 | set_address(&conn->super.local.address, local_addr); |
2176 | 0 | set_address(&conn->super.remote.address, remote_addr); |
2177 | 0 | quicly_local_cid_init_set(&conn->super.local.cid_set, ctx->cid_encryptor, local_cid); |
2178 | 0 | conn->super.local.long_header_src_cid = conn->super.local.cid_set.cids[0].cid; |
2179 | 0 | quicly_remote_cid_init_set(&conn->super.remote.cid_set, remote_cid, ctx->tls->random_bytes); |
2180 | 0 | conn->super.state = QUICLY_STATE_FIRSTFLIGHT; |
2181 | 0 | if (server_name != NULL) { |
2182 | 0 | conn->super.local.bidi.next_stream_id = 0; |
2183 | 0 | conn->super.local.uni.next_stream_id = 2; |
2184 | 0 | conn->super.remote.bidi.next_stream_id = 1; |
2185 | 0 | conn->super.remote.uni.next_stream_id = 3; |
2186 | 0 | } else { |
2187 | 0 | conn->super.local.bidi.next_stream_id = 1; |
2188 | 0 | conn->super.local.uni.next_stream_id = 3; |
2189 | 0 | conn->super.remote.bidi.next_stream_id = 0; |
2190 | 0 | conn->super.remote.uni.next_stream_id = 2; |
2191 | 0 | } |
2192 | 0 | conn->super.remote.transport_params = default_transport_params; |
2193 | 0 | conn->super.version = protocol_version; |
2194 | 0 | conn->super.remote.largest_retire_prior_to = 0; |
2195 | 0 | quicly_linklist_init(&conn->super._default_scheduler.active); |
2196 | 0 | quicly_linklist_init(&conn->super._default_scheduler.blocked); |
2197 | 0 | conn->streams = kh_init(quicly_stream_t); |
2198 | 0 | quicly_maxsender_init(&conn->ingress.max_data.sender, conn->super.ctx->transport_params.max_data); |
2199 | 0 | quicly_maxsender_init(&conn->ingress.max_streams.uni, conn->super.ctx->transport_params.max_streams_uni); |
2200 | 0 | quicly_maxsender_init(&conn->ingress.max_streams.bidi, conn->super.ctx->transport_params.max_streams_bidi); |
2201 | 0 | quicly_loss_init(&conn->egress.loss, &conn->super.ctx->loss, |
2202 | 0 | conn->super.ctx->loss.default_initial_rtt /* FIXME remember initial_rtt in session ticket */, |
2203 | 0 | &conn->super.remote.transport_params.max_ack_delay, &conn->super.remote.transport_params.ack_delay_exponent); |
2204 | 0 | conn->egress.next_pn_to_skip = |
2205 | 0 | calc_next_pn_to_skip(conn->super.ctx->tls, 0, initcwnd, conn->super.ctx->initial_egress_max_udp_payload_size); |
2206 | 0 | conn->egress.max_udp_payload_size = conn->super.ctx->initial_egress_max_udp_payload_size; |
2207 | 0 | init_max_streams(&conn->egress.max_streams.uni); |
2208 | 0 | init_max_streams(&conn->egress.max_streams.bidi); |
2209 | 0 | conn->egress.path_challenge.tail_ref = &conn->egress.path_challenge.head; |
2210 | 0 | conn->egress.ack_frequency.update_at = INT64_MAX; |
2211 | 0 | conn->egress.send_ack_at = INT64_MAX; |
2212 | 0 | conn->super.ctx->init_cc->cb(conn->super.ctx->init_cc, &conn->egress.cc, initcwnd, conn->stash.now); |
2213 | 0 | quicly_retire_cid_init(&conn->egress.retire_cid); |
2214 | 0 | quicly_linklist_init(&conn->egress.pending_streams.blocked.uni); |
2215 | 0 | quicly_linklist_init(&conn->egress.pending_streams.blocked.bidi); |
2216 | 0 | quicly_linklist_init(&conn->egress.pending_streams.control); |
2217 | 0 | quicly_ratemeter_init(&conn->egress.ratemeter); |
2218 | 0 | conn->crypto.tls = tls; |
2219 | 0 | if (handshake_properties != NULL) { |
2220 | 0 | assert(handshake_properties->additional_extensions == NULL); |
2221 | 0 | assert(handshake_properties->collect_extension == NULL); |
2222 | 0 | assert(handshake_properties->collected_extensions == NULL); |
2223 | 0 | conn->crypto.handshake_properties = *handshake_properties; |
2224 | 0 | } else { |
2225 | 0 | conn->crypto.handshake_properties = (ptls_handshake_properties_t){{{{NULL}}}}; |
2226 | 0 | } |
2227 | 0 | conn->crypto.handshake_properties.collect_extension = collect_transport_parameters; |
2228 | 0 | conn->retry_scid.len = UINT8_MAX; |
2229 | 0 | conn->idle_timeout.at = INT64_MAX; |
2230 | 0 | conn->idle_timeout.should_rearm_on_send = 1; |
2231 | 0 | conn->stash.on_ack_stream.active_acked_cache.stream_id = INT64_MIN; |
2232 | |
|
2233 | 0 | *ptls_get_data_ptr(tls) = conn; |
2234 | |
|
2235 | 0 | update_open_count(conn->super.ctx, 1); |
2236 | |
|
2237 | 0 | return conn; |
2238 | 0 | } |
2239 | | |
2240 | | static int client_collected_extensions(ptls_t *tls, ptls_handshake_properties_t *properties, ptls_raw_extension_t *slots) |
2241 | 0 | { |
2242 | 0 | quicly_conn_t *conn = (void *)((char *)properties - offsetof(quicly_conn_t, crypto.handshake_properties)); |
2243 | 0 | int ret; |
2244 | |
|
2245 | 0 | assert(properties->client.early_data_acceptance != PTLS_EARLY_DATA_ACCEPTANCE_UNKNOWN); |
2246 | | |
2247 | 0 | if (slots[0].type == UINT16_MAX) { |
2248 | 0 | ret = PTLS_ALERT_MISSING_EXTENSION; |
2249 | 0 | goto Exit; |
2250 | 0 | } |
2251 | 0 | assert(slots[0].type == get_transport_parameters_extension_id(conn->super.version)); |
2252 | 0 | assert(slots[1].type == UINT16_MAX); |
2253 | | |
2254 | 0 | const uint8_t *src = slots[0].data.base, *end = src + slots[0].data.len; |
2255 | 0 | quicly_transport_parameters_t params; |
2256 | 0 | quicly_cid_t original_dcid, initial_scid, retry_scid = {}; |
2257 | | |
2258 | | /* obtain pointer to initial CID of the peer. It is guaranteed to exist in the first slot, as TP is received before any frame |
2259 | | * that updates the CID set. */ |
2260 | 0 | quicly_remote_cid_t *remote_cid = &conn->super.remote.cid_set.cids[0]; |
2261 | 0 | assert(remote_cid->sequence == 0); |
2262 | | |
2263 | | /* decode */ |
2264 | 0 | if ((ret = quicly_decode_transport_parameter_list(¶ms, needs_cid_auth(conn) || is_retry(conn) ? &original_dcid : NULL, |
2265 | 0 | needs_cid_auth(conn) ? &initial_scid : &tp_cid_ignore, |
2266 | 0 | needs_cid_auth(conn) ? is_retry(conn) ? &retry_scid : NULL : &tp_cid_ignore, |
2267 | 0 | remote_cid->stateless_reset_token, src, end)) != 0) |
2268 | 0 | goto Exit; |
2269 | | |
2270 | | /* validate CIDs */ |
2271 | 0 | if (needs_cid_auth(conn) || is_retry(conn)) { |
2272 | 0 | if (!quicly_cid_is_equal(&conn->super.original_dcid, ptls_iovec_init(original_dcid.cid, original_dcid.len))) { |
2273 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2274 | 0 | goto Exit; |
2275 | 0 | } |
2276 | 0 | } |
2277 | 0 | if (needs_cid_auth(conn)) { |
2278 | 0 | if (!quicly_cid_is_equal(&remote_cid->cid, ptls_iovec_init(initial_scid.cid, initial_scid.len))) { |
2279 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2280 | 0 | goto Exit; |
2281 | 0 | } |
2282 | 0 | if (is_retry(conn)) { |
2283 | 0 | if (!quicly_cid_is_equal(&conn->retry_scid, ptls_iovec_init(retry_scid.cid, retry_scid.len))) { |
2284 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; |
2285 | 0 | goto Exit; |
2286 | 0 | } |
2287 | 0 | } |
2288 | 0 | } |
2289 | | |
2290 | 0 | if (properties->client.early_data_acceptance == PTLS_EARLY_DATA_ACCEPTED) { |
2291 | 0 | #define ZERORTT_VALIDATE(x) \ |
2292 | 0 | if (params.x < conn->super.remote.transport_params.x) { \ |
2293 | 0 | ret = QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER; \ |
2294 | 0 | goto Exit; \ |
2295 | 0 | } |
2296 | 0 | ZERORTT_VALIDATE(max_data); |
2297 | 0 | ZERORTT_VALIDATE(max_stream_data.bidi_local); |
2298 | 0 | ZERORTT_VALIDATE(max_stream_data.bidi_remote); |
2299 | 0 | ZERORTT_VALIDATE(max_stream_data.uni); |
2300 | 0 | ZERORTT_VALIDATE(max_streams_bidi); |
2301 | 0 | ZERORTT_VALIDATE(max_streams_uni); |
2302 | 0 | #undef ZERORTT_VALIDATE |
2303 | 0 | } |
2304 | | |
2305 | | /* store the results */ |
2306 | 0 | conn->super.remote.transport_params = params; |
2307 | 0 | ack_frequency_set_next_update_at(conn); |
2308 | |
|
2309 | 0 | Exit: |
2310 | 0 | return ret; /* negative error codes used to transmit QUIC errors through picotls */ |
2311 | 0 | } |
2312 | | |
2313 | | int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *server_name, struct sockaddr *dest_addr, |
2314 | | struct sockaddr *src_addr, const quicly_cid_plaintext_t *new_cid, ptls_iovec_t address_token, |
2315 | | ptls_handshake_properties_t *handshake_properties, const quicly_transport_parameters_t *resumed_transport_params, |
2316 | | void *appdata) |
2317 | 0 | { |
2318 | 0 | const struct st_ptls_salt_t *salt; |
2319 | 0 | quicly_conn_t *conn = NULL; |
2320 | 0 | const quicly_cid_t *server_cid; |
2321 | 0 | ptls_buffer_t buf; |
2322 | 0 | size_t epoch_offsets[5] = {0}; |
2323 | 0 | size_t max_early_data_size = 0; |
2324 | 0 | int ret; |
2325 | |
|
2326 | 0 | if ((salt = get_salt(ctx->initial_version)) == NULL) { |
2327 | 0 | if ((ctx->initial_version & 0x0f0f0f0f) == 0x0a0a0a0a) { |
2328 | | /* greasing version, use our own greasing salt */ |
2329 | 0 | static const struct st_ptls_salt_t grease_salt = {.initial = {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, |
2330 | 0 | 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, |
2331 | 0 | 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}}; |
2332 | 0 | salt = &grease_salt; |
2333 | 0 | } else { |
2334 | 0 | ret = QUICLY_ERROR_INVALID_INITIAL_VERSION; |
2335 | 0 | goto Exit; |
2336 | 0 | } |
2337 | 0 | } |
2338 | | |
2339 | 0 | if ((conn = create_connection( |
2340 | 0 | ctx, ctx->initial_version, server_name, dest_addr, src_addr, NULL, new_cid, handshake_properties, appdata, |
2341 | 0 | quicly_cc_calc_initial_cwnd(ctx->initcwnd_packets, ctx->transport_params.max_udp_payload_size))) == NULL) { |
2342 | 0 | ret = PTLS_ERROR_NO_MEMORY; |
2343 | 0 | goto Exit; |
2344 | 0 | } |
2345 | 0 | conn->super.remote.address_validation.validated = 1; |
2346 | 0 | conn->super.remote.address_validation.send_probe = 1; |
2347 | 0 | if (address_token.len != 0) { |
2348 | 0 | if ((conn->token.base = malloc(address_token.len)) == NULL) { |
2349 | 0 | ret = PTLS_ERROR_NO_MEMORY; |
2350 | 0 | goto Exit; |
2351 | 0 | } |
2352 | 0 | memcpy(conn->token.base, address_token.base, address_token.len); |
2353 | 0 | conn->token.len = address_token.len; |
2354 | 0 | } |
2355 | 0 | server_cid = quicly_get_remote_cid(conn); |
2356 | 0 | conn->super.original_dcid = *server_cid; |
2357 | |
|
2358 | 0 | QUICLY_PROBE(CONNECT, conn, conn->stash.now, conn->super.version); |
2359 | 0 | QUICLY_LOG_CONN(connect, conn, { PTLS_LOG_ELEMENT_UNSIGNED(version, conn->super.version); }); |
2360 | | |
2361 | 0 | if ((ret = setup_handshake_space_and_flow(conn, QUICLY_EPOCH_INITIAL)) != 0) |
2362 | 0 | goto Exit; |
2363 | 0 | if ((ret = setup_initial_encryption(get_aes128gcmsha256(ctx), &conn->initial->cipher.ingress, &conn->initial->cipher.egress, |
2364 | 0 | ptls_iovec_init(server_cid->cid, server_cid->len), 1, |
2365 | 0 | ptls_iovec_init(salt->initial, sizeof(salt->initial)), conn)) != 0) |
2366 | 0 | goto Exit; |
2367 | | |
2368 | | /* handshake (we always encode authentication CIDs, as we do not (yet) regenerate ClientHello when receiving Retry) */ |
2369 | 0 | ptls_buffer_init(&conn->crypto.transport_params.buf, "", 0); |
2370 | 0 | if ((ret = quicly_encode_transport_parameter_list( |
2371 | 0 | &conn->crypto.transport_params.buf, &conn->super.ctx->transport_params, NULL, &conn->super.local.cid_set.cids[0].cid, |
2372 | 0 | NULL, NULL, conn->super.ctx->expand_client_hello ? conn->super.ctx->initial_egress_max_udp_payload_size : 0)) != 0) |
2373 | 0 | goto Exit; |
2374 | 0 | conn->crypto.transport_params.ext[0] = |
2375 | 0 | (ptls_raw_extension_t){QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_FINAL, |
2376 | 0 | {conn->crypto.transport_params.buf.base, conn->crypto.transport_params.buf.off}}; |
2377 | 0 | conn->crypto.transport_params.ext[1] = |
2378 | 0 | (ptls_raw_extension_t){QUICLY_TLS_EXTENSION_TYPE_TRANSPORT_PARAMETERS_DRAFT, |
2379 | 0 | {conn->crypto.transport_params.buf.base, conn->crypto.transport_params.buf.off}}; |
2380 | 0 | conn->crypto.transport_params.ext[2] = (ptls_raw_extension_t){UINT16_MAX}; |
2381 | 0 | conn->crypto.handshake_properties.additional_extensions = conn->crypto.transport_params.ext; |
2382 | 0 | conn->crypto.handshake_properties.collected_extensions = client_collected_extensions; |
2383 | |
|
2384 | 0 | ptls_buffer_init(&buf, "", 0); |
2385 | 0 | if (resumed_transport_params != NULL) |
2386 | 0 | conn->crypto.handshake_properties.client.max_early_data_size = &max_early_data_size; |
2387 | 0 | ret = ptls_handle_message(conn->crypto.tls, &buf, epoch_offsets, 0, NULL, 0, &conn->crypto.handshake_properties); |
2388 | 0 | conn->crypto.handshake_properties.client.max_early_data_size = NULL; |
2389 | 0 | if (ret != PTLS_ERROR_IN_PROGRESS) { |
2390 | 0 | assert(ret > 0); /* no QUIC errors */ |
2391 | 0 | goto Exit; |
2392 | 0 | } |
2393 | 0 | write_crypto_data(conn, &buf, epoch_offsets); |
2394 | 0 | ptls_buffer_dispose(&buf); |
2395 | |
|
2396 | 0 | if (max_early_data_size != 0) { |
2397 | | /* when attempting 0-RTT, apply the remembered transport parameters */ |
2398 | 0 | #define APPLY(n) conn->super.remote.transport_params.n = resumed_transport_params->n |
2399 | 0 | APPLY(active_connection_id_limit); |
2400 | 0 | APPLY(max_data); |
2401 | 0 | APPLY(max_stream_data.bidi_local); |
2402 | 0 | APPLY(max_stream_data.bidi_remote); |
2403 | 0 | APPLY(max_stream_data.uni); |
2404 | 0 | APPLY(max_streams_bidi); |
2405 | 0 | APPLY(max_streams_uni); |
2406 | 0 | #undef APPLY |
2407 | 0 | if ((ret = apply_remote_transport_params(conn)) != 0) |
2408 | 0 | goto Exit; |
2409 | 0 | } |
2410 | | |
2411 | 0 | *_conn = conn; |
2412 | 0 | ret = 0; |
2413 | |
|
2414 | 0 | Exit: |
2415 | 0 | if (conn != NULL) |
2416 | 0 | unlock_now(conn); |
2417 | 0 | if (ret != 0) { |
2418 | 0 | if (conn != NULL) |
2419 | 0 | quicly_free(conn); |
2420 | 0 | } |
2421 | 0 | return ret; |
2422 | 0 | } |
2423 | | |
2424 | | static int server_collected_extensions(ptls_t *tls, ptls_handshake_properties_t *properties, ptls_raw_extension_t *slots) |
2425 | 0 | { |
2426 | 0 | quicly_conn_t *conn = (void *)((char *)properties - offsetof(quicly_conn_t, crypto.handshake_properties)); |
2427 | 0 | quicly_cid_t initial_scid; |
2428 | 0 | int ret; |
2429 | |
|
2430 | 0 | if (slots[0].type == UINT16_MAX) { |
2431 | 0 | ret = PTLS_ALERT_MISSING_EXTENSION; |
2432 | 0 | goto Exit; |
2433 | 0 | } |
2434 | 0 | assert(slots[0].type == get_transport_parameters_extension_id(conn->super.version)); |
2435 | 0 | assert(slots[1].type == UINT16_MAX); |
2436 | | |
2437 | 0 | { /* decode transport_parameters extension */ |
2438 | 0 | const uint8_t *src = slots[0].data.base, *end = src + slots[0].data.len; |
2439 | 0 | if ((ret = quicly_decode_transport_parameter_list(&conn->super.remote.transport_params, |
2440 | 0 | needs_cid_auth(conn) ? NULL : &tp_cid_ignore, |
2441 | 0 | needs_cid_auth(conn) ? &initial_scid : &tp_cid_ignore, |
2442 | 0 | needs_cid_auth(conn) ? NULL : &tp_cid_ignore, NULL, src, end)) != 0) |
2443 | 0 | goto Exit; |
2444 | 0 | if (needs_cid_auth(conn) && |
2445 | 0 | !quicly_cid_is_equal(&conn->super.remote.cid_set.cids[0].cid, ptls_iovec_init(initial_scid.cid, initial_scid.len))) { |
2446 | 0 | ret = QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
2447 | 0 | goto Exit; |
2448 | 0 | } |
2449 | 0 | } |
2450 | | |
2451 | | /* setup ack frequency */ |
2452 | 0 | ack_frequency_set_next_update_at(conn); |
2453 | | |
2454 | | /* update UDP max payload size to: |
2455 | | * max(current, min(max_the_remote_sent, remote.tp.max_udp_payload_size, local.tp.max_udp_payload_size)) */ |
2456 | 0 | assert(conn->initial != NULL); |
2457 | 0 | if (conn->egress.max_udp_payload_size < conn->initial->largest_ingress_udp_payload_size) { |
2458 | 0 | uint16_t size = conn->initial->largest_ingress_udp_payload_size; |
2459 | 0 | if (size > conn->super.remote.transport_params.max_udp_payload_size) |
2460 | 0 | size = conn->super.remote.transport_params.max_udp_payload_size; |
2461 | 0 | if (size > conn->super.ctx->transport_params.max_udp_payload_size) |
2462 | 0 | size = conn->super.ctx->transport_params.max_udp_payload_size; |
2463 | 0 | conn->egress.max_udp_payload_size = size; |
2464 | 0 | } |
2465 | | |
2466 | | /* set transport_parameters extension to be sent in EE */ |
2467 | 0 | assert(properties->additional_extensions == NULL); |
2468 | 0 | ptls_buffer_init(&conn->crypto.transport_params.buf, "", 0); |
2469 | 0 | assert(conn->super.local.cid_set.cids[0].sequence == 0 && "make sure that local_cid is in expected state before sending SRT"); |
2470 | 0 | if ((ret = quicly_encode_transport_parameter_list( |
2471 | 0 | &conn->crypto.transport_params.buf, &conn->super.ctx->transport_params, |
2472 | 0 | needs_cid_auth(conn) || is_retry(conn) ? &conn->super.original_dcid : NULL, |
2473 | 0 | needs_cid_auth(conn) ? &conn->super.local.cid_set.cids[0].cid : NULL, |
2474 | 0 | needs_cid_auth(conn) && is_retry(conn) ? &conn->retry_scid : NULL, |
2475 | 0 | conn->super.ctx->cid_encryptor != NULL ? conn->super.local.cid_set.cids[0].stateless_reset_token : NULL, 0)) != 0) |
2476 | 0 | goto Exit; |
2477 | 0 | properties->additional_extensions = conn->crypto.transport_params.ext; |
2478 | 0 | conn->crypto.transport_params.ext[0] = |
2479 | 0 | (ptls_raw_extension_t){get_transport_parameters_extension_id(conn->super.version), |
2480 | 0 | {conn->crypto.transport_params.buf.base, conn->crypto.transport_params.buf.off}}; |
2481 | 0 | conn->crypto.transport_params.ext[1] = (ptls_raw_extension_t){UINT16_MAX}; |
2482 | 0 | conn->crypto.handshake_properties.additional_extensions = conn->crypto.transport_params.ext; |
2483 | |
|
2484 | 0 | ret = 0; |
2485 | |
|
2486 | 0 | Exit: |
2487 | 0 | return ret; |
2488 | 0 | } |
2489 | | |
2490 | | static size_t aead_decrypt_core(ptls_aead_context_t *aead, uint64_t pn, quicly_decoded_packet_t *packet, size_t aead_off) |
2491 | 0 | { |
2492 | 0 | return ptls_aead_decrypt(aead, packet->octets.base + aead_off, packet->octets.base + aead_off, packet->octets.len - aead_off, |
2493 | 0 | pn, packet->octets.base, aead_off); |
2494 | 0 | } |
2495 | | |
2496 | | static int aead_decrypt_fixed_key(void *ctx, uint64_t pn, quicly_decoded_packet_t *packet, size_t aead_off, size_t *ptlen) |
2497 | 0 | { |
2498 | 0 | ptls_aead_context_t *aead = ctx; |
2499 | |
|
2500 | 0 | if ((*ptlen = aead_decrypt_core(aead, pn, packet, aead_off)) == SIZE_MAX) |
2501 | 0 | return QUICLY_ERROR_PACKET_IGNORED; |
2502 | 0 | return 0; |
2503 | 0 | } |
2504 | | |
2505 | | static int aead_decrypt_1rtt(void *ctx, uint64_t pn, quicly_decoded_packet_t *packet, size_t aead_off, size_t *ptlen) |
2506 | 0 | { |
2507 | 0 | quicly_conn_t *conn = ctx; |
2508 | 0 | struct st_quicly_application_space_t *space = conn->application; |
2509 | 0 | size_t aead_index = (packet->octets.base[0] & QUICLY_KEY_PHASE_BIT) != 0; |
2510 | 0 | int ret; |
2511 | | |
2512 | | /* prepare key, when not available (yet) */ |
2513 | 0 | if (space->cipher.ingress.aead[aead_index] == NULL) { |
2514 | 0 | Retry_1RTT : { |
2515 | | /* Replace the AEAD key at the alternative slot (note: decryption key slots are shared by 0-RTT and 1-RTT), at the same time |
2516 | | * dropping 0-RTT header protection key. */ |
2517 | 0 | if (conn->application->cipher.ingress.header_protection.zero_rtt != NULL) { |
2518 | 0 | ptls_cipher_free(conn->application->cipher.ingress.header_protection.zero_rtt); |
2519 | 0 | conn->application->cipher.ingress.header_protection.zero_rtt = NULL; |
2520 | 0 | } |
2521 | 0 | ptls_cipher_suite_t *cipher = ptls_get_cipher(conn->crypto.tls); |
2522 | 0 | if ((ret = update_1rtt_key(conn, cipher, 0, &space->cipher.ingress.aead[aead_index], space->cipher.ingress.secret)) != 0) |
2523 | 0 | return ret; |
2524 | 0 | ++space->cipher.ingress.key_phase.prepared; |
2525 | 0 | QUICLY_PROBE(CRYPTO_RECEIVE_KEY_UPDATE_PREPARE, conn, conn->stash.now, space->cipher.ingress.key_phase.prepared, |
2526 | 0 | QUICLY_PROBE_HEXDUMP(space->cipher.ingress.secret, cipher->hash->digest_size)); |
2527 | 0 | QUICLY_LOG_CONN(crypto_receive_key_update_prepare, conn, { |
2528 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(phase, space->cipher.ingress.key_phase.prepared); |
2529 | 0 | PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(secret, space->cipher.ingress.secret, cipher->hash->digest_size); |
2530 | 0 | }); |
2531 | 0 | } |
2532 | 0 | } |
2533 | | |
2534 | | /* decrypt */ |
2535 | 0 | ptls_aead_context_t *aead = space->cipher.ingress.aead[aead_index]; |
2536 | 0 | if ((*ptlen = aead_decrypt_core(aead, pn, packet, aead_off)) == SIZE_MAX) { |
2537 | | /* retry with a new key, if possible */ |
2538 | 0 | if (space->cipher.ingress.key_phase.decrypted == space->cipher.ingress.key_phase.prepared && |
2539 | 0 | space->cipher.ingress.key_phase.decrypted % 2 != aead_index) { |
2540 | | /* reapply AEAD to revert payload to the encrypted form. This assumes that the cipher used in AEAD is CTR. */ |
2541 | 0 | aead_decrypt_core(aead, pn, packet, aead_off); |
2542 | 0 | goto Retry_1RTT; |
2543 | 0 | } |
2544 | | /* otherwise return failure */ |
2545 | 0 | return QUICLY_ERROR_PACKET_IGNORED; |
2546 | 0 | } |
2547 | | |
2548 | | /* update the confirmed key phase and also the egress key phase, if necessary */ |
2549 | 0 | if (space->cipher.ingress.key_phase.prepared != space->cipher.ingress.key_phase.decrypted && |
2550 | 0 | space->cipher.ingress.key_phase.prepared % 2 == aead_index) { |
2551 | 0 | if ((ret = received_key_update(conn, space->cipher.ingress.key_phase.prepared)) != 0) |
2552 | 0 | return ret; |
2553 | 0 | } |
2554 | | |
2555 | 0 | return 0; |
2556 | 0 | } |
2557 | | |
2558 | | static int do_decrypt_packet(ptls_cipher_context_t *header_protection, |
2559 | | int (*aead_cb)(void *, uint64_t, quicly_decoded_packet_t *, size_t, size_t *), void *aead_ctx, |
2560 | | uint64_t *next_expected_pn, quicly_decoded_packet_t *packet, uint64_t *pn, ptls_iovec_t *payload) |
2561 | 0 | { |
2562 | 0 | size_t encrypted_len = packet->octets.len - packet->encrypted_off; |
2563 | 0 | uint8_t hpmask[5] = {0}; |
2564 | 0 | uint32_t pnbits = 0; |
2565 | 0 | size_t pnlen, ptlen, i; |
2566 | 0 | int ret; |
2567 | | |
2568 | | /* decipher the header protection, as well as obtaining pnbits, pnlen */ |
2569 | 0 | if (encrypted_len < header_protection->algo->iv_size + QUICLY_MAX_PN_SIZE) { |
2570 | 0 | *pn = UINT64_MAX; |
2571 | 0 | return QUICLY_ERROR_PACKET_IGNORED; |
2572 | 0 | } |
2573 | 0 | ptls_cipher_init(header_protection, packet->octets.base + packet->encrypted_off + QUICLY_MAX_PN_SIZE); |
2574 | 0 | ptls_cipher_encrypt(header_protection, hpmask, hpmask, sizeof(hpmask)); |
2575 | 0 | packet->octets.base[0] ^= hpmask[0] & (QUICLY_PACKET_IS_LONG_HEADER(packet->octets.base[0]) ? 0xf : 0x1f); |
2576 | 0 | pnlen = (packet->octets.base[0] & 0x3) + 1; |
2577 | 0 | for (i = 0; i != pnlen; ++i) { |
2578 | 0 | packet->octets.base[packet->encrypted_off + i] ^= hpmask[i + 1]; |
2579 | 0 | pnbits = (pnbits << 8) | packet->octets.base[packet->encrypted_off + i]; |
2580 | 0 | } |
2581 | |
|
2582 | 0 | size_t aead_off = packet->encrypted_off + pnlen; |
2583 | 0 | *pn = quicly_determine_packet_number(pnbits, pnlen * 8, *next_expected_pn); |
2584 | | |
2585 | | /* AEAD decryption */ |
2586 | 0 | if ((ret = (*aead_cb)(aead_ctx, *pn, packet, aead_off, &ptlen)) != 0) { |
2587 | 0 | return ret; |
2588 | 0 | } |
2589 | 0 | if (*next_expected_pn <= *pn) |
2590 | 0 | *next_expected_pn = *pn + 1; |
2591 | |
|
2592 | 0 | *payload = ptls_iovec_init(packet->octets.base + aead_off, ptlen); |
2593 | 0 | return 0; |
2594 | 0 | } |
2595 | | |
2596 | | static int decrypt_packet(ptls_cipher_context_t *header_protection, |
2597 | | int (*aead_cb)(void *, uint64_t, quicly_decoded_packet_t *, size_t, size_t *), void *aead_ctx, |
2598 | | uint64_t *next_expected_pn, quicly_decoded_packet_t *packet, uint64_t *pn, ptls_iovec_t *payload) |
2599 | 0 | { |
2600 | 0 | int ret; |
2601 | | |
2602 | | /* decrypt ourselves, or use the pre-decrypted input */ |
2603 | 0 | if (packet->decrypted.pn == UINT64_MAX) { |
2604 | 0 | if ((ret = do_decrypt_packet(header_protection, aead_cb, aead_ctx, next_expected_pn, packet, pn, payload)) != 0) |
2605 | 0 | return ret; |
2606 | 0 | } else { |
2607 | 0 | *payload = ptls_iovec_init(packet->octets.base + packet->encrypted_off, packet->octets.len - packet->encrypted_off); |
2608 | 0 | *pn = packet->decrypted.pn; |
2609 | 0 | if (aead_cb == aead_decrypt_1rtt) { |
2610 | 0 | quicly_conn_t *conn = aead_ctx; |
2611 | 0 | if (conn->application->cipher.ingress.key_phase.decrypted < packet->decrypted.key_phase) { |
2612 | 0 | if ((ret = received_key_update(conn, packet->decrypted.key_phase)) != 0) |
2613 | 0 | return ret; |
2614 | 0 | } |
2615 | 0 | } |
2616 | 0 | if (*next_expected_pn < *pn) |
2617 | 0 | *next_expected_pn = *pn + 1; |
2618 | 0 | } |
2619 | | |
2620 | | /* check reserved bits after AEAD decryption */ |
2621 | 0 | if ((packet->octets.base[0] & (QUICLY_PACKET_IS_LONG_HEADER(packet->octets.base[0]) ? QUICLY_LONG_HEADER_RESERVED_BITS |
2622 | 0 | : QUICLY_SHORT_HEADER_RESERVED_BITS)) != |
2623 | 0 | 0) { |
2624 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
2625 | 0 | } |
2626 | 0 | if (payload->len == 0) { |
2627 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
2628 | 0 | } |
2629 | | |
2630 | 0 | return 0; |
2631 | 0 | } |
2632 | | |
2633 | | static int do_on_ack_ack(quicly_conn_t *conn, const quicly_sent_packet_t *packet, uint64_t start, uint64_t start_length, |
2634 | | struct st_quicly_sent_ack_additional_t *additional, size_t additional_capacity) |
2635 | 0 | { |
2636 | | /* find the pn space */ |
2637 | 0 | struct st_quicly_pn_space_t *space; |
2638 | 0 | switch (packet->ack_epoch) { |
2639 | 0 | case QUICLY_EPOCH_INITIAL: |
2640 | 0 | space = &conn->initial->super; |
2641 | 0 | break; |
2642 | 0 | case QUICLY_EPOCH_HANDSHAKE: |
2643 | 0 | space = &conn->handshake->super; |
2644 | 0 | break; |
2645 | 0 | case QUICLY_EPOCH_1RTT: |
2646 | 0 | space = &conn->application->super; |
2647 | 0 | break; |
2648 | 0 | default: |
2649 | 0 | assert(!"FIXME"); |
2650 | 0 | return QUICLY_TRANSPORT_ERROR_INTERNAL; |
2651 | 0 | } |
2652 | | |
2653 | | /* subtract given ACK ranges */ |
2654 | 0 | int ret; |
2655 | 0 | uint64_t end = start + start_length; |
2656 | 0 | if ((ret = quicly_ranges_subtract(&space->ack_queue, start, end)) != 0) |
2657 | 0 | return ret; |
2658 | 0 | for (size_t i = 0; i < additional_capacity && additional[i].gap != 0; ++i) { |
2659 | 0 | start = end + additional[i].gap; |
2660 | 0 | end = start + additional[i].length; |
2661 | 0 | if ((ret = quicly_ranges_subtract(&space->ack_queue, start, end)) != 0) |
2662 | 0 | return ret; |
2663 | 0 | } |
2664 | | |
2665 | | /* make adjustments */ |
2666 | 0 | if (space->ack_queue.num_ranges == 0) { |
2667 | 0 | space->largest_pn_received_at = INT64_MAX; |
2668 | 0 | space->unacked_count = 0; |
2669 | 0 | } else if (space->ack_queue.num_ranges > QUICLY_MAX_ACK_BLOCKS) { |
2670 | 0 | quicly_ranges_drop_by_range_indices(&space->ack_queue, space->ack_queue.num_ranges - QUICLY_MAX_ACK_BLOCKS, |
2671 | 0 | space->ack_queue.num_ranges); |
2672 | 0 | } |
2673 | |
|
2674 | 0 | return 0; |
2675 | 0 | } |
2676 | | |
2677 | | static int on_ack_ack_ranges64(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2678 | 0 | { |
2679 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2680 | | |
2681 | | /* TODO log */ |
2682 | |
|
2683 | 0 | return acked ? do_on_ack_ack(conn, packet, sent->data.ack.start, sent->data.ack.ranges64.start_length, |
2684 | 0 | sent->data.ack.ranges64.additional, PTLS_ELEMENTSOF(sent->data.ack.ranges64.additional)) |
2685 | 0 | : 0; |
2686 | 0 | } |
2687 | | |
2688 | | static int on_ack_ack_ranges8(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2689 | 0 | { |
2690 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2691 | | |
2692 | | /* TODO log */ |
2693 | |
|
2694 | 0 | return acked ? do_on_ack_ack(conn, packet, sent->data.ack.start, sent->data.ack.ranges8.start_length, |
2695 | 0 | sent->data.ack.ranges8.additional, PTLS_ELEMENTSOF(sent->data.ack.ranges8.additional)) |
2696 | 0 | : 0; |
2697 | 0 | } |
2698 | | |
2699 | | static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_id, quicly_sendstate_sent_t *sent) |
2700 | 0 | { |
2701 | 0 | quicly_stream_t *stream; |
2702 | 0 | int ret; |
2703 | |
|
2704 | 0 | if ((stream = quicly_get_stream(conn, stream_id)) == NULL) |
2705 | 0 | return 0; |
2706 | | |
2707 | 0 | size_t bytes_to_shift; |
2708 | 0 | if ((ret = quicly_sendstate_acked(&stream->sendstate, sent, &bytes_to_shift)) != 0) |
2709 | 0 | return ret; |
2710 | 0 | if (bytes_to_shift != 0) { |
2711 | 0 | QUICLY_PROBE(STREAM_ON_SEND_SHIFT, stream->conn, stream->conn->stash.now, stream, bytes_to_shift); |
2712 | 0 | stream->callbacks->on_send_shift(stream, bytes_to_shift); |
2713 | 0 | QUICLY_LOG_CONN(stream_on_send_shift, stream->conn, { |
2714 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
2715 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(delta, bytes_to_shift); |
2716 | 0 | }); |
2717 | 0 | } |
2718 | 0 | if (stream_is_destroyable(stream)) { |
2719 | 0 | destroy_stream(stream, 0); |
2720 | 0 | } else if (stream->_send_aux.reset_stream.sender_state == QUICLY_SENDER_STATE_NONE) { |
2721 | 0 | resched_stream_data(stream); |
2722 | 0 | } |
2723 | |
|
2724 | 0 | return 0; |
2725 | 0 | } |
2726 | | |
2727 | | static int on_ack_stream_ack_cached(quicly_conn_t *conn) |
2728 | 0 | { |
2729 | 0 | int ret; |
2730 | |
|
2731 | 0 | if (conn->stash.on_ack_stream.active_acked_cache.stream_id == INT64_MIN) |
2732 | 0 | return 0; |
2733 | 0 | ret = on_ack_stream_ack_one(conn, conn->stash.on_ack_stream.active_acked_cache.stream_id, |
2734 | 0 | &conn->stash.on_ack_stream.active_acked_cache.args); |
2735 | 0 | conn->stash.on_ack_stream.active_acked_cache.stream_id = INT64_MIN; |
2736 | 0 | return ret; |
2737 | 0 | } |
2738 | | |
2739 | | static int on_ack_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2740 | 0 | { |
2741 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2742 | 0 | int ret; |
2743 | |
|
2744 | 0 | if (acked) { |
2745 | |
|
2746 | 0 | QUICLY_PROBE(STREAM_ACKED, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, |
2747 | 0 | sent->data.stream.args.end - sent->data.stream.args.start); |
2748 | 0 | QUICLY_LOG_CONN(stream_acked, conn, { |
2749 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); |
2750 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); |
2751 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); |
2752 | 0 | }); |
2753 | | |
2754 | 0 | if (packet->frames_in_flight && conn->stash.on_ack_stream.active_acked_cache.stream_id == sent->data.stream.stream_id && |
2755 | 0 | conn->stash.on_ack_stream.active_acked_cache.args.end == sent->data.stream.args.start) { |
2756 | | /* Fast path: append the newly supplied range to the existing cached range. */ |
2757 | 0 | conn->stash.on_ack_stream.active_acked_cache.args.end = sent->data.stream.args.end; |
2758 | 0 | } else { |
2759 | | /* Slow path: submit the cached range, and if possible, cache the newly supplied range. Else submit the newly supplied |
2760 | | * range directly. */ |
2761 | 0 | if ((ret = on_ack_stream_ack_cached(conn)) != 0) |
2762 | 0 | return ret; |
2763 | 0 | if (packet->frames_in_flight) { |
2764 | 0 | conn->stash.on_ack_stream.active_acked_cache.stream_id = sent->data.stream.stream_id; |
2765 | 0 | conn->stash.on_ack_stream.active_acked_cache.args = sent->data.stream.args; |
2766 | 0 | } else { |
2767 | 0 | if ((ret = on_ack_stream_ack_one(conn, sent->data.stream.stream_id, &sent->data.stream.args)) != 0) |
2768 | 0 | return ret; |
2769 | 0 | } |
2770 | 0 | } |
2771 | |
|
2772 | 0 | } else { |
2773 | |
|
2774 | 0 | QUICLY_PROBE(STREAM_LOST, conn, conn->stash.now, sent->data.stream.stream_id, sent->data.stream.args.start, |
2775 | 0 | sent->data.stream.args.end - sent->data.stream.args.start); |
2776 | 0 | QUICLY_LOG_CONN(stream_lost, conn, { |
2777 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, sent->data.stream.stream_id); |
2778 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(off, sent->data.stream.args.start); |
2779 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(len, sent->data.stream.args.end - sent->data.stream.args.start); |
2780 | 0 | }); |
2781 | | |
2782 | 0 | quicly_stream_t *stream; |
2783 | 0 | if ((stream = quicly_get_stream(conn, sent->data.stream.stream_id)) == NULL) |
2784 | 0 | return 0; |
2785 | | /* FIXME handle rto error */ |
2786 | 0 | if ((ret = quicly_sendstate_lost(&stream->sendstate, &sent->data.stream.args)) != 0) |
2787 | 0 | return ret; |
2788 | 0 | if (stream->_send_aux.reset_stream.sender_state == QUICLY_SENDER_STATE_NONE) |
2789 | 0 | resched_stream_data(stream); |
2790 | 0 | } |
2791 | | |
2792 | 0 | return 0; |
2793 | 0 | } |
2794 | | |
2795 | | static int on_ack_max_stream_data(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2796 | 0 | { |
2797 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2798 | 0 | quicly_stream_t *stream; |
2799 | |
|
2800 | 0 | if ((stream = quicly_get_stream(conn, sent->data.stream.stream_id)) != NULL) { |
2801 | 0 | if (acked) { |
2802 | 0 | quicly_maxsender_acked(&stream->_send_aux.max_stream_data_sender, &sent->data.max_stream_data.args); |
2803 | 0 | } else { |
2804 | 0 | quicly_maxsender_lost(&stream->_send_aux.max_stream_data_sender, &sent->data.max_stream_data.args); |
2805 | 0 | if (should_send_max_stream_data(stream)) |
2806 | 0 | sched_stream_control(stream); |
2807 | 0 | } |
2808 | 0 | } |
2809 | |
|
2810 | 0 | return 0; |
2811 | 0 | } |
2812 | | |
2813 | | static int on_ack_max_data(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2814 | 0 | { |
2815 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2816 | |
|
2817 | 0 | if (acked) { |
2818 | 0 | quicly_maxsender_acked(&conn->ingress.max_data.sender, &sent->data.max_data.args); |
2819 | 0 | } else { |
2820 | 0 | quicly_maxsender_lost(&conn->ingress.max_data.sender, &sent->data.max_data.args); |
2821 | 0 | } |
2822 | |
|
2823 | 0 | return 0; |
2824 | 0 | } |
2825 | | |
2826 | | static int on_ack_max_streams(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2827 | 0 | { |
2828 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2829 | 0 | quicly_maxsender_t *maxsender = sent->data.max_streams.uni ? &conn->ingress.max_streams.uni : &conn->ingress.max_streams.bidi; |
2830 | 0 | assert(maxsender != NULL); /* we would only receive an ACK if we have sent the frame */ |
2831 | | |
2832 | 0 | if (acked) { |
2833 | 0 | quicly_maxsender_acked(maxsender, &sent->data.max_streams.args); |
2834 | 0 | } else { |
2835 | 0 | quicly_maxsender_lost(maxsender, &sent->data.max_streams.args); |
2836 | 0 | } |
2837 | |
|
2838 | 0 | return 0; |
2839 | 0 | } |
2840 | | |
2841 | | static void on_ack_stream_state_sender(quicly_sender_state_t *sender_state, int acked) |
2842 | 0 | { |
2843 | 0 | *sender_state = acked ? QUICLY_SENDER_STATE_ACKED : QUICLY_SENDER_STATE_SEND; |
2844 | 0 | } |
2845 | | |
2846 | | static int on_ack_reset_stream(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2847 | 0 | { |
2848 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2849 | 0 | quicly_stream_t *stream; |
2850 | |
|
2851 | 0 | if ((stream = quicly_get_stream(conn, sent->data.stream_state_sender.stream_id)) != NULL) { |
2852 | 0 | on_ack_stream_state_sender(&stream->_send_aux.reset_stream.sender_state, acked); |
2853 | 0 | if (stream_is_destroyable(stream)) |
2854 | 0 | destroy_stream(stream, 0); |
2855 | 0 | } |
2856 | |
|
2857 | 0 | return 0; |
2858 | 0 | } |
2859 | | |
2860 | | static int on_ack_stop_sending(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2861 | 0 | { |
2862 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2863 | 0 | quicly_stream_t *stream; |
2864 | |
|
2865 | 0 | if ((stream = quicly_get_stream(conn, sent->data.stream_state_sender.stream_id)) != NULL) { |
2866 | 0 | on_ack_stream_state_sender(&stream->_send_aux.stop_sending.sender_state, acked); |
2867 | 0 | if (stream->_send_aux.stop_sending.sender_state != QUICLY_SENDER_STATE_ACKED) |
2868 | 0 | sched_stream_control(stream); |
2869 | 0 | } |
2870 | |
|
2871 | 0 | return 0; |
2872 | 0 | } |
2873 | | |
2874 | | static int on_ack_streams_blocked(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2875 | 0 | { |
2876 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2877 | 0 | struct st_quicly_max_streams_t *m = |
2878 | 0 | sent->data.streams_blocked.uni ? &conn->egress.max_streams.uni : &conn->egress.max_streams.bidi; |
2879 | |
|
2880 | 0 | if (acked) { |
2881 | 0 | quicly_maxsender_acked(&m->blocked_sender, &sent->data.streams_blocked.args); |
2882 | 0 | } else { |
2883 | 0 | quicly_maxsender_lost(&m->blocked_sender, &sent->data.streams_blocked.args); |
2884 | 0 | } |
2885 | |
|
2886 | 0 | return 0; |
2887 | 0 | } |
2888 | | |
2889 | | static int on_ack_handshake_done(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2890 | 0 | { |
2891 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2892 | | |
2893 | | /* When lost, reschedule for transmission. When acked, suppress retransmission if scheduled. */ |
2894 | 0 | if (acked) { |
2895 | 0 | conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT; |
2896 | 0 | } else { |
2897 | 0 | conn->egress.pending_flows |= QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT; |
2898 | 0 | } |
2899 | 0 | return 0; |
2900 | 0 | } |
2901 | | |
2902 | | static int on_ack_data_blocked(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2903 | 0 | { |
2904 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2905 | |
|
2906 | 0 | if (conn->egress.max_data.permitted == sent->data.data_blocked.offset) { |
2907 | 0 | if (acked) { |
2908 | 0 | conn->egress.data_blocked = QUICLY_SENDER_STATE_ACKED; |
2909 | 0 | } else if (packet->frames_in_flight && conn->egress.data_blocked == QUICLY_SENDER_STATE_UNACKED) { |
2910 | 0 | conn->egress.data_blocked = QUICLY_SENDER_STATE_SEND; |
2911 | 0 | } |
2912 | 0 | } |
2913 | |
|
2914 | 0 | return 0; |
2915 | 0 | } |
2916 | | |
2917 | | static int on_ack_stream_data_blocked_frame(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, |
2918 | | quicly_sent_t *sent) |
2919 | 0 | { |
2920 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2921 | 0 | quicly_stream_t *stream; |
2922 | |
|
2923 | 0 | if ((stream = quicly_get_stream(conn, sent->data.stream_data_blocked.stream_id)) == NULL) |
2924 | 0 | return 0; |
2925 | | |
2926 | 0 | if (stream->_send_aux.max_stream_data == sent->data.stream_data_blocked.offset) { |
2927 | 0 | if (acked) { |
2928 | 0 | stream->_send_aux.blocked = QUICLY_SENDER_STATE_ACKED; |
2929 | 0 | } else if (packet->frames_in_flight && stream->_send_aux.blocked == QUICLY_SENDER_STATE_UNACKED) { |
2930 | 0 | stream->_send_aux.blocked = QUICLY_SENDER_STATE_SEND; |
2931 | 0 | sched_stream_control(stream); |
2932 | 0 | } |
2933 | 0 | } |
2934 | |
|
2935 | 0 | return 0; |
2936 | 0 | } |
2937 | | |
2938 | | static int on_ack_new_token(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2939 | 0 | { |
2940 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2941 | |
|
2942 | 0 | if (sent->data.new_token.is_inflight) { |
2943 | 0 | --conn->egress.new_token.num_inflight; |
2944 | 0 | sent->data.new_token.is_inflight = 0; |
2945 | 0 | } |
2946 | 0 | if (acked) { |
2947 | 0 | QUICLY_PROBE(NEW_TOKEN_ACKED, conn, conn->stash.now, sent->data.new_token.generation); |
2948 | 0 | QUICLY_LOG_CONN(new_token_acked, conn, { PTLS_LOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); }); |
2949 | 0 | if (conn->egress.new_token.max_acked < sent->data.new_token.generation) |
2950 | 0 | conn->egress.new_token.max_acked = sent->data.new_token.generation; |
2951 | 0 | } |
2952 | | |
2953 | 0 | if (conn->egress.new_token.num_inflight == 0 && conn->egress.new_token.max_acked < conn->egress.new_token.generation) |
2954 | 0 | conn->egress.pending_flows |= QUICLY_PENDING_FLOW_NEW_TOKEN_BIT; |
2955 | |
|
2956 | 0 | return 0; |
2957 | 0 | } |
2958 | | |
2959 | | static int on_ack_new_connection_id(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2960 | 0 | { |
2961 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2962 | 0 | uint64_t sequence = sent->data.new_connection_id.sequence; |
2963 | |
|
2964 | 0 | if (acked) { |
2965 | 0 | quicly_local_cid_on_acked(&conn->super.local.cid_set, sequence); |
2966 | 0 | } else { |
2967 | 0 | if (quicly_local_cid_on_lost(&conn->super.local.cid_set, sequence)) |
2968 | 0 | conn->egress.pending_flows |= QUICLY_PENDING_FLOW_CID_FRAME_BIT; |
2969 | 0 | } |
2970 | |
|
2971 | 0 | return 0; |
2972 | 0 | } |
2973 | | |
2974 | | static int on_ack_retire_connection_id(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
2975 | 0 | { |
2976 | 0 | quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap)); |
2977 | 0 | uint64_t sequence = sent->data.retire_connection_id.sequence; |
2978 | |
|
2979 | 0 | if (!acked) |
2980 | 0 | schedule_retire_connection_id_frame(conn, sequence); |
2981 | |
|
2982 | 0 | return 0; |
2983 | 0 | } |
2984 | | |
2985 | | static int should_send_datagram_frame(quicly_conn_t *conn) |
2986 | 0 | { |
2987 | 0 | if (conn->egress.datagram_frame_payloads.count == 0) |
2988 | 0 | return 0; |
2989 | 0 | if (conn->application == NULL) |
2990 | 0 | return 0; |
2991 | 0 | if (conn->application->cipher.egress.key.aead == NULL) |
2992 | 0 | return 0; |
2993 | 0 | return 1; |
2994 | 0 | } |
2995 | | |
2996 | | static inline uint64_t calc_amplification_limit_allowance(quicly_conn_t *conn) |
2997 | 0 | { |
2998 | 0 | if (conn->super.remote.address_validation.validated) |
2999 | 0 | return UINT64_MAX; |
3000 | 0 | uint64_t budget = conn->super.stats.num_bytes.received * conn->super.ctx->pre_validation_amplification_limit; |
3001 | 0 | if (budget <= conn->super.stats.num_bytes.sent) |
3002 | 0 | return 0; |
3003 | 0 | return budget - conn->super.stats.num_bytes.sent; |
3004 | 0 | } |
3005 | | |
3006 | | /* Helper function to compute send window based on: |
3007 | | * * state of peer validation, |
3008 | | * * current cwnd, |
3009 | | * * minimum send requirements in |min_bytes_to_send|, and |
3010 | | * * if sending is to be restricted to the minimum, indicated in |restrict_sending| |
3011 | | */ |
3012 | | static size_t calc_send_window(quicly_conn_t *conn, size_t min_bytes_to_send, uint64_t amp_window, int restrict_sending) |
3013 | 0 | { |
3014 | 0 | uint64_t window = 0; |
3015 | 0 | if (restrict_sending) { |
3016 | | /* Send min_bytes_to_send on PTO */ |
3017 | 0 | window = min_bytes_to_send; |
3018 | 0 | } else { |
3019 | | /* Limit to cwnd */ |
3020 | 0 | if (conn->egress.cc.cwnd > conn->egress.loss.sentmap.bytes_in_flight) |
3021 | 0 | window = conn->egress.cc.cwnd - conn->egress.loss.sentmap.bytes_in_flight; |
3022 | | /* Allow at least one packet on time-threshold loss detection */ |
3023 | 0 | window = window > min_bytes_to_send ? window : min_bytes_to_send; |
3024 | 0 | } |
3025 | | /* Cap the window by the amount allowed by address validation */ |
3026 | 0 | if (amp_window < window) |
3027 | 0 | window = amp_window; |
3028 | |
|
3029 | 0 | return window; |
3030 | 0 | } |
3031 | | |
3032 | | /** |
3033 | | * Checks if the server is waiting for ClientFinished. When that is the case, the loss timer is deactivated, to avoid repeatedly |
3034 | | * sending 1-RTT packets while the client spends time verifying the certificate chain at the same time buffering 1-RTT packets. |
3035 | | */ |
3036 | | static int is_point5rtt_with_no_handshake_data_to_send(quicly_conn_t *conn) |
3037 | 0 | { |
3038 | | /* bail out unless this is a server-side connection waiting for ClientFinished */ |
3039 | 0 | if (!(conn->handshake != NULL && conn->application != NULL && !quicly_is_client(conn))) |
3040 | 0 | return 0; |
3041 | 0 | quicly_stream_t *stream = quicly_get_stream(conn, (quicly_stream_id_t)-1 - QUICLY_EPOCH_HANDSHAKE); |
3042 | 0 | assert(stream != NULL); |
3043 | 0 | return stream->sendstate.pending.num_ranges == 0 && stream->sendstate.acked.ranges[0].end == stream->sendstate.size_inflight; |
3044 | 0 | } |
3045 | | |
3046 | | int64_t quicly_get_first_timeout(quicly_conn_t *conn) |
3047 | 0 | { |
3048 | 0 | if (conn->super.state >= QUICLY_STATE_CLOSING) |
3049 | 0 | return conn->egress.send_ack_at; |
3050 | | |
3051 | 0 | if (should_send_datagram_frame(conn)) |
3052 | 0 | return 0; |
3053 | | |
3054 | 0 | uint64_t amp_window = calc_amplification_limit_allowance(conn); |
3055 | |
|
3056 | 0 | if (calc_send_window(conn, 0, amp_window, 0) > 0) { |
3057 | 0 | if (conn->egress.pending_flows != 0) |
3058 | 0 | return 0; |
3059 | 0 | if (quicly_linklist_is_linked(&conn->egress.pending_streams.control)) |
3060 | 0 | return 0; |
3061 | 0 | if (scheduler_can_send(conn)) |
3062 | 0 | return 0; |
3063 | 0 | } |
3064 | | |
3065 | | /* if something can be sent, return the earliest timeout. Otherwise return the idle timeout. */ |
3066 | 0 | int64_t at = conn->idle_timeout.at; |
3067 | 0 | if (amp_window > 0) { |
3068 | 0 | if (conn->egress.loss.alarm_at < at && !is_point5rtt_with_no_handshake_data_to_send(conn)) |
3069 | 0 | at = conn->egress.loss.alarm_at; |
3070 | 0 | if (conn->egress.send_ack_at < at) |
3071 | 0 | at = conn->egress.send_ack_at; |
3072 | 0 | } |
3073 | |
|
3074 | 0 | return at; |
3075 | 0 | } |
3076 | | |
3077 | | uint64_t quicly_get_next_expected_packet_number(quicly_conn_t *conn) |
3078 | 0 | { |
3079 | 0 | if (!conn->application) |
3080 | 0 | return UINT64_MAX; |
3081 | | |
3082 | 0 | return conn->application->super.next_expected_packet_number; |
3083 | 0 | } |
3084 | | |
3085 | | /** |
3086 | | * data structure that is used during one call through quicly_send() |
3087 | | */ |
3088 | | struct st_quicly_send_context_t { |
3089 | | /** |
3090 | | * current encryption context |
3091 | | */ |
3092 | | struct { |
3093 | | struct st_quicly_cipher_context_t *cipher; |
3094 | | uint8_t first_byte; |
3095 | | } current; |
3096 | | /** |
3097 | | * packet under construction |
3098 | | */ |
3099 | | struct { |
3100 | | struct st_quicly_cipher_context_t *cipher; |
3101 | | /** |
3102 | | * points to the first byte of the target QUIC packet. It will not point to packet->octets.base[0] when the datagram |
3103 | | * contains multiple QUIC packet. |
3104 | | */ |
3105 | | uint8_t *first_byte_at; |
3106 | | /** |
3107 | | * if the target QUIC packet contains an ack-eliciting frame |
3108 | | */ |
3109 | | uint8_t ack_eliciting : 1; |
3110 | | /** |
3111 | | * if the target datagram should be padded to full size |
3112 | | */ |
3113 | | uint8_t full_size : 1; |
3114 | | } target; |
3115 | | /** |
3116 | | * output buffer into which list of datagrams is written |
3117 | | */ |
3118 | | struct iovec *datagrams; |
3119 | | /** |
3120 | | * max number of datagrams that can be stored in |packets| |
3121 | | */ |
3122 | | size_t max_datagrams; |
3123 | | /** |
3124 | | * number of datagrams currently stored in |packets| |
3125 | | */ |
3126 | | size_t num_datagrams; |
3127 | | /** |
3128 | | * buffer in which packets are built |
3129 | | */ |
3130 | | struct { |
3131 | | /** |
3132 | | * starting position of the current (or next) datagram |
3133 | | */ |
3134 | | uint8_t *datagram; |
3135 | | /** |
3136 | | * end position of the payload buffer |
3137 | | */ |
3138 | | uint8_t *end; |
3139 | | } payload_buf; |
3140 | | /** |
3141 | | * Currently available window for sending (in bytes); the value becomes negative when the sender uses more space than permitted. |
3142 | | * That happens because the sender operates at packet-level rather than byte-level. |
3143 | | */ |
3144 | | ssize_t send_window; |
3145 | | /** |
3146 | | * location where next frame should be written |
3147 | | */ |
3148 | | uint8_t *dst; |
3149 | | /** |
3150 | | * end of the payload area, beyond which frames cannot be written |
3151 | | */ |
3152 | | uint8_t *dst_end; |
3153 | | /** |
3154 | | * address at which payload starts |
3155 | | */ |
3156 | | uint8_t *dst_payload_from; |
3157 | | /** |
3158 | | * first packet number to be used within the lifetime of this send context |
3159 | | */ |
3160 | | uint64_t first_packet_number; |
3161 | | }; |
3162 | | |
3163 | | static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int coalesced) |
3164 | 0 | { |
3165 | 0 | size_t datagram_size, packet_bytes_in_flight; |
3166 | |
|
3167 | 0 | assert(s->target.cipher->aead != NULL); |
3168 | | |
3169 | 0 | assert(s->dst != s->dst_payload_from); |
3170 | | |
3171 | | /* pad so that the pn + payload would be at least 4 bytes */ |
3172 | 0 | while (s->dst - s->dst_payload_from < QUICLY_MAX_PN_SIZE - QUICLY_SEND_PN_SIZE) |
3173 | 0 | *s->dst++ = QUICLY_FRAME_TYPE_PADDING; |
3174 | |
|
3175 | 0 | if (!coalesced && s->target.full_size) { |
3176 | 0 | assert(s->num_datagrams == 0 || s->datagrams[s->num_datagrams - 1].iov_len == conn->egress.max_udp_payload_size); |
3177 | 0 | const size_t max_size = conn->egress.max_udp_payload_size - QUICLY_AEAD_TAG_SIZE; |
3178 | 0 | assert(s->dst - s->payload_buf.datagram <= max_size); |
3179 | 0 | memset(s->dst, QUICLY_FRAME_TYPE_PADDING, s->payload_buf.datagram + max_size - s->dst); |
3180 | 0 | s->dst = s->payload_buf.datagram + max_size; |
3181 | 0 | } |
3182 | | |
3183 | | /* encode packet size, packet number, key-phase */ |
3184 | 0 | if (QUICLY_PACKET_IS_LONG_HEADER(*s->target.first_byte_at)) { |
3185 | 0 | uint16_t length = s->dst - s->dst_payload_from + s->target.cipher->aead->algo->tag_size + QUICLY_SEND_PN_SIZE; |
3186 | | /* length is always 2 bytes, see _do_prepare_packet */ |
3187 | 0 | length |= 0x4000; |
3188 | 0 | quicly_encode16(s->dst_payload_from - QUICLY_SEND_PN_SIZE - 2, length); |
3189 | 0 | switch (*s->target.first_byte_at & QUICLY_PACKET_TYPE_BITMASK) { |
3190 | 0 | case QUICLY_PACKET_TYPE_INITIAL: |
3191 | 0 | case QUICLY_PACKET_TYPE_HANDSHAKE: |
3192 | 0 | conn->super.stats.num_packets.initial_handshake_sent++; |
3193 | 0 | break; |
3194 | 0 | } |
3195 | 0 | } else { |
3196 | 0 | if (conn->egress.packet_number >= conn->application->cipher.egress.key_update_pn.next) { |
3197 | 0 | int ret; |
3198 | 0 | if ((ret = update_1rtt_egress_key(conn)) != 0) |
3199 | 0 | return ret; |
3200 | 0 | } |
3201 | 0 | if ((conn->application->cipher.egress.key_phase & 1) != 0) |
3202 | 0 | *s->target.first_byte_at |= QUICLY_KEY_PHASE_BIT; |
3203 | 0 | } |
3204 | 0 | quicly_encode16(s->dst_payload_from - QUICLY_SEND_PN_SIZE, (uint16_t)conn->egress.packet_number); |
3205 | | |
3206 | | /* encrypt the packet */ |
3207 | 0 | s->dst += s->target.cipher->aead->algo->tag_size; |
3208 | 0 | datagram_size = s->dst - s->payload_buf.datagram; |
3209 | 0 | assert(datagram_size <= conn->egress.max_udp_payload_size); |
3210 | | |
3211 | 0 | conn->super.ctx->crypto_engine->encrypt_packet( |
3212 | 0 | conn->super.ctx->crypto_engine, conn, s->target.cipher->header_protection, s->target.cipher->aead, |
3213 | 0 | ptls_iovec_init(s->payload_buf.datagram, datagram_size), s->target.first_byte_at - s->payload_buf.datagram, |
3214 | 0 | s->dst_payload_from - s->payload_buf.datagram, conn->egress.packet_number, coalesced); |
3215 | | |
3216 | | /* update CC, commit sentmap */ |
3217 | 0 | if (s->target.ack_eliciting) { |
3218 | 0 | packet_bytes_in_flight = s->dst - s->target.first_byte_at; |
3219 | 0 | s->send_window -= packet_bytes_in_flight; |
3220 | 0 | } else { |
3221 | 0 | packet_bytes_in_flight = 0; |
3222 | 0 | } |
3223 | 0 | if (quicly_sentmap_is_open(&conn->egress.loss.sentmap)) |
3224 | 0 | quicly_sentmap_commit(&conn->egress.loss.sentmap, (uint16_t)packet_bytes_in_flight); |
3225 | |
|
3226 | 0 | conn->egress.cc.type->cc_on_sent(&conn->egress.cc, &conn->egress.loss, (uint32_t)packet_bytes_in_flight, conn->stash.now); |
3227 | 0 | QUICLY_PROBE(PACKET_SENT, conn, conn->stash.now, conn->egress.packet_number, s->dst - s->target.first_byte_at, |
3228 | 0 | get_epoch(*s->target.first_byte_at), !s->target.ack_eliciting); |
3229 | 0 | QUICLY_LOG_CONN(packet_sent, conn, { |
3230 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(pn, conn->egress.packet_number); |
3231 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(len, s->dst - s->target.first_byte_at); |
3232 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(*s->target.first_byte_at)); |
3233 | 0 | PTLS_LOG_ELEMENT_BOOL(ack_only, !s->target.ack_eliciting); |
3234 | 0 | }); |
3235 | | |
3236 | 0 | ++conn->egress.packet_number; |
3237 | 0 | ++conn->super.stats.num_packets.sent; |
3238 | |
|
3239 | 0 | if (!coalesced) { |
3240 | 0 | conn->super.stats.num_bytes.sent += datagram_size; |
3241 | 0 | s->datagrams[s->num_datagrams++] = (struct iovec){.iov_base = s->payload_buf.datagram, .iov_len = datagram_size}; |
3242 | 0 | s->payload_buf.datagram += datagram_size; |
3243 | 0 | s->target.cipher = NULL; |
3244 | 0 | s->target.first_byte_at = NULL; |
3245 | 0 | } |
3246 | | |
3247 | | /* insert PN gap if necessary, registering the PN to the ack queue so that we'd close the connection in the event of receiving |
3248 | | * an ACK for that gap. */ |
3249 | 0 | if (conn->egress.packet_number >= conn->egress.next_pn_to_skip && !QUICLY_PACKET_IS_LONG_HEADER(s->current.first_byte) && |
3250 | 0 | conn->super.state < QUICLY_STATE_CLOSING) { |
3251 | 0 | int ret; |
3252 | 0 | if ((ret = quicly_sentmap_prepare(&conn->egress.loss.sentmap, conn->egress.packet_number, conn->stash.now, |
3253 | 0 | QUICLY_EPOCH_1RTT)) != 0) |
3254 | 0 | return ret; |
3255 | 0 | if (quicly_sentmap_allocate(&conn->egress.loss.sentmap, on_invalid_ack) == NULL) |
3256 | 0 | return PTLS_ERROR_NO_MEMORY; |
3257 | 0 | quicly_sentmap_commit(&conn->egress.loss.sentmap, 0); |
3258 | 0 | ++conn->egress.packet_number; |
3259 | 0 | conn->egress.next_pn_to_skip = calc_next_pn_to_skip(conn->super.ctx->tls, conn->egress.packet_number, conn->egress.cc.cwnd, |
3260 | 0 | conn->egress.max_udp_payload_size); |
3261 | 0 | } |
3262 | | |
3263 | 0 | return 0; |
3264 | 0 | } |
3265 | | |
3266 | | static inline uint8_t *emit_cid(uint8_t *dst, const quicly_cid_t *cid) |
3267 | 0 | { |
3268 | 0 | if (cid->len != 0) { |
3269 | 0 | memcpy(dst, cid->cid, cid->len); |
3270 | 0 | dst += cid->len; |
3271 | 0 | } |
3272 | 0 | return dst; |
3273 | 0 | } |
3274 | | |
3275 | | enum allocate_frame_type { |
3276 | | ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING, |
3277 | | ALLOCATE_FRAME_TYPE_ACK_ELICITING, |
3278 | | ALLOCATE_FRAME_TYPE_ACK_ELICITING_NO_CC, |
3279 | | }; |
3280 | | |
3281 | | static int do_allocate_frame(quicly_conn_t *conn, quicly_send_context_t *s, size_t min_space, enum allocate_frame_type frame_type) |
3282 | 0 | { |
3283 | 0 | int coalescible, ret; |
3284 | |
|
3285 | 0 | assert((s->current.first_byte & QUICLY_QUIC_BIT) != 0); |
3286 | | |
3287 | | /* allocate and setup the new packet if necessary */ |
3288 | 0 | if (s->dst_end - s->dst < min_space || s->target.first_byte_at == NULL) { |
3289 | 0 | coalescible = 0; |
3290 | 0 | } else if (((*s->target.first_byte_at ^ s->current.first_byte) & QUICLY_PACKET_TYPE_BITMASK) != 0) { |
3291 | 0 | coalescible = QUICLY_PACKET_IS_LONG_HEADER(*s->target.first_byte_at); |
3292 | 0 | } else if (s->dst_end - s->dst < min_space) { |
3293 | 0 | coalescible = 0; |
3294 | 0 | } else { |
3295 | | /* use the existing packet */ |
3296 | 0 | goto TargetReady; |
3297 | 0 | } |
3298 | | |
3299 | | /* commit at the same time determining if we will coalesce the packets */ |
3300 | 0 | if (s->target.first_byte_at != NULL) { |
3301 | 0 | if (coalescible) { |
3302 | 0 | size_t overhead = 1 /* type */ + conn->super.remote.cid_set.cids[0].cid.len + QUICLY_SEND_PN_SIZE + |
3303 | 0 | s->current.cipher->aead->algo->tag_size; |
3304 | 0 | if (QUICLY_PACKET_IS_LONG_HEADER(s->current.first_byte)) |
3305 | 0 | overhead += 4 /* version */ + 1 /* cidl */ + conn->super.remote.cid_set.cids[0].cid.len + |
3306 | 0 | conn->super.local.long_header_src_cid.len + |
3307 | 0 | (s->current.first_byte == QUICLY_PACKET_TYPE_INITIAL) /* token_length == 0 */ + 2 /* length */; |
3308 | 0 | size_t packet_min_space = QUICLY_MAX_PN_SIZE - QUICLY_SEND_PN_SIZE; |
3309 | 0 | if (packet_min_space < min_space) |
3310 | 0 | packet_min_space = min_space; |
3311 | 0 | if (overhead + packet_min_space > s->dst_end - s->dst) |
3312 | 0 | coalescible = 0; |
3313 | 0 | } |
3314 | | /* Close the packet under construction. Datagrams being returned by `quicly_send` are padded to full-size (except for the |
3315 | | * last one datagram) so that they can be sent at once using GSO. */ |
3316 | 0 | if (!coalescible) |
3317 | 0 | s->target.full_size = 1; |
3318 | 0 | if ((ret = commit_send_packet(conn, s, coalescible)) != 0) |
3319 | 0 | return ret; |
3320 | 0 | } else { |
3321 | 0 | coalescible = 0; |
3322 | 0 | } |
3323 | | |
3324 | | /* allocate packet */ |
3325 | 0 | if (coalescible) { |
3326 | 0 | s->dst_end += s->target.cipher->aead->algo->tag_size; /* restore the AEAD tag size (tag size can differ bet. epochs) */ |
3327 | 0 | s->target.cipher = s->current.cipher; |
3328 | 0 | } else { |
3329 | 0 | if (s->num_datagrams >= s->max_datagrams) |
3330 | 0 | return QUICLY_ERROR_SENDBUF_FULL; |
3331 | | /* note: send_window (ssize_t) can become negative; see doc-comment */ |
3332 | 0 | if (frame_type == ALLOCATE_FRAME_TYPE_ACK_ELICITING && s->send_window <= 0) |
3333 | 0 | return QUICLY_ERROR_SENDBUF_FULL; |
3334 | 0 | if (s->payload_buf.end - s->payload_buf.datagram < conn->egress.max_udp_payload_size) |
3335 | 0 | return QUICLY_ERROR_SENDBUF_FULL; |
3336 | 0 | s->target.cipher = s->current.cipher; |
3337 | 0 | s->target.full_size = 0; |
3338 | 0 | s->dst = s->payload_buf.datagram; |
3339 | 0 | s->dst_end = s->dst + conn->egress.max_udp_payload_size; |
3340 | 0 | } |
3341 | 0 | s->target.ack_eliciting = 0; |
3342 | |
|
3343 | 0 | QUICLY_PROBE(PACKET_PREPARE, conn, conn->stash.now, s->current.first_byte, |
3344 | 0 | QUICLY_PROBE_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); |
3345 | 0 | QUICLY_LOG_CONN(packet_prepare, conn, { |
3346 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(first_octet, s->current.first_byte); |
3347 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); |
3348 | 0 | }); |
3349 | | |
3350 | | /* emit header */ |
3351 | 0 | s->target.first_byte_at = s->dst; |
3352 | 0 | *s->dst++ = s->current.first_byte | 0x1 /* pnlen == 2 */; |
3353 | 0 | if (QUICLY_PACKET_IS_LONG_HEADER(s->current.first_byte)) { |
3354 | 0 | s->dst = quicly_encode32(s->dst, conn->super.version); |
3355 | 0 | *s->dst++ = conn->super.remote.cid_set.cids[0].cid.len; |
3356 | 0 | s->dst = emit_cid(s->dst, &conn->super.remote.cid_set.cids[0].cid); |
3357 | 0 | *s->dst++ = conn->super.local.long_header_src_cid.len; |
3358 | 0 | s->dst = emit_cid(s->dst, &conn->super.local.long_header_src_cid); |
3359 | | /* token */ |
3360 | 0 | if (s->current.first_byte == QUICLY_PACKET_TYPE_INITIAL) { |
3361 | 0 | s->dst = quicly_encodev(s->dst, conn->token.len); |
3362 | 0 | if (conn->token.len != 0) { |
3363 | 0 | assert(s->dst_end - s->dst > conn->token.len); |
3364 | 0 | memcpy(s->dst, conn->token.base, conn->token.len); |
3365 | 0 | s->dst += conn->token.len; |
3366 | 0 | } |
3367 | 0 | } |
3368 | | /* payload length is filled laterwards (see commit_send_packet) */ |
3369 | 0 | *s->dst++ = 0; |
3370 | 0 | *s->dst++ = 0; |
3371 | 0 | } else { |
3372 | 0 | s->dst = emit_cid(s->dst, &conn->super.remote.cid_set.cids[0].cid); |
3373 | 0 | } |
3374 | 0 | s->dst += QUICLY_SEND_PN_SIZE; /* space for PN bits, filled in at commit time */ |
3375 | 0 | s->dst_payload_from = s->dst; |
3376 | 0 | assert(s->target.cipher->aead != NULL); |
3377 | 0 | s->dst_end -= s->target.cipher->aead->algo->tag_size; |
3378 | 0 | assert(s->dst_end - s->dst >= QUICLY_MAX_PN_SIZE - QUICLY_SEND_PN_SIZE); |
3379 | | |
3380 | 0 | if (conn->super.state < QUICLY_STATE_CLOSING) { |
3381 | | /* register to sentmap */ |
3382 | 0 | uint8_t ack_epoch = get_epoch(s->current.first_byte); |
3383 | 0 | if (ack_epoch == QUICLY_EPOCH_0RTT) |
3384 | 0 | ack_epoch = QUICLY_EPOCH_1RTT; |
3385 | 0 | if ((ret = quicly_sentmap_prepare(&conn->egress.loss.sentmap, conn->egress.packet_number, conn->stash.now, ack_epoch)) != 0) |
3386 | 0 | return ret; |
3387 | | /* adjust ack-frequency */ |
3388 | 0 | if (conn->stash.now >= conn->egress.ack_frequency.update_at) { |
3389 | 0 | assert(conn->super.remote.transport_params.min_ack_delay_usec != UINT64_MAX); |
3390 | 0 | if (conn->egress.cc.num_loss_episodes >= QUICLY_FIRST_ACK_FREQUENCY_LOSS_EPISODE && conn->initial == NULL && |
3391 | 0 | conn->handshake == NULL) { |
3392 | 0 | uint32_t fraction_of_cwnd = (uint32_t)((uint64_t)conn->egress.cc.cwnd * conn->super.ctx->ack_frequency / 1024); |
3393 | 0 | if (fraction_of_cwnd >= conn->egress.max_udp_payload_size * 3) { |
3394 | 0 | uint32_t packet_tolerance = fraction_of_cwnd / conn->egress.max_udp_payload_size; |
3395 | 0 | if (packet_tolerance > QUICLY_MAX_PACKET_TOLERANCE) |
3396 | 0 | packet_tolerance = QUICLY_MAX_PACKET_TOLERANCE; |
3397 | 0 | s->dst = quicly_encode_ack_frequency_frame(s->dst, conn->egress.ack_frequency.sequence++, packet_tolerance, |
3398 | 0 | conn->super.remote.transport_params.max_ack_delay * 1000, 0); |
3399 | 0 | ++conn->super.stats.num_frames_sent.ack_frequency; |
3400 | 0 | } |
3401 | 0 | } |
3402 | 0 | ack_frequency_set_next_update_at(conn); |
3403 | 0 | } |
3404 | 0 | } |
3405 | | |
3406 | 0 | TargetReady: |
3407 | 0 | if (frame_type != ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING) { |
3408 | 0 | s->target.ack_eliciting = 1; |
3409 | 0 | conn->egress.last_retransmittable_sent_at = conn->stash.now; |
3410 | 0 | } |
3411 | 0 | return 0; |
3412 | 0 | } |
3413 | | |
3414 | | static int allocate_ack_eliciting_frame(quicly_conn_t *conn, quicly_send_context_t *s, size_t min_space, quicly_sent_t **sent, |
3415 | | quicly_sent_acked_cb acked) |
3416 | 0 | { |
3417 | 0 | int ret; |
3418 | |
|
3419 | 0 | if ((ret = do_allocate_frame(conn, s, min_space, ALLOCATE_FRAME_TYPE_ACK_ELICITING)) != 0) |
3420 | 0 | return ret; |
3421 | 0 | if ((*sent = quicly_sentmap_allocate(&conn->egress.loss.sentmap, acked)) == NULL) |
3422 | 0 | return PTLS_ERROR_NO_MEMORY; |
3423 | | |
3424 | 0 | return ret; |
3425 | 0 | } |
3426 | | |
3427 | | static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, quicly_send_context_t *s) |
3428 | 0 | { |
3429 | 0 | uint64_t ack_delay; |
3430 | 0 | int ret; |
3431 | |
|
3432 | 0 | if (space->ack_queue.num_ranges == 0) |
3433 | 0 | return 0; |
3434 | | |
3435 | | /* calc ack_delay */ |
3436 | 0 | if (space->largest_pn_received_at < conn->stash.now) { |
3437 | | /* We underreport ack_delay up to 1 milliseconds assuming that QUICLY_LOCAL_ACK_DELAY_EXPONENT is 10. It's considered a |
3438 | | * non-issue because our time measurement is at millisecond granularity anyways. */ |
3439 | 0 | ack_delay = ((conn->stash.now - space->largest_pn_received_at) * 1000) >> QUICLY_LOCAL_ACK_DELAY_EXPONENT; |
3440 | 0 | } else { |
3441 | 0 | ack_delay = 0; |
3442 | 0 | } |
3443 | |
|
3444 | 0 | Emit: /* emit an ACK frame */ |
3445 | 0 | if ((ret = do_allocate_frame(conn, s, QUICLY_ACK_FRAME_CAPACITY, ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING)) != 0) |
3446 | 0 | return ret; |
3447 | 0 | uint8_t *dst = s->dst; |
3448 | 0 | dst = quicly_encode_ack_frame(dst, s->dst_end, &space->ack_queue, ack_delay); |
3449 | | |
3450 | | /* when there's no space, retry with a new MTU-sized packet */ |
3451 | 0 | if (dst == NULL) { |
3452 | | /* [rare case] A coalesced packet might not have enough space to hold only an ACK. If so, pad it, as that's easier than |
3453 | | * rolling back. */ |
3454 | 0 | if (s->dst == s->dst_payload_from) { |
3455 | 0 | assert(s->target.first_byte_at != s->payload_buf.datagram); |
3456 | 0 | *s->dst++ = QUICLY_FRAME_TYPE_PADDING; |
3457 | 0 | } |
3458 | 0 | s->target.full_size = 1; |
3459 | 0 | if ((ret = commit_send_packet(conn, s, 0)) != 0) |
3460 | 0 | return ret; |
3461 | 0 | goto Emit; |
3462 | 0 | } |
3463 | | |
3464 | 0 | ++conn->super.stats.num_frames_sent.ack; |
3465 | 0 | QUICLY_PROBE(ACK_SEND, conn, conn->stash.now, space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end - 1, ack_delay); |
3466 | 0 | QUICLY_LOG_CONN(ack_send, conn, { |
3467 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(largest_acked, space->ack_queue.ranges[space->ack_queue.num_ranges - 1].end - 1); |
3468 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(ack_delay, ack_delay); |
3469 | 0 | }); |
3470 | | |
3471 | | /* when there are no less than QUICLY_NUM_ACK_BLOCKS_TO_INDUCE_ACKACK (8) gaps, bundle PING once every 4 packets being sent */ |
3472 | 0 | if (space->ack_queue.num_ranges >= QUICLY_NUM_ACK_BLOCKS_TO_INDUCE_ACKACK && conn->egress.packet_number % 4 == 0 && |
3473 | 0 | dst < s->dst_end) { |
3474 | 0 | *dst++ = QUICLY_FRAME_TYPE_PING; |
3475 | 0 | ++conn->super.stats.num_frames_sent.ping; |
3476 | 0 | QUICLY_PROBE(PING_SEND, conn, conn->stash.now); |
3477 | 0 | QUICLY_LOG_CONN(ping_send, conn, {}); |
3478 | 0 | } |
3479 | | |
3480 | 0 | s->dst = dst; |
3481 | |
|
3482 | 0 | { /* save what's inflight */ |
3483 | 0 | size_t range_index = 0; |
3484 | 0 | while (range_index < space->ack_queue.num_ranges) { |
3485 | 0 | quicly_sent_t *sent; |
3486 | 0 | struct st_quicly_sent_ack_additional_t *additional, *additional_end; |
3487 | | /* allocate */ |
3488 | 0 | if ((sent = quicly_sentmap_allocate(&conn->egress.loss.sentmap, on_ack_ack_ranges8)) == NULL) |
3489 | 0 | return PTLS_ERROR_NO_MEMORY; |
3490 | | /* store the first range, as well as preparing references to the additional slots */ |
3491 | 0 | sent->data.ack.start = space->ack_queue.ranges[range_index].start; |
3492 | 0 | uint64_t length = space->ack_queue.ranges[range_index].end - space->ack_queue.ranges[range_index].start; |
3493 | 0 | if (length <= UINT8_MAX) { |
3494 | 0 | sent->data.ack.ranges8.start_length = length; |
3495 | 0 | additional = sent->data.ack.ranges8.additional; |
3496 | 0 | additional_end = additional + PTLS_ELEMENTSOF(sent->data.ack.ranges8.additional); |
3497 | 0 | } else { |
3498 | 0 | sent->acked = on_ack_ack_ranges64; |
3499 | 0 | sent->data.ack.ranges64.start_length = length; |
3500 | 0 | additional = sent->data.ack.ranges64.additional; |
3501 | 0 | additional_end = additional + PTLS_ELEMENTSOF(sent->data.ack.ranges64.additional); |
3502 | 0 | } |
3503 | | /* store additional ranges, if possible */ |
3504 | 0 | for (++range_index; range_index < space->ack_queue.num_ranges && additional < additional_end; |
3505 | 0 | ++range_index, ++additional) { |
3506 | 0 | uint64_t gap = space->ack_queue.ranges[range_index].start - space->ack_queue.ranges[range_index - 1].end; |
3507 | 0 | uint64_t length = space->ack_queue.ranges[range_index].end - space->ack_queue.ranges[range_index].start; |
3508 | 0 | if (gap > UINT8_MAX || length > UINT8_MAX) |
3509 | 0 | break; |
3510 | 0 | additional->gap = gap; |
3511 | 0 | additional->length = length; |
3512 | 0 | } |
3513 | | /* additional list is zero-terminated, if not full */ |
3514 | 0 | if (additional < additional_end) |
3515 | 0 | additional->gap = 0; |
3516 | 0 | } |
3517 | 0 | } |
3518 | | |
3519 | 0 | space->unacked_count = 0; |
3520 | |
|
3521 | 0 | return ret; |
3522 | 0 | } |
3523 | | |
3524 | | static int prepare_stream_state_sender(quicly_stream_t *stream, quicly_sender_state_t *sender, quicly_send_context_t *s, |
3525 | | size_t min_space, quicly_sent_acked_cb ack_cb) |
3526 | 0 | { |
3527 | 0 | quicly_sent_t *sent; |
3528 | 0 | int ret; |
3529 | |
|
3530 | 0 | if ((ret = allocate_ack_eliciting_frame(stream->conn, s, min_space, &sent, ack_cb)) != 0) |
3531 | 0 | return ret; |
3532 | 0 | sent->data.stream_state_sender.stream_id = stream->stream_id; |
3533 | 0 | *sender = QUICLY_SENDER_STATE_UNACKED; |
3534 | |
|
3535 | 0 | return 0; |
3536 | 0 | } |
3537 | | |
3538 | | static int send_control_frames_of_stream(quicly_stream_t *stream, quicly_send_context_t *s) |
3539 | 0 | { |
3540 | 0 | int ret; |
3541 | | |
3542 | | /* send STOP_SENDING if necessary */ |
3543 | 0 | if (stream->_send_aux.stop_sending.sender_state == QUICLY_SENDER_STATE_SEND) { |
3544 | | /* FIXME also send an empty STREAM frame */ |
3545 | 0 | if ((ret = prepare_stream_state_sender(stream, &stream->_send_aux.stop_sending.sender_state, s, |
3546 | 0 | QUICLY_STOP_SENDING_FRAME_CAPACITY, on_ack_stop_sending)) != 0) |
3547 | 0 | return ret; |
3548 | 0 | s->dst = quicly_encode_stop_sending_frame(s->dst, stream->stream_id, stream->_send_aux.stop_sending.error_code); |
3549 | 0 | ++stream->conn->super.stats.num_frames_sent.stop_sending; |
3550 | 0 | QUICLY_PROBE(STOP_SENDING_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, |
3551 | 0 | stream->_send_aux.stop_sending.error_code); |
3552 | 0 | QUICLY_LOG_CONN(stop_sending_send, stream->conn, { |
3553 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
3554 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.stop_sending.error_code); |
3555 | 0 | }); |
3556 | 0 | } |
3557 | | |
3558 | | /* send MAX_STREAM_DATA if necessary */ |
3559 | 0 | if (should_send_max_stream_data(stream)) { |
3560 | 0 | uint64_t new_value = stream->recvstate.data_off + stream->_recv_aux.window; |
3561 | 0 | quicly_sent_t *sent; |
3562 | | /* prepare */ |
3563 | 0 | if ((ret = allocate_ack_eliciting_frame(stream->conn, s, QUICLY_MAX_STREAM_DATA_FRAME_CAPACITY, &sent, |
3564 | 0 | on_ack_max_stream_data)) != 0) |
3565 | 0 | return ret; |
3566 | | /* send */ |
3567 | 0 | s->dst = quicly_encode_max_stream_data_frame(s->dst, stream->stream_id, new_value); |
3568 | | /* register ack */ |
3569 | 0 | sent->data.max_stream_data.stream_id = stream->stream_id; |
3570 | 0 | quicly_maxsender_record(&stream->_send_aux.max_stream_data_sender, new_value, &sent->data.max_stream_data.args); |
3571 | | /* update stats */ |
3572 | 0 | ++stream->conn->super.stats.num_frames_sent.max_stream_data; |
3573 | 0 | QUICLY_PROBE(MAX_STREAM_DATA_SEND, stream->conn, stream->conn->stash.now, stream, new_value); |
3574 | 0 | QUICLY_LOG_CONN(max_stream_data_send, stream->conn, { |
3575 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
3576 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_value); |
3577 | 0 | }); |
3578 | 0 | } |
3579 | | |
3580 | | /* send RESET_STREAM if necessary */ |
3581 | 0 | if (stream->_send_aux.reset_stream.sender_state == QUICLY_SENDER_STATE_SEND) { |
3582 | 0 | if ((ret = prepare_stream_state_sender(stream, &stream->_send_aux.reset_stream.sender_state, s, QUICLY_RST_FRAME_CAPACITY, |
3583 | 0 | on_ack_reset_stream)) != 0) |
3584 | 0 | return ret; |
3585 | 0 | s->dst = quicly_encode_reset_stream_frame(s->dst, stream->stream_id, stream->_send_aux.reset_stream.error_code, |
3586 | 0 | stream->sendstate.size_inflight); |
3587 | 0 | ++stream->conn->super.stats.num_frames_sent.reset_stream; |
3588 | 0 | QUICLY_PROBE(RESET_STREAM_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, |
3589 | 0 | stream->_send_aux.reset_stream.error_code, stream->sendstate.size_inflight); |
3590 | 0 | QUICLY_LOG_CONN(reset_stream_send, stream->conn, { |
3591 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
3592 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(error_code, stream->_send_aux.reset_stream.error_code); |
3593 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(final_size, stream->sendstate.size_inflight); |
3594 | 0 | }); |
3595 | 0 | } |
3596 | | |
3597 | | /* send STREAM_DATA_BLOCKED if necessary */ |
3598 | 0 | if (stream->_send_aux.blocked == QUICLY_SENDER_STATE_SEND) { |
3599 | 0 | quicly_sent_t *sent; |
3600 | 0 | if ((ret = allocate_ack_eliciting_frame(stream->conn, s, QUICLY_STREAM_DATA_BLOCKED_FRAME_CAPACITY, &sent, |
3601 | 0 | on_ack_stream_data_blocked_frame)) != 0) |
3602 | 0 | return ret; |
3603 | 0 | uint64_t offset = stream->_send_aux.max_stream_data; |
3604 | 0 | sent->data.stream_data_blocked.stream_id = stream->stream_id; |
3605 | 0 | sent->data.stream_data_blocked.offset = offset; |
3606 | 0 | s->dst = quicly_encode_stream_data_blocked_frame(s->dst, stream->stream_id, offset); |
3607 | 0 | stream->_send_aux.blocked = QUICLY_SENDER_STATE_UNACKED; |
3608 | 0 | ++stream->conn->super.stats.num_frames_sent.stream_data_blocked; |
3609 | 0 | QUICLY_PROBE(STREAM_DATA_BLOCKED_SEND, stream->conn, stream->conn->stash.now, stream->stream_id, offset); |
3610 | 0 | QUICLY_LOG_CONN(stream_data_blocked_send, stream->conn, { |
3611 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
3612 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(maximum, offset); |
3613 | 0 | }); |
3614 | 0 | } |
3615 | | |
3616 | 0 | return 0; |
3617 | 0 | } |
3618 | | |
3619 | | static int send_stream_control_frames(quicly_conn_t *conn, quicly_send_context_t *s) |
3620 | 0 | { |
3621 | 0 | int ret = 0; |
3622 | |
|
3623 | 0 | while (s->num_datagrams != s->max_datagrams && quicly_linklist_is_linked(&conn->egress.pending_streams.control)) { |
3624 | 0 | quicly_stream_t *stream = |
3625 | 0 | (void *)((char *)conn->egress.pending_streams.control.next - offsetof(quicly_stream_t, _send_aux.pending_link.control)); |
3626 | 0 | if ((ret = send_control_frames_of_stream(stream, s)) != 0) |
3627 | 0 | goto Exit; |
3628 | 0 | quicly_linklist_unlink(&stream->_send_aux.pending_link.control); |
3629 | 0 | } |
3630 | | |
3631 | 0 | Exit: |
3632 | 0 | return ret; |
3633 | 0 | } |
3634 | | |
3635 | | int quicly_is_blocked(quicly_conn_t *conn) |
3636 | 0 | { |
3637 | 0 | if (conn->egress.max_data.sent < conn->egress.max_data.permitted) |
3638 | 0 | return 0; |
3639 | | |
3640 | | /* schedule the transmission of DATA_BLOCKED frame, if it's new information */ |
3641 | 0 | if (conn->egress.data_blocked == QUICLY_SENDER_STATE_NONE) |
3642 | 0 | conn->egress.data_blocked = QUICLY_SENDER_STATE_SEND; |
3643 | |
|
3644 | 0 | return 1; |
3645 | 0 | } |
3646 | | |
3647 | | int quicly_stream_can_send(quicly_stream_t *stream, int at_stream_level) |
3648 | 0 | { |
3649 | | /* return if there is nothing to be sent */ |
3650 | 0 | if (stream->sendstate.pending.num_ranges == 0) |
3651 | 0 | return 0; |
3652 | | |
3653 | | /* return if flow is capped neither by MAX_STREAM_DATA nor (in case we are hitting connection-level flow control) by the number |
3654 | | * of bytes we've already sent */ |
3655 | 0 | uint64_t blocked_at = at_stream_level ? stream->_send_aux.max_stream_data : stream->sendstate.size_inflight; |
3656 | 0 | if (stream->sendstate.pending.ranges[0].start < blocked_at) |
3657 | 0 | return 1; |
3658 | | /* we can always send EOS, if that is the only thing to be sent */ |
3659 | 0 | if (stream->sendstate.pending.ranges[0].start >= stream->sendstate.final_size) { |
3660 | 0 | assert(stream->sendstate.pending.ranges[0].start == stream->sendstate.final_size); |
3661 | 0 | return 1; |
3662 | 0 | } |
3663 | | |
3664 | | /* if known to be blocked at stream-level, schedule the emission of STREAM_DATA_BLOCKED frame */ |
3665 | 0 | if (at_stream_level && stream->_send_aux.blocked == QUICLY_SENDER_STATE_NONE) { |
3666 | 0 | stream->_send_aux.blocked = QUICLY_SENDER_STATE_SEND; |
3667 | 0 | sched_stream_control(stream); |
3668 | 0 | } |
3669 | |
|
3670 | 0 | return 0; |
3671 | 0 | } |
3672 | | |
3673 | | int quicly_can_send_data(quicly_conn_t *conn, quicly_send_context_t *s) |
3674 | 0 | { |
3675 | 0 | return s->num_datagrams < s->max_datagrams; |
3676 | 0 | } |
3677 | | |
3678 | | /** |
3679 | | * If necessary, changes the frame representation from one without length field to one that has if necessary. Or, as an alternative, |
3680 | | * prepends PADDING frames. Upon return, `dst` points to the end of the frame being built. `*len`, `*wrote_all`, `*frame_type_at` |
3681 | | * are also updated reflecting their values post-adjustment. |
3682 | | */ |
3683 | | static inline void adjust_stream_frame_layout(uint8_t **dst, uint8_t *const dst_end, size_t *len, int *wrote_all, |
3684 | | uint8_t **frame_at) |
3685 | 0 | { |
3686 | 0 | size_t space_left = (dst_end - *dst) - *len, len_of_len = quicly_encodev_capacity(*len); |
3687 | |
|
3688 | 0 | if (**frame_at == QUICLY_FRAME_TYPE_CRYPTO) { |
3689 | | /* CRYPTO frame: adjust payload length to make space for the length field, if necessary. */ |
3690 | 0 | if (space_left < len_of_len) { |
3691 | 0 | *len = dst_end - *dst - len_of_len; |
3692 | 0 | *wrote_all = 0; |
3693 | 0 | } |
3694 | 0 | } else { |
3695 | | /* STREAM frame: insert length if space can be left for more frames. Otherwise, retain STREAM frame header omitting the |
3696 | | * length field, prepending PADDING if necessary. */ |
3697 | 0 | if (space_left <= len_of_len) { |
3698 | 0 | if (space_left != 0) { |
3699 | 0 | memmove(*frame_at + space_left, *frame_at, *dst + *len - *frame_at); |
3700 | 0 | memset(*frame_at, QUICLY_FRAME_TYPE_PADDING, space_left); |
3701 | 0 | *dst += space_left; |
3702 | 0 | *frame_at += space_left; |
3703 | 0 | } |
3704 | 0 | *dst += *len; |
3705 | 0 | return; |
3706 | 0 | } |
3707 | 0 | **frame_at |= QUICLY_FRAME_TYPE_STREAM_BIT_LEN; |
3708 | 0 | } |
3709 | | |
3710 | | /* insert length before payload of `*len` bytes */ |
3711 | 0 | memmove(*dst + len_of_len, *dst, *len); |
3712 | 0 | *dst = quicly_encodev(*dst, *len); |
3713 | 0 | *dst += *len; |
3714 | 0 | } |
3715 | | |
3716 | | int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s) |
3717 | 0 | { |
3718 | 0 | uint64_t off = stream->sendstate.pending.ranges[0].start; |
3719 | 0 | quicly_sent_t *sent; |
3720 | 0 | uint8_t *dst; /* this pointer points to the current write position within the frame being built, while `s->dst` points to the |
3721 | | * beginning of the frame. */ |
3722 | 0 | size_t len; |
3723 | 0 | int ret, wrote_all, is_fin; |
3724 | | |
3725 | | /* write frame type, stream_id and offset, calculate capacity (and store that in `len`) */ |
3726 | 0 | if (stream->stream_id < 0) { |
3727 | 0 | if ((ret = allocate_ack_eliciting_frame(stream->conn, s, |
3728 | 0 | 1 + quicly_encodev_capacity(off) + 2 /* type + offset + len + 1-byte payload */, |
3729 | 0 | &sent, on_ack_stream)) != 0) |
3730 | 0 | return ret; |
3731 | 0 | dst = s->dst; |
3732 | 0 | *dst++ = QUICLY_FRAME_TYPE_CRYPTO; |
3733 | 0 | dst = quicly_encodev(dst, off); |
3734 | 0 | len = s->dst_end - dst; |
3735 | 0 | } else { |
3736 | 0 | uint8_t header[18], *hp = header + 1; |
3737 | 0 | hp = quicly_encodev(hp, stream->stream_id); |
3738 | 0 | if (off != 0) { |
3739 | 0 | header[0] = QUICLY_FRAME_TYPE_STREAM_BASE | QUICLY_FRAME_TYPE_STREAM_BIT_OFF; |
3740 | 0 | hp = quicly_encodev(hp, off); |
3741 | 0 | } else { |
3742 | 0 | header[0] = QUICLY_FRAME_TYPE_STREAM_BASE; |
3743 | 0 | } |
3744 | 0 | if (off == stream->sendstate.final_size) { |
3745 | 0 | assert(!quicly_sendstate_is_open(&stream->sendstate)); |
3746 | | /* special case for emitting FIN only */ |
3747 | 0 | header[0] |= QUICLY_FRAME_TYPE_STREAM_BIT_FIN; |
3748 | 0 | if ((ret = allocate_ack_eliciting_frame(stream->conn, s, hp - header, &sent, on_ack_stream)) != 0) |
3749 | 0 | return ret; |
3750 | 0 | if (hp - header != s->dst_end - s->dst) { |
3751 | 0 | header[0] |= QUICLY_FRAME_TYPE_STREAM_BIT_LEN; |
3752 | 0 | *hp++ = 0; /* empty length */ |
3753 | 0 | } |
3754 | 0 | memcpy(s->dst, header, hp - header); |
3755 | 0 | s->dst += hp - header; |
3756 | 0 | len = 0; |
3757 | 0 | wrote_all = 1; |
3758 | 0 | is_fin = 1; |
3759 | 0 | goto UpdateState; |
3760 | 0 | } |
3761 | 0 | if ((ret = allocate_ack_eliciting_frame(stream->conn, s, hp - header + 1, &sent, on_ack_stream)) != 0) |
3762 | 0 | return ret; |
3763 | 0 | dst = s->dst; |
3764 | 0 | memcpy(dst, header, hp - header); |
3765 | 0 | dst += hp - header; |
3766 | 0 | len = s->dst_end - dst; |
3767 | | /* cap by max_stream_data */ |
3768 | 0 | if (off + len > stream->_send_aux.max_stream_data) |
3769 | 0 | len = stream->_send_aux.max_stream_data - off; |
3770 | | /* cap by max_data */ |
3771 | 0 | if (off + len > stream->sendstate.size_inflight) { |
3772 | 0 | uint64_t new_bytes = off + len - stream->sendstate.size_inflight; |
3773 | 0 | if (new_bytes > stream->conn->egress.max_data.permitted - stream->conn->egress.max_data.sent) { |
3774 | 0 | size_t max_stream_data = |
3775 | 0 | stream->sendstate.size_inflight + stream->conn->egress.max_data.permitted - stream->conn->egress.max_data.sent; |
3776 | 0 | len = max_stream_data - off; |
3777 | 0 | } |
3778 | 0 | } |
3779 | 0 | } |
3780 | 0 | { /* cap len to the current range */ |
3781 | 0 | uint64_t range_capacity = stream->sendstate.pending.ranges[0].end - off; |
3782 | 0 | if (off + range_capacity > stream->sendstate.final_size) { |
3783 | 0 | assert(!quicly_sendstate_is_open(&stream->sendstate)); |
3784 | 0 | assert(range_capacity > 1); /* see the special case above */ |
3785 | 0 | range_capacity -= 1; |
3786 | 0 | } |
3787 | 0 | if (len > range_capacity) |
3788 | 0 | len = range_capacity; |
3789 | 0 | } |
3790 | | |
3791 | | /* Write payload, adjusting len to actual size. Note that `on_send_emit` might fail (e.g., when underlying pread(2) fails), in |
3792 | | * which case the application will either close the connection immediately or reset the stream. If that happens, we return |
3793 | | * immediately without updating state. */ |
3794 | 0 | assert(len != 0); |
3795 | 0 | size_t emit_off = (size_t)(off - stream->sendstate.acked.ranges[0].end); |
3796 | 0 | QUICLY_PROBE(STREAM_ON_SEND_EMIT, stream->conn, stream->conn->stash.now, stream, emit_off, len); |
3797 | 0 | QUICLY_LOG_CONN(stream_on_send_emit, stream->conn, { |
3798 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
3799 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(off, off); |
3800 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(capacity, len); |
3801 | 0 | }); |
3802 | 0 | stream->callbacks->on_send_emit(stream, emit_off, dst, &len, &wrote_all); |
3803 | 0 | if (stream->conn->super.state >= QUICLY_STATE_CLOSING) { |
3804 | 0 | return QUICLY_ERROR_IS_CLOSING; |
3805 | 0 | } else if (stream->_send_aux.reset_stream.sender_state != QUICLY_SENDER_STATE_NONE) { |
3806 | 0 | return 0; |
3807 | 0 | } |
3808 | 0 | assert(len != 0); |
3809 | | |
3810 | 0 | adjust_stream_frame_layout(&dst, s->dst_end, &len, &wrote_all, &s->dst); |
3811 | | |
3812 | | /* determine if the frame incorporates FIN */ |
3813 | 0 | if (off + len == stream->sendstate.final_size) { |
3814 | 0 | assert(!quicly_sendstate_is_open(&stream->sendstate)); |
3815 | 0 | assert(s->dst != NULL); |
3816 | 0 | is_fin = 1; |
3817 | 0 | *s->dst |= QUICLY_FRAME_TYPE_STREAM_BIT_FIN; |
3818 | 0 | } else { |
3819 | 0 | is_fin = 0; |
3820 | 0 | } |
3821 | | |
3822 | | /* update s->dst now that frame construction is complete */ |
3823 | 0 | s->dst = dst; |
3824 | |
|
3825 | 0 | UpdateState: |
3826 | 0 | if (stream->stream_id < 0) { |
3827 | 0 | ++stream->conn->super.stats.num_frames_sent.crypto; |
3828 | 0 | } else { |
3829 | 0 | ++stream->conn->super.stats.num_frames_sent.stream; |
3830 | 0 | } |
3831 | 0 | stream->conn->super.stats.num_bytes.stream_data_sent += len; |
3832 | 0 | if (off < stream->sendstate.size_inflight) |
3833 | 0 | stream->conn->super.stats.num_bytes.stream_data_resent += |
3834 | 0 | (stream->sendstate.size_inflight < off + len ? stream->sendstate.size_inflight : off + len) - off; |
3835 | 0 | QUICLY_PROBE(STREAM_SEND, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); |
3836 | 0 | QUICLY_LOG_CONN(stream_send, stream->conn, { |
3837 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
3838 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(off, off); |
3839 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(len, len); |
3840 | 0 | PTLS_LOG_ELEMENT_BOOL(is_fin, is_fin); |
3841 | 0 | }); |
3842 | | |
3843 | 0 | QUICLY_PROBE(QUICTRACE_SEND_STREAM, stream->conn, stream->conn->stash.now, stream, off, len, is_fin); |
3844 | | /* update sendstate (and also MAX_DATA counter) */ |
3845 | 0 | if (stream->sendstate.size_inflight < off + len) { |
3846 | 0 | if (stream->stream_id >= 0) |
3847 | 0 | stream->conn->egress.max_data.sent += off + len - stream->sendstate.size_inflight; |
3848 | 0 | stream->sendstate.size_inflight = off + len; |
3849 | 0 | } |
3850 | 0 | if ((ret = quicly_ranges_subtract(&stream->sendstate.pending, off, off + len + is_fin)) != 0) |
3851 | 0 | return ret; |
3852 | 0 | if (wrote_all) { |
3853 | 0 | if ((ret = quicly_ranges_subtract(&stream->sendstate.pending, stream->sendstate.size_inflight, UINT64_MAX)) != 0) |
3854 | 0 | return ret; |
3855 | 0 | } |
3856 | | |
3857 | | /* setup sentmap */ |
3858 | 0 | sent->data.stream.stream_id = stream->stream_id; |
3859 | 0 | sent->data.stream.args.start = off; |
3860 | 0 | sent->data.stream.args.end = off + len + is_fin; |
3861 | |
|
3862 | 0 | return 0; |
3863 | 0 | } |
3864 | | |
3865 | | static inline int init_acks_iter(quicly_conn_t *conn, quicly_sentmap_iter_t *iter) |
3866 | 0 | { |
3867 | 0 | return quicly_loss_init_sentmap_iter(&conn->egress.loss, iter, conn->stash.now, |
3868 | 0 | conn->super.remote.transport_params.max_ack_delay, |
3869 | 0 | conn->super.state >= QUICLY_STATE_CLOSING); |
3870 | 0 | } |
3871 | | |
3872 | | int discard_sentmap_by_epoch(quicly_conn_t *conn, unsigned ack_epochs) |
3873 | 0 | { |
3874 | 0 | quicly_sentmap_iter_t iter; |
3875 | 0 | const quicly_sent_packet_t *sent; |
3876 | 0 | int ret; |
3877 | |
|
3878 | 0 | if ((ret = init_acks_iter(conn, &iter)) != 0) |
3879 | 0 | return ret; |
3880 | | |
3881 | 0 | while ((sent = quicly_sentmap_get(&iter))->packet_number != UINT64_MAX) { |
3882 | 0 | if ((ack_epochs & (1u << sent->ack_epoch)) != 0) { |
3883 | 0 | if ((ret = quicly_sentmap_update(&conn->egress.loss.sentmap, &iter, QUICLY_SENTMAP_EVENT_EXPIRED)) != 0) |
3884 | 0 | return ret; |
3885 | 0 | } else { |
3886 | 0 | quicly_sentmap_skip(&iter); |
3887 | 0 | } |
3888 | 0 | } |
3889 | | |
3890 | 0 | return ret; |
3891 | 0 | } |
3892 | | |
3893 | | /** |
3894 | | * Mark frames of given epoch as pending, until `*bytes_to_mark` becomes zero. |
3895 | | */ |
3896 | | static int mark_frames_on_pto(quicly_conn_t *conn, uint8_t ack_epoch, size_t *bytes_to_mark) |
3897 | 0 | { |
3898 | 0 | quicly_sentmap_iter_t iter; |
3899 | 0 | const quicly_sent_packet_t *sent; |
3900 | 0 | int ret; |
3901 | |
|
3902 | 0 | if ((ret = init_acks_iter(conn, &iter)) != 0) |
3903 | 0 | return ret; |
3904 | | |
3905 | 0 | while ((sent = quicly_sentmap_get(&iter))->packet_number != UINT64_MAX) { |
3906 | 0 | if (sent->ack_epoch == ack_epoch && sent->frames_in_flight) { |
3907 | 0 | *bytes_to_mark = *bytes_to_mark > sent->cc_bytes_in_flight ? *bytes_to_mark - sent->cc_bytes_in_flight : 0; |
3908 | 0 | if ((ret = quicly_sentmap_update(&conn->egress.loss.sentmap, &iter, QUICLY_SENTMAP_EVENT_PTO)) != 0) |
3909 | 0 | return ret; |
3910 | 0 | assert(!sent->frames_in_flight); |
3911 | 0 | if (*bytes_to_mark == 0) |
3912 | 0 | break; |
3913 | 0 | } else { |
3914 | 0 | quicly_sentmap_skip(&iter); |
3915 | 0 | } |
3916 | 0 | } |
3917 | | |
3918 | 0 | return 0; |
3919 | 0 | } |
3920 | | |
3921 | | static void on_loss_detected(quicly_loss_t *loss, const quicly_sent_packet_t *lost_packet, int is_time_threshold) |
3922 | 0 | { |
3923 | 0 | quicly_conn_t *conn = (void *)((char *)loss - offsetof(quicly_conn_t, egress.loss)); |
3924 | |
|
3925 | 0 | ++conn->super.stats.num_packets.lost; |
3926 | 0 | if (is_time_threshold) |
3927 | 0 | ++conn->super.stats.num_packets.lost_time_threshold; |
3928 | 0 | conn->super.stats.num_bytes.lost += lost_packet->cc_bytes_in_flight; |
3929 | 0 | conn->egress.cc.type->cc_on_lost(&conn->egress.cc, &conn->egress.loss, lost_packet->cc_bytes_in_flight, |
3930 | 0 | lost_packet->packet_number, conn->egress.packet_number, conn->stash.now, |
3931 | 0 | conn->egress.max_udp_payload_size); |
3932 | 0 | QUICLY_PROBE(PACKET_LOST, conn, conn->stash.now, lost_packet->packet_number, lost_packet->ack_epoch); |
3933 | 0 | QUICLY_LOG_CONN(packet_lost, conn, { |
3934 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(pn, lost_packet->packet_number); |
3935 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(packet_type, lost_packet->ack_epoch); |
3936 | 0 | }); |
3937 | 0 | QUICLY_PROBE(CC_CONGESTION, conn, conn->stash.now, lost_packet->packet_number + 1, conn->egress.loss.sentmap.bytes_in_flight, |
3938 | 0 | conn->egress.cc.cwnd); |
3939 | 0 | QUICLY_LOG_CONN(cc_congestion, conn, { |
3940 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(max_lost_pn, lost_packet->packet_number + 1); |
3941 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(flight, conn->egress.loss.sentmap.bytes_in_flight); |
3942 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); |
3943 | 0 | }); |
3944 | 0 | QUICLY_PROBE(QUICTRACE_CC_LOST, conn, conn->stash.now, &conn->egress.loss.rtt, conn->egress.cc.cwnd, |
3945 | 0 | conn->egress.loss.sentmap.bytes_in_flight); |
3946 | 0 | } |
3947 | | |
3948 | | static int send_max_streams(quicly_conn_t *conn, int uni, quicly_send_context_t *s) |
3949 | 0 | { |
3950 | 0 | if (!should_send_max_streams(conn, uni)) |
3951 | 0 | return 0; |
3952 | | |
3953 | 0 | quicly_maxsender_t *maxsender = uni ? &conn->ingress.max_streams.uni : &conn->ingress.max_streams.bidi; |
3954 | 0 | struct st_quicly_conn_streamgroup_state_t *group = uni ? &conn->super.remote.uni : &conn->super.remote.bidi; |
3955 | 0 | int ret; |
3956 | |
|
3957 | 0 | uint64_t new_count = |
3958 | 0 | group->next_stream_id / 4 + |
3959 | 0 | (uni ? conn->super.ctx->transport_params.max_streams_uni : conn->super.ctx->transport_params.max_streams_bidi) - |
3960 | 0 | group->num_streams; |
3961 | |
|
3962 | 0 | quicly_sent_t *sent; |
3963 | 0 | if ((ret = allocate_ack_eliciting_frame(conn, s, QUICLY_MAX_STREAMS_FRAME_CAPACITY, &sent, on_ack_max_streams)) != 0) |
3964 | 0 | return ret; |
3965 | 0 | s->dst = quicly_encode_max_streams_frame(s->dst, uni, new_count); |
3966 | 0 | sent->data.max_streams.uni = uni; |
3967 | 0 | quicly_maxsender_record(maxsender, new_count, &sent->data.max_streams.args); |
3968 | |
|
3969 | 0 | if (uni) { |
3970 | 0 | ++conn->super.stats.num_frames_sent.max_streams_uni; |
3971 | 0 | } else { |
3972 | 0 | ++conn->super.stats.num_frames_sent.max_streams_bidi; |
3973 | 0 | } |
3974 | 0 | QUICLY_PROBE(MAX_STREAMS_SEND, conn, conn->stash.now, new_count, uni); |
3975 | 0 | QUICLY_LOG_CONN(max_streams_send, conn, { |
3976 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_count); |
3977 | 0 | PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); |
3978 | 0 | }); |
3979 | | |
3980 | 0 | return 0; |
3981 | 0 | } |
3982 | | |
3983 | | static int send_streams_blocked(quicly_conn_t *conn, int uni, quicly_send_context_t *s) |
3984 | 0 | { |
3985 | 0 | quicly_linklist_t *blocked_list = uni ? &conn->egress.pending_streams.blocked.uni : &conn->egress.pending_streams.blocked.bidi; |
3986 | 0 | int ret; |
3987 | |
|
3988 | 0 | if (!quicly_linklist_is_linked(blocked_list)) |
3989 | 0 | return 0; |
3990 | | |
3991 | 0 | struct st_quicly_max_streams_t *max_streams = uni ? &conn->egress.max_streams.uni : &conn->egress.max_streams.bidi; |
3992 | 0 | quicly_stream_t *oldest_blocked_stream = |
3993 | 0 | (void *)((char *)blocked_list->next - offsetof(quicly_stream_t, _send_aux.pending_link.control)); |
3994 | 0 | assert(max_streams->count == oldest_blocked_stream->stream_id / 4); |
3995 | | |
3996 | 0 | if (!quicly_maxsender_should_send_blocked(&max_streams->blocked_sender, max_streams->count)) |
3997 | 0 | return 0; |
3998 | | |
3999 | 0 | quicly_sent_t *sent; |
4000 | 0 | if ((ret = allocate_ack_eliciting_frame(conn, s, QUICLY_STREAMS_BLOCKED_FRAME_CAPACITY, &sent, on_ack_streams_blocked)) != 0) |
4001 | 0 | return ret; |
4002 | 0 | s->dst = quicly_encode_streams_blocked_frame(s->dst, uni, max_streams->count); |
4003 | 0 | sent->data.streams_blocked.uni = uni; |
4004 | 0 | quicly_maxsender_record(&max_streams->blocked_sender, max_streams->count, &sent->data.streams_blocked.args); |
4005 | |
|
4006 | 0 | ++conn->super.stats.num_frames_sent.streams_blocked; |
4007 | 0 | QUICLY_PROBE(STREAMS_BLOCKED_SEND, conn, conn->stash.now, max_streams->count, uni); |
4008 | 0 | QUICLY_LOG_CONN(streams_blocked_send, conn, { |
4009 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(maximum, max_streams->count); |
4010 | 0 | PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); |
4011 | 0 | }); |
4012 | | |
4013 | 0 | return 0; |
4014 | 0 | } |
4015 | | |
4016 | | static void open_blocked_streams(quicly_conn_t *conn, int uni) |
4017 | 0 | { |
4018 | 0 | uint64_t count; |
4019 | 0 | quicly_linklist_t *anchor; |
4020 | |
|
4021 | 0 | if (uni) { |
4022 | 0 | count = conn->egress.max_streams.uni.count; |
4023 | 0 | anchor = &conn->egress.pending_streams.blocked.uni; |
4024 | 0 | } else { |
4025 | 0 | count = conn->egress.max_streams.bidi.count; |
4026 | 0 | anchor = &conn->egress.pending_streams.blocked.bidi; |
4027 | 0 | } |
4028 | |
|
4029 | 0 | while (quicly_linklist_is_linked(anchor)) { |
4030 | 0 | quicly_stream_t *stream = (void *)((char *)anchor->next - offsetof(quicly_stream_t, _send_aux.pending_link.control)); |
4031 | 0 | if (stream->stream_id / 4 >= count) |
4032 | 0 | break; |
4033 | 0 | assert(stream->streams_blocked); |
4034 | 0 | quicly_linklist_unlink(&stream->_send_aux.pending_link.control); |
4035 | 0 | stream->streams_blocked = 0; |
4036 | 0 | stream->_send_aux.max_stream_data = quicly_stream_is_unidirectional(stream->stream_id) |
4037 | 0 | ? conn->super.remote.transport_params.max_stream_data.uni |
4038 | 0 | : conn->super.remote.transport_params.max_stream_data.bidi_remote; |
4039 | | /* TODO retain separate flags for stream states so that we do not always need to sched for both control and data */ |
4040 | 0 | sched_stream_control(stream); |
4041 | 0 | resched_stream_data(stream); |
4042 | 0 | } |
4043 | 0 | } |
4044 | | |
4045 | | static int send_handshake_done(quicly_conn_t *conn, quicly_send_context_t *s) |
4046 | 0 | { |
4047 | 0 | quicly_sent_t *sent; |
4048 | 0 | int ret; |
4049 | |
|
4050 | 0 | if ((ret = allocate_ack_eliciting_frame(conn, s, 1, &sent, on_ack_handshake_done)) != 0) |
4051 | 0 | goto Exit; |
4052 | 0 | *s->dst++ = QUICLY_FRAME_TYPE_HANDSHAKE_DONE; |
4053 | 0 | conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT; |
4054 | 0 | ++conn->super.stats.num_frames_sent.handshake_done; |
4055 | 0 | QUICLY_PROBE(HANDSHAKE_DONE_SEND, conn, conn->stash.now); |
4056 | 0 | QUICLY_LOG_CONN(handshake_done_send, conn, {}); |
4057 | | |
4058 | 0 | ret = 0; |
4059 | 0 | Exit: |
4060 | 0 | return ret; |
4061 | 0 | } |
4062 | | |
4063 | | static int send_data_blocked(quicly_conn_t *conn, quicly_send_context_t *s) |
4064 | 0 | { |
4065 | 0 | quicly_sent_t *sent; |
4066 | 0 | int ret; |
4067 | |
|
4068 | 0 | uint64_t offset = conn->egress.max_data.permitted; |
4069 | 0 | if ((ret = allocate_ack_eliciting_frame(conn, s, QUICLY_DATA_BLOCKED_FRAME_CAPACITY, &sent, on_ack_data_blocked)) != 0) |
4070 | 0 | goto Exit; |
4071 | 0 | sent->data.data_blocked.offset = offset; |
4072 | 0 | s->dst = quicly_encode_data_blocked_frame(s->dst, offset); |
4073 | 0 | conn->egress.data_blocked = QUICLY_SENDER_STATE_UNACKED; |
4074 | |
|
4075 | 0 | ++conn->super.stats.num_frames_sent.data_blocked; |
4076 | 0 | QUICLY_PROBE(DATA_BLOCKED_SEND, conn, conn->stash.now, offset); |
4077 | 0 | QUICLY_LOG_CONN(data_blocked_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(off, offset); }); |
4078 | | |
4079 | 0 | ret = 0; |
4080 | 0 | Exit: |
4081 | 0 | return ret; |
4082 | 0 | } |
4083 | | |
4084 | | static int send_resumption_token(quicly_conn_t *conn, quicly_send_context_t *s) |
4085 | 0 | { |
4086 | 0 | quicly_address_token_plaintext_t token; |
4087 | 0 | ptls_buffer_t tokenbuf; |
4088 | 0 | uint8_t tokenbuf_small[128]; |
4089 | 0 | quicly_sent_t *sent; |
4090 | 0 | int ret; |
4091 | |
|
4092 | 0 | ptls_buffer_init(&tokenbuf, tokenbuf_small, sizeof(tokenbuf_small)); |
4093 | | |
4094 | | /* build token */ |
4095 | 0 | token = |
4096 | 0 | (quicly_address_token_plaintext_t){QUICLY_ADDRESS_TOKEN_TYPE_RESUMPTION, conn->super.ctx->now->cb(conn->super.ctx->now)}; |
4097 | 0 | token.remote = conn->super.remote.address; |
4098 | | /* TODO fill token.resumption */ |
4099 | | |
4100 | | /* encrypt */ |
4101 | 0 | if ((ret = conn->super.ctx->generate_resumption_token->cb(conn->super.ctx->generate_resumption_token, conn, &tokenbuf, |
4102 | 0 | &token)) != 0) |
4103 | 0 | goto Exit; |
4104 | 0 | assert(tokenbuf.off < QUICLY_MIN_CLIENT_INITIAL_SIZE / 2 && "this is a ballpark figure, but tokens ought to be small"); |
4105 | | |
4106 | | /* emit frame */ |
4107 | 0 | if ((ret = allocate_ack_eliciting_frame(conn, s, quicly_new_token_frame_capacity(ptls_iovec_init(tokenbuf.base, tokenbuf.off)), |
4108 | 0 | &sent, on_ack_new_token)) != 0) |
4109 | 0 | goto Exit; |
4110 | 0 | ++conn->egress.new_token.num_inflight; |
4111 | 0 | sent->data.new_token.is_inflight = 1; |
4112 | 0 | sent->data.new_token.generation = conn->egress.new_token.generation; |
4113 | 0 | s->dst = quicly_encode_new_token_frame(s->dst, ptls_iovec_init(tokenbuf.base, tokenbuf.off)); |
4114 | 0 | conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_NEW_TOKEN_BIT; |
4115 | |
|
4116 | 0 | ++conn->super.stats.num_frames_sent.new_token; |
4117 | 0 | QUICLY_PROBE(NEW_TOKEN_SEND, conn, conn->stash.now, tokenbuf.base, tokenbuf.off, sent->data.new_token.generation); |
4118 | 0 | QUICLY_LOG_CONN(new_token_send, conn, { |
4119 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(token, tokenbuf.base, tokenbuf.off); |
4120 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(generation, sent->data.new_token.generation); |
4121 | 0 | }); |
4122 | 0 | ret = 0; |
4123 | 0 | Exit: |
4124 | 0 | ptls_buffer_dispose(&tokenbuf); |
4125 | 0 | return ret; |
4126 | 0 | } |
4127 | | |
4128 | | size_t quicly_send_version_negotiation(quicly_context_t *ctx, ptls_iovec_t dest_cid, ptls_iovec_t src_cid, const uint32_t *versions, |
4129 | | void *payload) |
4130 | 0 | { |
4131 | 0 | uint8_t *dst = payload; |
4132 | | |
4133 | | /* type_flags */ |
4134 | 0 | ctx->tls->random_bytes(dst, 1); |
4135 | 0 | *dst |= QUICLY_LONG_HEADER_BIT; |
4136 | 0 | ++dst; |
4137 | | /* version */ |
4138 | 0 | dst = quicly_encode32(dst, 0); |
4139 | | /* connection-id */ |
4140 | 0 | *dst++ = dest_cid.len; |
4141 | 0 | if (dest_cid.len != 0) { |
4142 | 0 | memcpy(dst, dest_cid.base, dest_cid.len); |
4143 | 0 | dst += dest_cid.len; |
4144 | 0 | } |
4145 | 0 | *dst++ = src_cid.len; |
4146 | 0 | if (src_cid.len != 0) { |
4147 | 0 | memcpy(dst, src_cid.base, src_cid.len); |
4148 | 0 | dst += src_cid.len; |
4149 | 0 | } |
4150 | | /* supported_versions */ |
4151 | 0 | for (const uint32_t *v = versions; *v != 0; ++v) |
4152 | 0 | dst = quicly_encode32(dst, *v); |
4153 | | /* add a greasing version. This also covers the case where an empty list is specified by the caller to indicate rejection. */ |
4154 | 0 | uint32_t grease_version = 0; |
4155 | 0 | if (src_cid.len >= sizeof(grease_version)) |
4156 | 0 | memcpy(&grease_version, src_cid.base, sizeof(grease_version)); |
4157 | 0 | grease_version = (grease_version & 0xf0f0f0f0) | 0x0a0a0a0a; |
4158 | 0 | dst = quicly_encode32(dst, grease_version); |
4159 | |
|
4160 | 0 | return dst - (uint8_t *)payload; |
4161 | 0 | } |
4162 | | |
4163 | | int quicly_retry_calc_cidpair_hash(ptls_hash_algorithm_t *sha256, ptls_iovec_t client_cid, ptls_iovec_t server_cid, uint64_t *value) |
4164 | 0 | { |
4165 | 0 | uint8_t digest[PTLS_SHA256_DIGEST_SIZE], buf[(QUICLY_MAX_CID_LEN_V1 + 1) * 2], *p = buf; |
4166 | 0 | int ret; |
4167 | |
|
4168 | 0 | *p++ = (uint8_t)client_cid.len; |
4169 | 0 | memcpy(p, client_cid.base, client_cid.len); |
4170 | 0 | p += client_cid.len; |
4171 | 0 | *p++ = (uint8_t)server_cid.len; |
4172 | 0 | memcpy(p, server_cid.base, server_cid.len); |
4173 | 0 | p += server_cid.len; |
4174 | |
|
4175 | 0 | if ((ret = ptls_calc_hash(sha256, digest, buf, p - buf)) != 0) |
4176 | 0 | return ret; |
4177 | 0 | p = digest; |
4178 | 0 | *value = quicly_decode64((void *)&p); |
4179 | |
|
4180 | 0 | return 0; |
4181 | 0 | } |
4182 | | |
4183 | | size_t quicly_send_retry(quicly_context_t *ctx, ptls_aead_context_t *token_encrypt_ctx, uint32_t protocol_version, |
4184 | | struct sockaddr *dest_addr, ptls_iovec_t dest_cid, struct sockaddr *src_addr, ptls_iovec_t src_cid, |
4185 | | ptls_iovec_t odcid, ptls_iovec_t token_prefix, ptls_iovec_t appdata, |
4186 | | ptls_aead_context_t **retry_aead_cache, uint8_t *datagram) |
4187 | 0 | { |
4188 | 0 | quicly_address_token_plaintext_t token; |
4189 | 0 | ptls_buffer_t buf; |
4190 | 0 | int ret; |
4191 | |
|
4192 | 0 | assert(!(src_cid.len == odcid.len && memcmp(src_cid.base, odcid.base, src_cid.len) == 0)); |
4193 | | |
4194 | | /* build token as plaintext */ |
4195 | 0 | token = (quicly_address_token_plaintext_t){QUICLY_ADDRESS_TOKEN_TYPE_RETRY, ctx->now->cb(ctx->now)}; |
4196 | 0 | set_address(&token.remote, dest_addr); |
4197 | 0 | set_address(&token.local, src_addr); |
4198 | |
|
4199 | 0 | quicly_set_cid(&token.retry.original_dcid, odcid); |
4200 | 0 | quicly_set_cid(&token.retry.client_cid, dest_cid); |
4201 | 0 | quicly_set_cid(&token.retry.server_cid, src_cid); |
4202 | 0 | if (appdata.len != 0) { |
4203 | 0 | assert(appdata.len <= sizeof(token.appdata.bytes)); |
4204 | 0 | memcpy(token.appdata.bytes, appdata.base, appdata.len); |
4205 | 0 | token.appdata.len = appdata.len; |
4206 | 0 | } |
4207 | | |
4208 | | /* start building the packet */ |
4209 | 0 | ptls_buffer_init(&buf, datagram, QUICLY_MIN_CLIENT_INITIAL_SIZE); |
4210 | | |
4211 | | /* first generate a pseudo packet */ |
4212 | 0 | ptls_buffer_push_block(&buf, 1, { ptls_buffer_pushv(&buf, odcid.base, odcid.len); }); |
4213 | 0 | ctx->tls->random_bytes(buf.base + buf.off, 1); |
4214 | 0 | buf.base[buf.off] = QUICLY_PACKET_TYPE_RETRY | (buf.base[buf.off] & 0x0f); |
4215 | 0 | ++buf.off; |
4216 | 0 | ptls_buffer_push32(&buf, protocol_version); |
4217 | 0 | ptls_buffer_push_block(&buf, 1, { ptls_buffer_pushv(&buf, dest_cid.base, dest_cid.len); }); |
4218 | 0 | ptls_buffer_push_block(&buf, 1, { ptls_buffer_pushv(&buf, src_cid.base, src_cid.len); }); |
4219 | 0 | if (token_prefix.len != 0) { |
4220 | 0 | assert(token_prefix.len <= buf.capacity - buf.off); |
4221 | 0 | memcpy(buf.base + buf.off, token_prefix.base, token_prefix.len); |
4222 | 0 | buf.off += token_prefix.len; |
4223 | 0 | } |
4224 | 0 | if ((ret = quicly_encrypt_address_token(ctx->tls->random_bytes, token_encrypt_ctx, &buf, buf.off - token_prefix.len, &token)) != |
4225 | 0 | 0) |
4226 | 0 | goto Exit; |
4227 | | |
4228 | | /* append AEAD tag */ |
4229 | 0 | ret = ptls_buffer_reserve(&buf, PTLS_AESGCM_TAG_SIZE); |
4230 | 0 | assert(ret == 0); |
4231 | 0 | assert(!buf.is_allocated && "retry packet is too large"); |
4232 | 0 | { |
4233 | 0 | ptls_aead_context_t *aead = |
4234 | 0 | retry_aead_cache != NULL && *retry_aead_cache != NULL ? *retry_aead_cache : create_retry_aead(ctx, protocol_version, 1); |
4235 | 0 | ptls_aead_encrypt(aead, buf.base + buf.off, "", 0, 0, buf.base, buf.off); |
4236 | 0 | if (retry_aead_cache != NULL) { |
4237 | 0 | *retry_aead_cache = aead; |
4238 | 0 | } else { |
4239 | 0 | ptls_aead_free(aead); |
4240 | 0 | } |
4241 | 0 | } |
4242 | 0 | buf.off += PTLS_AESGCM_TAG_SIZE; |
4243 | | |
4244 | | /* convert the image to a Retry packet, by stripping the ODCID field */ |
4245 | 0 | memmove(buf.base, buf.base + odcid.len + 1, buf.off - (odcid.len + 1)); |
4246 | 0 | buf.off -= odcid.len + 1; |
4247 | |
|
4248 | 0 | ret = 0; |
4249 | |
|
4250 | 0 | Exit: |
4251 | 0 | return ret == 0 ? buf.off : SIZE_MAX; |
4252 | 0 | } |
4253 | | |
4254 | | static struct st_quicly_pn_space_t *setup_send_space(quicly_conn_t *conn, size_t epoch, quicly_send_context_t *s) |
4255 | 0 | { |
4256 | 0 | struct st_quicly_pn_space_t *space = NULL; |
4257 | |
|
4258 | 0 | switch (epoch) { |
4259 | 0 | case QUICLY_EPOCH_INITIAL: |
4260 | 0 | if (conn->initial == NULL || (s->current.cipher = &conn->initial->cipher.egress)->aead == NULL) |
4261 | 0 | return NULL; |
4262 | 0 | s->current.first_byte = QUICLY_PACKET_TYPE_INITIAL; |
4263 | 0 | space = &conn->initial->super; |
4264 | 0 | break; |
4265 | 0 | case QUICLY_EPOCH_HANDSHAKE: |
4266 | 0 | if (conn->handshake == NULL || (s->current.cipher = &conn->handshake->cipher.egress)->aead == NULL) |
4267 | 0 | return NULL; |
4268 | 0 | s->current.first_byte = QUICLY_PACKET_TYPE_HANDSHAKE; |
4269 | 0 | space = &conn->handshake->super; |
4270 | 0 | break; |
4271 | 0 | case QUICLY_EPOCH_0RTT: |
4272 | 0 | case QUICLY_EPOCH_1RTT: |
4273 | 0 | if (conn->application == NULL || conn->application->cipher.egress.key.header_protection == NULL) |
4274 | 0 | return NULL; |
4275 | 0 | if ((epoch == QUICLY_EPOCH_0RTT) == conn->application->one_rtt_writable) |
4276 | 0 | return NULL; |
4277 | 0 | s->current.cipher = &conn->application->cipher.egress.key; |
4278 | 0 | s->current.first_byte = epoch == QUICLY_EPOCH_0RTT ? QUICLY_PACKET_TYPE_0RTT : QUICLY_QUIC_BIT; |
4279 | 0 | space = &conn->application->super; |
4280 | 0 | break; |
4281 | 0 | default: |
4282 | 0 | assert(!"logic flaw"); |
4283 | 0 | break; |
4284 | 0 | } |
4285 | | |
4286 | 0 | return space; |
4287 | 0 | } |
4288 | | |
4289 | | static int send_handshake_flow(quicly_conn_t *conn, size_t epoch, quicly_send_context_t *s, int ack_only, int send_probe) |
4290 | 0 | { |
4291 | 0 | struct st_quicly_pn_space_t *space; |
4292 | 0 | int ret = 0; |
4293 | | |
4294 | | /* setup send epoch, or return if it's impossible to send in this epoch */ |
4295 | 0 | if ((space = setup_send_space(conn, epoch, s)) == NULL) |
4296 | 0 | return 0; |
4297 | | |
4298 | | /* send ACK */ |
4299 | 0 | if (space != NULL && (space->unacked_count != 0 || send_probe)) |
4300 | 0 | if ((ret = send_ack(conn, space, s)) != 0) |
4301 | 0 | goto Exit; |
4302 | | |
4303 | 0 | if (!ack_only) { |
4304 | | /* send data */ |
4305 | 0 | while ((conn->egress.pending_flows & (uint8_t)(1 << epoch)) != 0) { |
4306 | 0 | quicly_stream_t *stream = quicly_get_stream(conn, -(quicly_stream_id_t)(1 + epoch)); |
4307 | 0 | assert(stream != NULL); |
4308 | 0 | if ((ret = quicly_send_stream(stream, s)) != 0) |
4309 | 0 | goto Exit; |
4310 | 0 | resched_stream_data(stream); |
4311 | 0 | send_probe = 0; |
4312 | 0 | } |
4313 | | |
4314 | | /* send probe if requested */ |
4315 | 0 | if (send_probe) { |
4316 | 0 | if ((ret = do_allocate_frame(conn, s, 1, ALLOCATE_FRAME_TYPE_ACK_ELICITING)) != 0) |
4317 | 0 | goto Exit; |
4318 | 0 | *s->dst++ = QUICLY_FRAME_TYPE_PING; |
4319 | 0 | conn->egress.last_retransmittable_sent_at = conn->stash.now; |
4320 | 0 | ++conn->super.stats.num_frames_sent.ping; |
4321 | 0 | QUICLY_PROBE(PING_SEND, conn, conn->stash.now); |
4322 | 0 | QUICLY_LOG_CONN(ping_send, conn, {}); |
4323 | 0 | } |
4324 | 0 | } |
4325 | | |
4326 | 0 | Exit: |
4327 | 0 | return ret; |
4328 | 0 | } |
4329 | | |
4330 | | static int send_connection_close(quicly_conn_t *conn, size_t epoch, quicly_send_context_t *s) |
4331 | 0 | { |
4332 | 0 | uint64_t error_code, offending_frame_type; |
4333 | 0 | const char *reason_phrase; |
4334 | 0 | int ret; |
4335 | | |
4336 | | /* setup send epoch, or return if it's impossible to send in this epoch */ |
4337 | 0 | if (setup_send_space(conn, epoch, s) == NULL) |
4338 | 0 | return 0; |
4339 | | |
4340 | | /* determine the payload, masking the application error when sending the frame using an unauthenticated epoch */ |
4341 | 0 | error_code = conn->egress.connection_close.error_code; |
4342 | 0 | offending_frame_type = conn->egress.connection_close.frame_type; |
4343 | 0 | reason_phrase = conn->egress.connection_close.reason_phrase; |
4344 | 0 | if (offending_frame_type == UINT64_MAX) { |
4345 | 0 | switch (get_epoch(s->current.first_byte)) { |
4346 | 0 | case QUICLY_EPOCH_INITIAL: |
4347 | 0 | case QUICLY_EPOCH_HANDSHAKE: |
4348 | 0 | error_code = QUICLY_TRANSPORT_ERROR_APPLICATION; |
4349 | 0 | offending_frame_type = QUICLY_FRAME_TYPE_PADDING; |
4350 | 0 | reason_phrase = ""; |
4351 | 0 | break; |
4352 | 0 | } |
4353 | 0 | } |
4354 | | |
4355 | | /* write frame */ |
4356 | 0 | if ((ret = do_allocate_frame(conn, s, quicly_close_frame_capacity(error_code, offending_frame_type, reason_phrase), |
4357 | 0 | ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING)) != 0) |
4358 | 0 | return ret; |
4359 | 0 | s->dst = quicly_encode_close_frame(s->dst, error_code, offending_frame_type, reason_phrase); |
4360 | | |
4361 | | /* update counter, probe */ |
4362 | 0 | if (offending_frame_type != UINT64_MAX) { |
4363 | 0 | ++conn->super.stats.num_frames_sent.transport_close; |
4364 | 0 | QUICLY_PROBE(TRANSPORT_CLOSE_SEND, conn, conn->stash.now, error_code, offending_frame_type, reason_phrase); |
4365 | 0 | QUICLY_LOG_CONN(transport_close_send, conn, { |
4366 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(error_code, error_code); |
4367 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(frame_type, offending_frame_type); |
4368 | 0 | PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); |
4369 | 0 | }); |
4370 | 0 | } else { |
4371 | 0 | ++conn->super.stats.num_frames_sent.application_close; |
4372 | 0 | QUICLY_PROBE(APPLICATION_CLOSE_SEND, conn, conn->stash.now, error_code, reason_phrase); |
4373 | 0 | QUICLY_LOG_CONN(application_close_send, conn, { |
4374 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(error_code, error_code); |
4375 | 0 | PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, reason_phrase, strlen(reason_phrase)); |
4376 | 0 | }); |
4377 | 0 | } |
4378 | | |
4379 | 0 | return 0; |
4380 | 0 | } |
4381 | | |
4382 | | static int send_new_connection_id(quicly_conn_t *conn, quicly_send_context_t *s, struct st_quicly_local_cid_t *new_cid) |
4383 | 0 | { |
4384 | 0 | int ret; |
4385 | 0 | quicly_sent_t *sent; |
4386 | 0 | uint64_t retire_prior_to = 0; /* TODO */ |
4387 | |
|
4388 | 0 | ret = allocate_ack_eliciting_frame( |
4389 | 0 | conn, s, quicly_new_connection_id_frame_capacity(new_cid->sequence, retire_prior_to, new_cid->cid.len), &sent, |
4390 | 0 | on_ack_new_connection_id); |
4391 | 0 | if (ret != 0) |
4392 | 0 | return ret; |
4393 | 0 | sent->data.new_connection_id.sequence = new_cid->sequence; |
4394 | |
|
4395 | 0 | s->dst = quicly_encode_new_connection_id_frame(s->dst, new_cid->sequence, retire_prior_to, new_cid->cid.cid, new_cid->cid.len, |
4396 | 0 | new_cid->stateless_reset_token); |
4397 | |
|
4398 | 0 | ++conn->super.stats.num_frames_sent.new_connection_id; |
4399 | 0 | QUICLY_PROBE(NEW_CONNECTION_ID_SEND, conn, conn->stash.now, new_cid->sequence, retire_prior_to, |
4400 | 0 | QUICLY_PROBE_HEXDUMP(new_cid->cid.cid, new_cid->cid.len), |
4401 | 0 | QUICLY_PROBE_HEXDUMP(new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); |
4402 | 0 | QUICLY_LOG_CONN(new_connection_id_send, conn, { |
4403 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(sequence, new_cid->sequence); |
4404 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(retire_prior_to, retire_prior_to); |
4405 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(cid, new_cid->cid.cid, new_cid->cid.len); |
4406 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(stateless_reset_token, new_cid->stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN); |
4407 | 0 | }); |
4408 | | |
4409 | 0 | return 0; |
4410 | 0 | } |
4411 | | |
4412 | | static int send_retire_connection_id(quicly_conn_t *conn, quicly_send_context_t *s, uint64_t sequence) |
4413 | 0 | { |
4414 | 0 | int ret; |
4415 | 0 | quicly_sent_t *sent; |
4416 | |
|
4417 | 0 | ret = allocate_ack_eliciting_frame(conn, s, quicly_retire_connection_id_frame_capacity(sequence), &sent, |
4418 | 0 | on_ack_retire_connection_id); |
4419 | 0 | if (ret != 0) |
4420 | 0 | return ret; |
4421 | 0 | sent->data.retire_connection_id.sequence = sequence; |
4422 | |
|
4423 | 0 | s->dst = quicly_encode_retire_connection_id_frame(s->dst, sequence); |
4424 | |
|
4425 | 0 | ++conn->super.stats.num_frames_sent.retire_connection_id; |
4426 | 0 | QUICLY_PROBE(RETIRE_CONNECTION_ID_SEND, conn, conn->stash.now, sequence); |
4427 | 0 | QUICLY_LOG_CONN(retire_connection_id_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(sequence, sequence); }); |
4428 | | |
4429 | 0 | return 0; |
4430 | 0 | } |
4431 | | |
4432 | | static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, int is_enc, size_t epoch, const void *secret) |
4433 | 0 | { |
4434 | 0 | quicly_conn_t *conn = *ptls_get_data_ptr(tls); |
4435 | 0 | ptls_context_t *tlsctx = ptls_get_context(tls); |
4436 | 0 | ptls_cipher_suite_t *cipher = ptls_get_cipher(tls); |
4437 | 0 | ptls_cipher_context_t **hp_slot; |
4438 | 0 | ptls_aead_context_t **aead_slot; |
4439 | 0 | int ret; |
4440 | 0 | static const char *log_labels[2][4] = { |
4441 | 0 | {NULL, "CLIENT_EARLY_TRAFFIC_SECRET", "CLIENT_HANDSHAKE_TRAFFIC_SECRET", "CLIENT_TRAFFIC_SECRET_0"}, |
4442 | 0 | {NULL, NULL, "SERVER_HANDSHAKE_TRAFFIC_SECRET", "SERVER_TRAFFIC_SECRET_0"}}; |
4443 | 0 | const char *log_label = log_labels[ptls_is_server(tls) == is_enc][epoch]; |
4444 | |
|
4445 | 0 | QUICLY_PROBE(CRYPTO_UPDATE_SECRET, conn, conn->stash.now, is_enc, epoch, log_label, |
4446 | 0 | QUICLY_PROBE_HEXDUMP(secret, cipher->hash->digest_size)); |
4447 | 0 | QUICLY_LOG_CONN(crypto_update_secret, conn, { |
4448 | 0 | PTLS_LOG_ELEMENT_BOOL(is_enc, is_enc); |
4449 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(epoch, epoch); |
4450 | 0 | PTLS_LOG_ELEMENT_SAFESTR(label, log_label); |
4451 | 0 | PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(secret, secret, cipher->hash->digest_size); |
4452 | 0 | }); |
4453 | | |
4454 | 0 | if (tlsctx->log_event != NULL) { |
4455 | 0 | char hexbuf[PTLS_MAX_DIGEST_SIZE * 2 + 1]; |
4456 | 0 | ptls_hexdump(hexbuf, secret, cipher->hash->digest_size); |
4457 | 0 | tlsctx->log_event->cb(tlsctx->log_event, tls, log_label, "%s", hexbuf); |
4458 | 0 | } |
4459 | |
|
4460 | 0 | #define SELECT_CIPHER_CONTEXT(p) \ |
4461 | 0 | do { \ |
4462 | 0 | hp_slot = &(p)->header_protection; \ |
4463 | 0 | aead_slot = &(p)->aead; \ |
4464 | 0 | } while (0) |
4465 | |
|
4466 | 0 | switch (epoch) { |
4467 | 0 | case QUICLY_EPOCH_0RTT: |
4468 | 0 | assert(is_enc == quicly_is_client(conn)); |
4469 | 0 | if (conn->application == NULL && (ret = setup_application_space(conn)) != 0) |
4470 | 0 | return ret; |
4471 | 0 | if (is_enc) { |
4472 | 0 | SELECT_CIPHER_CONTEXT(&conn->application->cipher.egress.key); |
4473 | 0 | } else { |
4474 | 0 | hp_slot = &conn->application->cipher.ingress.header_protection.zero_rtt; |
4475 | 0 | aead_slot = &conn->application->cipher.ingress.aead[1]; |
4476 | 0 | } |
4477 | 0 | break; |
4478 | 0 | case QUICLY_EPOCH_HANDSHAKE: |
4479 | 0 | if (conn->handshake == NULL && (ret = setup_handshake_space_and_flow(conn, QUICLY_EPOCH_HANDSHAKE)) != 0) |
4480 | 0 | return ret; |
4481 | 0 | SELECT_CIPHER_CONTEXT(is_enc ? &conn->handshake->cipher.egress : &conn->handshake->cipher.ingress); |
4482 | 0 | break; |
4483 | 0 | case QUICLY_EPOCH_1RTT: { |
4484 | 0 | if (is_enc) |
4485 | 0 | if ((ret = apply_remote_transport_params(conn)) != 0) |
4486 | 0 | return ret; |
4487 | 0 | if (conn->application == NULL && (ret = setup_application_space(conn)) != 0) |
4488 | 0 | return ret; |
4489 | 0 | uint8_t *secret_store; |
4490 | 0 | if (is_enc) { |
4491 | 0 | if (conn->application->cipher.egress.key.aead != NULL) |
4492 | 0 | dispose_cipher(&conn->application->cipher.egress.key); |
4493 | 0 | SELECT_CIPHER_CONTEXT(&conn->application->cipher.egress.key); |
4494 | 0 | secret_store = conn->application->cipher.egress.secret; |
4495 | 0 | } else { |
4496 | 0 | hp_slot = &conn->application->cipher.ingress.header_protection.one_rtt; |
4497 | 0 | aead_slot = &conn->application->cipher.ingress.aead[0]; |
4498 | 0 | secret_store = conn->application->cipher.ingress.secret; |
4499 | 0 | } |
4500 | 0 | memcpy(secret_store, secret, cipher->hash->digest_size); |
4501 | 0 | } break; |
4502 | 0 | default: |
4503 | 0 | assert(!"logic flaw"); |
4504 | 0 | break; |
4505 | 0 | } |
4506 | | |
4507 | 0 | #undef SELECT_CIPHER_CONTEXT |
4508 | | |
4509 | 0 | if ((ret = setup_cipher(conn, epoch, is_enc, hp_slot, aead_slot, cipher->aead, cipher->hash, secret)) != 0) |
4510 | 0 | return ret; |
4511 | | |
4512 | 0 | if (epoch == QUICLY_EPOCH_1RTT && is_enc) { |
4513 | | /* update states now that we have 1-RTT write key */ |
4514 | 0 | conn->application->one_rtt_writable = 1; |
4515 | 0 | open_blocked_streams(conn, 1); |
4516 | 0 | open_blocked_streams(conn, 0); |
4517 | | /* send the first resumption token using the 0.5 RTT window */ |
4518 | 0 | if (!quicly_is_client(conn) && conn->super.ctx->generate_resumption_token != NULL) { |
4519 | 0 | ret = quicly_send_resumption_token(conn); |
4520 | 0 | assert(ret == 0); |
4521 | 0 | } |
4522 | | |
4523 | | /* schedule NEW_CONNECTION_IDs */ |
4524 | 0 | size_t size = local_cid_size(conn); |
4525 | 0 | if (quicly_local_cid_set_size(&conn->super.local.cid_set, size)) |
4526 | 0 | conn->egress.pending_flows |= QUICLY_PENDING_FLOW_CID_FRAME_BIT; |
4527 | 0 | } |
4528 | | |
4529 | 0 | return 0; |
4530 | 0 | } |
4531 | | |
4532 | | static int do_send(quicly_conn_t *conn, quicly_send_context_t *s) |
4533 | 0 | { |
4534 | 0 | int restrict_sending = 0, ack_only = 0, ret; |
4535 | 0 | size_t min_packets_to_send = 0; |
4536 | | |
4537 | | /* handle timeouts */ |
4538 | 0 | if (conn->idle_timeout.at <= conn->stash.now) { |
4539 | 0 | QUICLY_PROBE(IDLE_TIMEOUT, conn, conn->stash.now); |
4540 | 0 | QUICLY_LOG_CONN(idle_timeout, conn, {}); |
4541 | 0 | goto CloseNow; |
4542 | 0 | } |
4543 | | /* handle handshake timeouts */ |
4544 | 0 | if ((conn->initial != NULL || conn->handshake != NULL) && |
4545 | 0 | conn->created_at + (uint64_t)conn->super.ctx->handshake_timeout_rtt_multiplier * conn->egress.loss.rtt.smoothed <= |
4546 | 0 | conn->stash.now) { |
4547 | 0 | QUICLY_PROBE(HANDSHAKE_TIMEOUT, conn, conn->stash.now, conn->stash.now - conn->created_at, conn->egress.loss.rtt.smoothed); |
4548 | 0 | QUICLY_LOG_CONN(handshake_timeout, conn, { |
4549 | 0 | PTLS_LOG_ELEMENT_SIGNED(elapsed, conn->stash.now - conn->created_at); |
4550 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(rtt_smoothed, conn->egress.loss.rtt.smoothed); |
4551 | 0 | }); |
4552 | 0 | conn->super.stats.num_handshake_timeouts++; |
4553 | 0 | goto CloseNow; |
4554 | 0 | } |
4555 | 0 | if (conn->super.stats.num_packets.initial_handshake_sent > conn->super.ctx->max_initial_handshake_packets) { |
4556 | 0 | QUICLY_PROBE(INITIAL_HANDSHAKE_PACKET_EXCEED, conn, conn->stash.now, conn->super.stats.num_packets.initial_handshake_sent); |
4557 | 0 | QUICLY_LOG_CONN(initial_handshake_packet_exceed, conn, |
4558 | 0 | { PTLS_LOG_ELEMENT_UNSIGNED(num_packets, conn->super.stats.num_packets.initial_handshake_sent); }); |
4559 | 0 | conn->super.stats.num_initial_handshake_exceeded++; |
4560 | 0 | goto CloseNow; |
4561 | 0 | } |
4562 | 0 | if (conn->egress.loss.alarm_at <= conn->stash.now) { |
4563 | 0 | if ((ret = quicly_loss_on_alarm(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, |
4564 | 0 | conn->initial == NULL && conn->handshake == NULL, &min_packets_to_send, &restrict_sending, |
4565 | 0 | on_loss_detected)) != 0) |
4566 | 0 | goto Exit; |
4567 | 0 | assert(min_packets_to_send > 0); |
4568 | 0 | assert(min_packets_to_send <= s->max_datagrams); |
4569 | | |
4570 | 0 | if (restrict_sending) { |
4571 | | /* PTO: when handshake is in progress, send from the very first unacknowledged byte so as to maximize the chance of |
4572 | | * making progress. When handshake is complete, transmit new data if any, else retransmit the oldest unacknowledged data |
4573 | | * that is considered inflight. */ |
4574 | 0 | QUICLY_PROBE(PTO, conn, conn->stash.now, conn->egress.loss.sentmap.bytes_in_flight, conn->egress.cc.cwnd, |
4575 | 0 | conn->egress.loss.pto_count); |
4576 | 0 | QUICLY_LOG_CONN(pto, conn, { |
4577 | 0 | PTLS_LOG_ELEMENT_SIGNED(inflight, conn->egress.loss.sentmap.bytes_in_flight); |
4578 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); |
4579 | 0 | PTLS_LOG_ELEMENT_SIGNED(pto_count, conn->egress.loss.pto_count); |
4580 | 0 | }); |
4581 | 0 | ++conn->super.stats.num_ptos; |
4582 | 0 | size_t bytes_to_mark = min_packets_to_send * conn->egress.max_udp_payload_size; |
4583 | 0 | if (conn->initial != NULL && (ret = mark_frames_on_pto(conn, QUICLY_EPOCH_INITIAL, &bytes_to_mark)) != 0) |
4584 | 0 | goto Exit; |
4585 | 0 | if (bytes_to_mark != 0 && conn->handshake != NULL && |
4586 | 0 | (ret = mark_frames_on_pto(conn, QUICLY_EPOCH_HANDSHAKE, &bytes_to_mark)) != 0) |
4587 | 0 | goto Exit; |
4588 | | /* Mark already sent 1-RTT data for PTO only if there's no new data, i.e., when scheduler_can_send() return false. */ |
4589 | 0 | if (bytes_to_mark != 0 && !scheduler_can_send(conn) && |
4590 | 0 | (ret = mark_frames_on_pto(conn, QUICLY_EPOCH_1RTT, &bytes_to_mark)) != 0) |
4591 | 0 | goto Exit; |
4592 | 0 | } |
4593 | 0 | } |
4594 | | |
4595 | 0 | s->send_window = calc_send_window(conn, min_packets_to_send * conn->egress.max_udp_payload_size, |
4596 | 0 | calc_amplification_limit_allowance(conn), restrict_sending); |
4597 | 0 | if (s->send_window == 0) |
4598 | 0 | ack_only = 1; |
4599 | | |
4600 | | /* send handshake flows; when PTO fires... |
4601 | | * * quicly running as a client sends either a Handshake probe (or data) if the handshake keys are available, or else an |
4602 | | * Initial probe (or data). |
4603 | | * * quicly running as a server sends both Initial and Handshake probes (or data) if the corresponding keys are available. */ |
4604 | 0 | if ((ret = send_handshake_flow(conn, QUICLY_EPOCH_INITIAL, s, ack_only, |
4605 | 0 | min_packets_to_send != 0 && (!quicly_is_client(conn) || conn->handshake == NULL))) != 0) |
4606 | 0 | goto Exit; |
4607 | 0 | if ((ret = send_handshake_flow(conn, QUICLY_EPOCH_HANDSHAKE, s, ack_only, min_packets_to_send != 0)) != 0) |
4608 | 0 | goto Exit; |
4609 | | |
4610 | | /* setup 0-RTT or 1-RTT send context (as the availability of the two epochs are mutually exclusive, we can try 1-RTT first as an |
4611 | | * optimization), then send application data if that succeeds */ |
4612 | 0 | if (setup_send_space(conn, QUICLY_EPOCH_1RTT, s) != NULL || setup_send_space(conn, QUICLY_EPOCH_0RTT, s) != NULL) { |
4613 | | /* acks */ |
4614 | 0 | if (conn->application->one_rtt_writable && conn->egress.send_ack_at <= conn->stash.now && |
4615 | 0 | conn->application->super.unacked_count != 0) { |
4616 | 0 | if ((ret = send_ack(conn, &conn->application->super, s)) != 0) |
4617 | 0 | goto Exit; |
4618 | 0 | } |
4619 | | /* DATAGRAM frame. Notes regarding current implementation: |
4620 | | * * Not limited by CC, nor the bytes counted by CC. |
4621 | | * * When given payload is too large and does not fit into a QUIC packet, a packet containing only PADDING frames is sent. |
4622 | | * This is because we do not have a way to retract the generation of a QUIC packet. |
4623 | | * * Does not notify the application that the frame was dropped internally. */ |
4624 | 0 | if (should_send_datagram_frame(conn)) { |
4625 | 0 | for (size_t i = 0; i != conn->egress.datagram_frame_payloads.count; ++i) { |
4626 | 0 | ptls_iovec_t *payload = conn->egress.datagram_frame_payloads.payloads + i; |
4627 | 0 | size_t required_space = quicly_datagram_frame_capacity(*payload); |
4628 | 0 | if ((ret = do_allocate_frame(conn, s, required_space, ALLOCATE_FRAME_TYPE_ACK_ELICITING_NO_CC)) != 0) |
4629 | 0 | goto Exit; |
4630 | 0 | if (s->dst_end - s->dst >= required_space) { |
4631 | 0 | s->dst = quicly_encode_datagram_frame(s->dst, *payload); |
4632 | 0 | QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, payload->base, payload->len); |
4633 | 0 | QUICLY_LOG_CONN(datagram_send, conn, |
4634 | 0 | { PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(payload, payload->base, payload->len); }); |
4635 | 0 | } else { |
4636 | | /* FIXME: At the moment, we add a padding because we do not have a way to reclaim allocated space, and because |
4637 | | * it is forbidden to send an empty QUIC packet. */ |
4638 | 0 | *s->dst++ = QUICLY_FRAME_TYPE_PADDING; |
4639 | 0 | } |
4640 | 0 | } |
4641 | 0 | } |
4642 | 0 | if (!ack_only) { |
4643 | | /* PTO or loss detection timeout, always send PING. This is the easiest thing to do in terms of timer control. */ |
4644 | 0 | if (min_packets_to_send != 0) { |
4645 | 0 | if ((ret = do_allocate_frame(conn, s, 1, ALLOCATE_FRAME_TYPE_ACK_ELICITING)) != 0) |
4646 | 0 | goto Exit; |
4647 | 0 | *s->dst++ = QUICLY_FRAME_TYPE_PING; |
4648 | 0 | ++conn->super.stats.num_frames_sent.ping; |
4649 | 0 | QUICLY_PROBE(PING_SEND, conn, conn->stash.now); |
4650 | 0 | QUICLY_LOG_CONN(ping_send, conn, {}); |
4651 | 0 | } |
4652 | | /* take actions only permitted for short header packets */ |
4653 | 0 | if (conn->application->one_rtt_writable) { |
4654 | | /* send HANDSHAKE_DONE */ |
4655 | 0 | if ((conn->egress.pending_flows & QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT) != 0 && |
4656 | 0 | (ret = send_handshake_done(conn, s)) != 0) |
4657 | 0 | goto Exit; |
4658 | | /* post-handshake messages */ |
4659 | 0 | if ((conn->egress.pending_flows & (uint8_t)(1 << QUICLY_EPOCH_1RTT)) != 0) { |
4660 | 0 | quicly_stream_t *stream = quicly_get_stream(conn, -(1 + QUICLY_EPOCH_1RTT)); |
4661 | 0 | assert(stream != NULL); |
4662 | 0 | if ((ret = quicly_send_stream(stream, s)) != 0) |
4663 | 0 | goto Exit; |
4664 | 0 | resched_stream_data(stream); |
4665 | 0 | } |
4666 | | /* respond to all pending received PATH_CHALLENGE frames */ |
4667 | 0 | if (conn->egress.path_challenge.head != NULL) { |
4668 | 0 | do { |
4669 | 0 | struct st_quicly_pending_path_challenge_t *c = conn->egress.path_challenge.head; |
4670 | 0 | if ((ret = do_allocate_frame(conn, s, QUICLY_PATH_CHALLENGE_FRAME_CAPACITY, |
4671 | 0 | ALLOCATE_FRAME_TYPE_NON_ACK_ELICITING)) != 0) |
4672 | 0 | goto Exit; |
4673 | 0 | s->dst = quicly_encode_path_challenge_frame(s->dst, c->is_response, c->data); |
4674 | 0 | if (c->is_response) { |
4675 | 0 | ++conn->super.stats.num_frames_sent.path_response; |
4676 | 0 | } else { |
4677 | 0 | ++conn->super.stats.num_frames_sent.path_challenge; |
4678 | 0 | } |
4679 | 0 | conn->egress.path_challenge.head = c->next; |
4680 | 0 | free(c); |
4681 | 0 | } while (conn->egress.path_challenge.head != NULL); |
4682 | 0 | conn->egress.path_challenge.tail_ref = &conn->egress.path_challenge.head; |
4683 | 0 | s->target.full_size = 1; /* datagrams carrying PATH_CHALLENGE / PATH_RESPONSE have to be full-sized */ |
4684 | 0 | } |
4685 | | /* send max_streams frames */ |
4686 | 0 | if ((ret = send_max_streams(conn, 1, s)) != 0) |
4687 | 0 | goto Exit; |
4688 | 0 | if ((ret = send_max_streams(conn, 0, s)) != 0) |
4689 | 0 | goto Exit; |
4690 | | /* send connection-level flow control frames */ |
4691 | 0 | if (should_send_max_data(conn)) { |
4692 | 0 | quicly_sent_t *sent; |
4693 | 0 | if ((ret = allocate_ack_eliciting_frame(conn, s, QUICLY_MAX_DATA_FRAME_CAPACITY, &sent, on_ack_max_data)) != 0) |
4694 | 0 | goto Exit; |
4695 | 0 | uint64_t new_value = conn->ingress.max_data.bytes_consumed + conn->super.ctx->transport_params.max_data; |
4696 | 0 | s->dst = quicly_encode_max_data_frame(s->dst, new_value); |
4697 | 0 | quicly_maxsender_record(&conn->ingress.max_data.sender, new_value, &sent->data.max_data.args); |
4698 | 0 | ++conn->super.stats.num_frames_sent.max_data; |
4699 | 0 | QUICLY_PROBE(MAX_DATA_SEND, conn, conn->stash.now, new_value); |
4700 | 0 | QUICLY_LOG_CONN(max_data_send, conn, { PTLS_LOG_ELEMENT_UNSIGNED(maximum, new_value); }); |
4701 | 0 | } |
4702 | 0 | if (conn->egress.data_blocked == QUICLY_SENDER_STATE_SEND && (ret = send_data_blocked(conn, s)) != 0) |
4703 | 0 | goto Exit; |
4704 | | /* send streams_blocked frames */ |
4705 | 0 | if ((ret = send_streams_blocked(conn, 1, s)) != 0) |
4706 | 0 | goto Exit; |
4707 | 0 | if ((ret = send_streams_blocked(conn, 0, s)) != 0) |
4708 | 0 | goto Exit; |
4709 | | /* send NEW_TOKEN */ |
4710 | 0 | if ((conn->egress.pending_flows & QUICLY_PENDING_FLOW_NEW_TOKEN_BIT) != 0 && |
4711 | 0 | (ret = send_resumption_token(conn, s)) != 0) |
4712 | 0 | goto Exit; |
4713 | 0 | if ((conn->egress.pending_flows & QUICLY_PENDING_FLOW_CID_FRAME_BIT) != 0) { |
4714 | | /* send NEW_CONNECTION_ID */ |
4715 | 0 | size_t i; |
4716 | 0 | size_t size = quicly_local_cid_get_size(&conn->super.local.cid_set); |
4717 | 0 | for (i = 0; i < size; i++) { |
4718 | | /* PENDING CIDs are located at the front */ |
4719 | 0 | struct st_quicly_local_cid_t *c = &conn->super.local.cid_set.cids[i]; |
4720 | 0 | if (c->state != QUICLY_LOCAL_CID_STATE_PENDING) |
4721 | 0 | break; |
4722 | 0 | if ((ret = send_new_connection_id(conn, s, c)) != 0) |
4723 | 0 | break; |
4724 | 0 | } |
4725 | 0 | quicly_local_cid_on_sent(&conn->super.local.cid_set, i); |
4726 | 0 | if (ret != 0) |
4727 | 0 | goto Exit; |
4728 | | /* send RETIRE_CONNECTION_ID */ |
4729 | 0 | size = quicly_retire_cid_get_num_pending(&conn->egress.retire_cid); |
4730 | 0 | for (i = 0; i < size; i++) { |
4731 | 0 | uint64_t sequence = conn->egress.retire_cid.sequences[i]; |
4732 | 0 | if ((ret = send_retire_connection_id(conn, s, sequence)) != 0) |
4733 | 0 | break; |
4734 | 0 | } |
4735 | 0 | quicly_retire_cid_shift(&conn->egress.retire_cid, i); |
4736 | 0 | if (ret != 0) |
4737 | 0 | goto Exit; |
4738 | 0 | conn->egress.pending_flows &= ~QUICLY_PENDING_FLOW_CID_FRAME_BIT; |
4739 | 0 | } |
4740 | 0 | } |
4741 | | /* send stream-level control frames */ |
4742 | 0 | if ((ret = send_stream_control_frames(conn, s)) != 0) |
4743 | 0 | goto Exit; |
4744 | | /* send STREAM frames */ |
4745 | 0 | if ((ret = conn->super.ctx->stream_scheduler->do_send(conn->super.ctx->stream_scheduler, conn, s)) != 0) |
4746 | 0 | goto Exit; |
4747 | | /* once more, send stream-level control frames, as the state might have changed */ |
4748 | 0 | if ((ret = send_stream_control_frames(conn, s)) != 0) |
4749 | 0 | goto Exit; |
4750 | 0 | } |
4751 | 0 | } |
4752 | | |
4753 | 0 | Exit: |
4754 | 0 | if (ret == QUICLY_ERROR_SENDBUF_FULL) |
4755 | 0 | ret = 0; |
4756 | 0 | if (ret == 0 && s->target.first_byte_at != NULL) { |
4757 | | /* last packet can be small-sized, unless it is the first flight sent from the client */ |
4758 | 0 | if ((s->payload_buf.datagram[0] & QUICLY_PACKET_TYPE_BITMASK) == QUICLY_PACKET_TYPE_INITIAL && |
4759 | 0 | (quicly_is_client(conn) || !ack_only)) |
4760 | 0 | s->target.full_size = 1; |
4761 | 0 | commit_send_packet(conn, s, 0); |
4762 | 0 | } |
4763 | 0 | if (ret == 0) { |
4764 | | /* update timers, start / stop delivery rate estimator */ |
4765 | 0 | if (conn->application == NULL || conn->application->super.unacked_count == 0) |
4766 | 0 | conn->egress.send_ack_at = INT64_MAX; /* we have sent ACKs for every epoch (or before address validation) */ |
4767 | 0 | int can_send_stream_data = scheduler_can_send(conn); |
4768 | 0 | update_send_alarm(conn, can_send_stream_data, 1); |
4769 | 0 | if (can_send_stream_data && |
4770 | 0 | (s->num_datagrams == s->max_datagrams || conn->egress.loss.sentmap.bytes_in_flight >= conn->egress.cc.cwnd)) { |
4771 | | /* as the flow is CWND-limited, start delivery rate estimator */ |
4772 | 0 | quicly_ratemeter_in_cwnd_limited(&conn->egress.ratemeter, s->first_packet_number); |
4773 | 0 | } else { |
4774 | 0 | quicly_ratemeter_not_cwnd_limited(&conn->egress.ratemeter, conn->egress.packet_number); |
4775 | 0 | } |
4776 | 0 | if (s->num_datagrams != 0) |
4777 | 0 | update_idle_timeout(conn, 0); |
4778 | 0 | } |
4779 | 0 | return ret; |
4780 | | |
4781 | 0 | CloseNow: |
4782 | 0 | conn->super.state = QUICLY_STATE_DRAINING; |
4783 | 0 | destroy_all_streams(conn, 0, 0); |
4784 | 0 | return QUICLY_ERROR_FREE_CONNECTION; |
4785 | 0 | } |
4786 | | |
4787 | | void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, size_t num_datagrams) |
4788 | 0 | { |
4789 | 0 | for (size_t i = 0; i != num_datagrams; ++i) { |
4790 | 0 | if (conn->egress.datagram_frame_payloads.count == PTLS_ELEMENTSOF(conn->egress.datagram_frame_payloads.payloads)) |
4791 | 0 | break; |
4792 | 0 | void *copied; |
4793 | 0 | if ((copied = malloc(datagrams[i].len)) == NULL) |
4794 | 0 | break; |
4795 | 0 | memcpy(copied, datagrams[i].base, datagrams[i].len); |
4796 | 0 | conn->egress.datagram_frame_payloads.payloads[conn->egress.datagram_frame_payloads.count++] = |
4797 | 0 | ptls_iovec_init(copied, datagrams[i].len); |
4798 | 0 | } |
4799 | 0 | } |
4800 | | |
4801 | | int quicly_set_cc(quicly_conn_t *conn, quicly_cc_type_t *cc) |
4802 | 0 | { |
4803 | 0 | return cc->cc_switch(&conn->egress.cc); |
4804 | 0 | } |
4805 | | |
4806 | | int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *src, struct iovec *datagrams, size_t *num_datagrams, |
4807 | | void *buf, size_t bufsize) |
4808 | 0 | { |
4809 | 0 | quicly_send_context_t s = {.current = {.first_byte = -1}, |
4810 | 0 | .datagrams = datagrams, |
4811 | 0 | .max_datagrams = *num_datagrams, |
4812 | 0 | .payload_buf = {.datagram = buf, .end = (uint8_t *)buf + bufsize}, |
4813 | 0 | .first_packet_number = conn->egress.packet_number}; |
4814 | 0 | int ret; |
4815 | |
|
4816 | 0 | lock_now(conn, 0); |
4817 | | |
4818 | | /* bail out if there's nothing is scheduled to be sent */ |
4819 | 0 | if (conn->stash.now < quicly_get_first_timeout(conn)) { |
4820 | 0 | ret = 0; |
4821 | 0 | goto Exit; |
4822 | 0 | } |
4823 | | |
4824 | 0 | QUICLY_PROBE(SEND, conn, conn->stash.now, conn->super.state, |
4825 | 0 | QUICLY_PROBE_HEXDUMP(conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len)); |
4826 | 0 | QUICLY_LOG_CONN(send, conn, { |
4827 | 0 | PTLS_LOG_ELEMENT_SIGNED(state, conn->super.state); |
4828 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(dcid, conn->super.remote.cid_set.cids[0].cid.cid, conn->super.remote.cid_set.cids[0].cid.len); |
4829 | 0 | }); |
4830 | | |
4831 | 0 | if (conn->super.state >= QUICLY_STATE_CLOSING) { |
4832 | 0 | quicly_sentmap_iter_t iter; |
4833 | 0 | if ((ret = init_acks_iter(conn, &iter)) != 0) |
4834 | 0 | goto Exit; |
4835 | | /* check if the connection can be closed now (after 3 pto) */ |
4836 | 0 | if (conn->super.state == QUICLY_STATE_DRAINING || |
4837 | 0 | conn->super.stats.num_frames_sent.transport_close + conn->super.stats.num_frames_sent.application_close != 0) { |
4838 | 0 | if (quicly_sentmap_get(&iter)->packet_number == UINT64_MAX) { |
4839 | 0 | assert(quicly_num_streams(conn) == 0); |
4840 | 0 | ret = QUICLY_ERROR_FREE_CONNECTION; |
4841 | 0 | goto Exit; |
4842 | 0 | } |
4843 | 0 | } |
4844 | 0 | if (conn->super.state == QUICLY_STATE_CLOSING && conn->egress.send_ack_at <= conn->stash.now) { |
4845 | | /* destroy all streams; doing so is delayed until the emission of CONNECTION_CLOSE frame to allow quicly_close to be |
4846 | | * called from a stream handler */ |
4847 | 0 | destroy_all_streams(conn, 0, 0); |
4848 | | /* send CONNECTION_CLOSE in all possible epochs */ |
4849 | 0 | for (size_t epoch = 0; epoch < QUICLY_NUM_EPOCHS; ++epoch) { |
4850 | 0 | if ((ret = send_connection_close(conn, epoch, &s)) != 0) |
4851 | 0 | goto Exit; |
4852 | 0 | } |
4853 | 0 | if ((ret = commit_send_packet(conn, &s, 0)) != 0) |
4854 | 0 | goto Exit; |
4855 | 0 | } |
4856 | | /* wait at least 1ms */ |
4857 | 0 | if ((conn->egress.send_ack_at = quicly_sentmap_get(&iter)->sent_at + get_sentmap_expiration_time(conn)) <= conn->stash.now) |
4858 | 0 | conn->egress.send_ack_at = conn->stash.now + 1; |
4859 | 0 | ret = 0; |
4860 | 0 | goto Exit; |
4861 | 0 | } |
4862 | | |
4863 | | /* emit packets */ |
4864 | 0 | if ((ret = do_send(conn, &s)) != 0) |
4865 | 0 | goto Exit; |
4866 | | |
4867 | 0 | assert_consistency(conn, 1); |
4868 | |
|
4869 | 0 | Exit: |
4870 | 0 | clear_datagram_frame_payloads(conn); |
4871 | 0 | if (s.num_datagrams != 0) { |
4872 | 0 | *dest = conn->super.remote.address; |
4873 | 0 | *src = conn->super.local.address; |
4874 | 0 | } |
4875 | 0 | *num_datagrams = s.num_datagrams; |
4876 | 0 | unlock_now(conn); |
4877 | 0 | return ret; |
4878 | 0 | } |
4879 | | |
4880 | | size_t quicly_send_close_invalid_token(quicly_context_t *ctx, uint32_t protocol_version, ptls_iovec_t dest_cid, |
4881 | | ptls_iovec_t src_cid, const char *err_desc, void *datagram) |
4882 | 0 | { |
4883 | 0 | struct st_quicly_cipher_context_t egress = {}; |
4884 | 0 | const struct st_ptls_salt_t *salt; |
4885 | | |
4886 | | /* setup keys */ |
4887 | 0 | if ((salt = get_salt(protocol_version)) == NULL) |
4888 | 0 | return SIZE_MAX; |
4889 | 0 | if (setup_initial_encryption(get_aes128gcmsha256(ctx), NULL, &egress, src_cid, 0, |
4890 | 0 | ptls_iovec_init(salt->initial, sizeof(salt->initial)), NULL) != 0) |
4891 | 0 | return SIZE_MAX; |
4892 | | |
4893 | 0 | uint8_t *dst = datagram, *length_at; |
4894 | | |
4895 | | /* build packet */ |
4896 | 0 | PTLS_BUILD_ASSERT(QUICLY_SEND_PN_SIZE == 2); |
4897 | 0 | *dst++ = QUICLY_PACKET_TYPE_INITIAL | 0x1 /* 2-byte PN */; |
4898 | 0 | dst = quicly_encode32(dst, protocol_version); |
4899 | 0 | *dst++ = dest_cid.len; |
4900 | 0 | memcpy(dst, dest_cid.base, dest_cid.len); |
4901 | 0 | dst += dest_cid.len; |
4902 | 0 | *dst++ = src_cid.len; |
4903 | 0 | memcpy(dst, src_cid.base, src_cid.len); |
4904 | 0 | dst += src_cid.len; |
4905 | 0 | *dst++ = 0; /* token_length = 0 */ |
4906 | 0 | length_at = dst++; /* length_at to be filled in later as 1-byte varint */ |
4907 | 0 | *dst++ = 0; /* PN = 0 */ |
4908 | 0 | *dst++ = 0; /* ditto */ |
4909 | 0 | uint8_t *payload_from = dst; |
4910 | 0 | dst = quicly_encode_close_frame(dst, QUICLY_ERROR_GET_ERROR_CODE(QUICLY_TRANSPORT_ERROR_INVALID_TOKEN), |
4911 | 0 | QUICLY_FRAME_TYPE_PADDING, err_desc); |
4912 | | |
4913 | | /* determine the size of the packet, make adjustments */ |
4914 | 0 | dst += egress.aead->algo->tag_size; |
4915 | 0 | assert(dst - (uint8_t *)datagram <= QUICLY_MIN_CLIENT_INITIAL_SIZE); |
4916 | 0 | assert(dst - length_at - 1 < 64); |
4917 | 0 | *length_at = dst - length_at - 1; |
4918 | 0 | size_t datagram_len = dst - (uint8_t *)datagram; |
4919 | | |
4920 | | /* encrypt packet */ |
4921 | 0 | quicly_default_crypto_engine.encrypt_packet(&quicly_default_crypto_engine, NULL, egress.header_protection, egress.aead, |
4922 | 0 | ptls_iovec_init(datagram, datagram_len), 0, payload_from - (uint8_t *)datagram, 0, |
4923 | 0 | 0); |
4924 | |
|
4925 | 0 | dispose_cipher(&egress); |
4926 | 0 | return datagram_len; |
4927 | 0 | } |
4928 | | |
4929 | | size_t quicly_send_stateless_reset(quicly_context_t *ctx, const void *src_cid, void *payload) |
4930 | 0 | { |
4931 | 0 | uint8_t *base = payload; |
4932 | | |
4933 | | /* build stateless reset packet */ |
4934 | 0 | ctx->tls->random_bytes(base, QUICLY_STATELESS_RESET_PACKET_MIN_LEN - QUICLY_STATELESS_RESET_TOKEN_LEN); |
4935 | 0 | base[0] = (base[0] & ~QUICLY_LONG_HEADER_BIT) | QUICLY_QUIC_BIT; |
4936 | 0 | if (!ctx->cid_encryptor->generate_stateless_reset_token( |
4937 | 0 | ctx->cid_encryptor, base + QUICLY_STATELESS_RESET_PACKET_MIN_LEN - QUICLY_STATELESS_RESET_TOKEN_LEN, src_cid)) |
4938 | 0 | return SIZE_MAX; |
4939 | | |
4940 | 0 | return QUICLY_STATELESS_RESET_PACKET_MIN_LEN; |
4941 | 0 | } |
4942 | | |
4943 | | int quicly_send_resumption_token(quicly_conn_t *conn) |
4944 | 0 | { |
4945 | 0 | if (conn->super.state <= QUICLY_STATE_CONNECTED) { |
4946 | 0 | ++conn->egress.new_token.generation; |
4947 | 0 | conn->egress.pending_flows |= QUICLY_PENDING_FLOW_NEW_TOKEN_BIT; |
4948 | 0 | } |
4949 | 0 | return 0; |
4950 | 0 | } |
4951 | | |
4952 | | static int on_end_closing(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent) |
4953 | 0 | { |
4954 | | /* we stop accepting frames by the time this ack callback is being registered */ |
4955 | 0 | assert(!acked); |
4956 | 0 | return 0; |
4957 | 0 | } |
4958 | | |
4959 | | static int enter_close(quicly_conn_t *conn, int local_is_initiating, int wait_draining) |
4960 | 0 | { |
4961 | 0 | int ret; |
4962 | |
|
4963 | 0 | assert(conn->super.state < QUICLY_STATE_CLOSING); |
4964 | | |
4965 | | /* release all inflight info, register a close timeout */ |
4966 | 0 | if ((ret = discard_sentmap_by_epoch(conn, ~0u)) != 0) |
4967 | 0 | return ret; |
4968 | 0 | if ((ret = quicly_sentmap_prepare(&conn->egress.loss.sentmap, conn->egress.packet_number, conn->stash.now, |
4969 | 0 | QUICLY_EPOCH_INITIAL)) != 0) |
4970 | 0 | return ret; |
4971 | 0 | if (quicly_sentmap_allocate(&conn->egress.loss.sentmap, on_end_closing) == NULL) |
4972 | 0 | return PTLS_ERROR_NO_MEMORY; |
4973 | 0 | quicly_sentmap_commit(&conn->egress.loss.sentmap, 0); |
4974 | 0 | ++conn->egress.packet_number; |
4975 | |
|
4976 | 0 | if (local_is_initiating) { |
4977 | 0 | conn->super.state = QUICLY_STATE_CLOSING; |
4978 | 0 | conn->egress.send_ack_at = 0; |
4979 | 0 | } else { |
4980 | 0 | conn->super.state = QUICLY_STATE_DRAINING; |
4981 | 0 | conn->egress.send_ack_at = wait_draining ? conn->stash.now + get_sentmap_expiration_time(conn) : 0; |
4982 | 0 | } |
4983 | |
|
4984 | 0 | setup_next_send(conn); |
4985 | |
|
4986 | 0 | return 0; |
4987 | 0 | } |
4988 | | |
4989 | | int initiate_close(quicly_conn_t *conn, int err, uint64_t frame_type, const char *reason_phrase) |
4990 | 0 | { |
4991 | 0 | uint16_t quic_error_code; |
4992 | |
|
4993 | 0 | if (conn->super.state >= QUICLY_STATE_CLOSING) |
4994 | 0 | return 0; |
4995 | | |
4996 | 0 | if (reason_phrase == NULL) |
4997 | 0 | reason_phrase = ""; |
4998 | | |
4999 | | /* convert error code to QUIC error codes */ |
5000 | 0 | if (err == 0) { |
5001 | 0 | quic_error_code = 0; |
5002 | 0 | frame_type = QUICLY_FRAME_TYPE_PADDING; |
5003 | 0 | } else if (QUICLY_ERROR_IS_QUIC_TRANSPORT(err)) { |
5004 | 0 | quic_error_code = QUICLY_ERROR_GET_ERROR_CODE(err); |
5005 | 0 | } else if (QUICLY_ERROR_IS_QUIC_APPLICATION(err)) { |
5006 | 0 | quic_error_code = QUICLY_ERROR_GET_ERROR_CODE(err); |
5007 | 0 | frame_type = UINT64_MAX; |
5008 | 0 | } else if (PTLS_ERROR_GET_CLASS(err) == PTLS_ERROR_CLASS_SELF_ALERT) { |
5009 | 0 | quic_error_code = QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT(err); |
5010 | 0 | } else { |
5011 | 0 | quic_error_code = QUICLY_ERROR_GET_ERROR_CODE(QUICLY_TRANSPORT_ERROR_INTERNAL); |
5012 | 0 | } |
5013 | |
|
5014 | 0 | conn->egress.connection_close.error_code = quic_error_code; |
5015 | 0 | conn->egress.connection_close.frame_type = frame_type; |
5016 | 0 | conn->egress.connection_close.reason_phrase = reason_phrase; |
5017 | 0 | return enter_close(conn, 1, 0); |
5018 | 0 | } |
5019 | | |
5020 | | int quicly_close(quicly_conn_t *conn, int err, const char *reason_phrase) |
5021 | 0 | { |
5022 | 0 | int ret; |
5023 | |
|
5024 | 0 | assert(err == 0 || QUICLY_ERROR_IS_QUIC_APPLICATION(err) || QUICLY_ERROR_IS_CONCEALED(err)); |
5025 | | |
5026 | 0 | lock_now(conn, 1); |
5027 | 0 | ret = initiate_close(conn, err, QUICLY_FRAME_TYPE_PADDING /* used when err == 0 */, reason_phrase); |
5028 | 0 | unlock_now(conn); |
5029 | |
|
5030 | 0 | return ret; |
5031 | 0 | } |
5032 | | |
5033 | | int quicly_get_or_open_stream(quicly_conn_t *conn, uint64_t stream_id, quicly_stream_t **stream) |
5034 | 0 | { |
5035 | 0 | int ret = 0; |
5036 | |
|
5037 | 0 | if ((*stream = quicly_get_stream(conn, stream_id)) != NULL) |
5038 | 0 | goto Exit; |
5039 | | |
5040 | 0 | if (quicly_stream_is_client_initiated(stream_id) != quicly_is_client(conn)) { |
5041 | | /* check if stream id is within the bounds */ |
5042 | 0 | if (stream_id / 4 >= quicly_get_ingress_max_streams(conn, quicly_stream_is_unidirectional(stream_id))) { |
5043 | 0 | ret = QUICLY_TRANSPORT_ERROR_STREAM_LIMIT; |
5044 | 0 | goto Exit; |
5045 | 0 | } |
5046 | | /* open new streams upto given id */ |
5047 | 0 | struct st_quicly_conn_streamgroup_state_t *group = get_streamgroup_state(conn, stream_id); |
5048 | 0 | if (group->next_stream_id <= stream_id) { |
5049 | 0 | uint64_t max_stream_data_local, max_stream_data_remote; |
5050 | 0 | if (quicly_stream_is_unidirectional(stream_id)) { |
5051 | 0 | max_stream_data_local = conn->super.ctx->transport_params.max_stream_data.uni; |
5052 | 0 | max_stream_data_remote = 0; |
5053 | 0 | } else { |
5054 | 0 | max_stream_data_local = conn->super.ctx->transport_params.max_stream_data.bidi_remote; |
5055 | 0 | max_stream_data_remote = conn->super.remote.transport_params.max_stream_data.bidi_local; |
5056 | 0 | } |
5057 | 0 | do { |
5058 | 0 | if ((*stream = open_stream(conn, group->next_stream_id, (uint32_t)max_stream_data_local, max_stream_data_remote)) == |
5059 | 0 | NULL) { |
5060 | 0 | ret = PTLS_ERROR_NO_MEMORY; |
5061 | 0 | goto Exit; |
5062 | 0 | } |
5063 | 0 | QUICLY_PROBE(STREAM_ON_OPEN, conn, conn->stash.now, *stream); |
5064 | 0 | QUICLY_LOG_CONN(stream_on_open, conn, { PTLS_LOG_ELEMENT_SIGNED(stream_id, (*stream)->stream_id); }); |
5065 | 0 | if ((ret = conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, *stream)) != 0) { |
5066 | 0 | *stream = NULL; |
5067 | 0 | goto Exit; |
5068 | 0 | } |
5069 | 0 | ++group->num_streams; |
5070 | 0 | group->next_stream_id += 4; |
5071 | 0 | } while (stream_id != (*stream)->stream_id); |
5072 | 0 | } |
5073 | 0 | } |
5074 | | |
5075 | 0 | Exit: |
5076 | 0 | return ret; |
5077 | 0 | } |
5078 | | |
5079 | | static int handle_crypto_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5080 | 0 | { |
5081 | 0 | quicly_stream_frame_t frame; |
5082 | 0 | quicly_stream_t *stream; |
5083 | 0 | int ret; |
5084 | |
|
5085 | 0 | if ((ret = quicly_decode_crypto_frame(&state->src, state->end, &frame)) != 0) |
5086 | 0 | return ret; |
5087 | 0 | stream = quicly_get_stream(conn, -(quicly_stream_id_t)(1 + state->epoch)); |
5088 | 0 | assert(stream != NULL); |
5089 | 0 | return apply_stream_frame(stream, &frame); |
5090 | 0 | } |
5091 | | |
5092 | | static int handle_stream_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5093 | 0 | { |
5094 | 0 | quicly_stream_frame_t frame; |
5095 | 0 | quicly_stream_t *stream; |
5096 | 0 | int ret; |
5097 | |
|
5098 | 0 | if ((ret = quicly_decode_stream_frame(state->frame_type, &state->src, state->end, &frame)) != 0) |
5099 | 0 | return ret; |
5100 | 0 | QUICLY_PROBE(QUICTRACE_RECV_STREAM, conn, conn->stash.now, frame.stream_id, frame.offset, frame.data.len, (int)frame.is_fin); |
5101 | 0 | if ((ret = quicly_get_or_open_stream(conn, frame.stream_id, &stream)) != 0 || stream == NULL) |
5102 | 0 | return ret; |
5103 | 0 | return apply_stream_frame(stream, &frame); |
5104 | 0 | } |
5105 | | |
5106 | | static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5107 | 0 | { |
5108 | 0 | quicly_reset_stream_frame_t frame; |
5109 | 0 | quicly_stream_t *stream; |
5110 | 0 | int ret; |
5111 | |
|
5112 | 0 | if ((ret = quicly_decode_reset_stream_frame(&state->src, state->end, &frame)) != 0) |
5113 | 0 | return ret; |
5114 | 0 | QUICLY_PROBE(RESET_STREAM_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code, frame.final_size); |
5115 | 0 | QUICLY_LOG_CONN(reset_stream_receive, conn, { |
5116 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, (quicly_stream_id_t)frame.stream_id); |
5117 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(app_error_code, frame.app_error_code); |
5118 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(final_size, frame.final_size); |
5119 | 0 | }); |
5120 | | |
5121 | 0 | if ((ret = quicly_get_or_open_stream(conn, frame.stream_id, &stream)) != 0 || stream == NULL) |
5122 | 0 | return ret; |
5123 | | |
5124 | 0 | if (!quicly_recvstate_transfer_complete(&stream->recvstate)) { |
5125 | 0 | uint64_t bytes_missing; |
5126 | 0 | if ((ret = quicly_recvstate_reset(&stream->recvstate, frame.final_size, &bytes_missing)) != 0) |
5127 | 0 | return ret; |
5128 | 0 | stream->conn->ingress.max_data.bytes_consumed += bytes_missing; |
5129 | 0 | int err = QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.app_error_code); |
5130 | 0 | QUICLY_PROBE(STREAM_ON_RECEIVE_RESET, stream->conn, stream->conn->stash.now, stream, err); |
5131 | 0 | QUICLY_LOG_CONN(stream_on_receive_reset, stream->conn, { |
5132 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
5133 | 0 | PTLS_LOG_ELEMENT_SIGNED(err, err); |
5134 | 0 | }); |
5135 | 0 | stream->callbacks->on_receive_reset(stream, err); |
5136 | 0 | if (stream->conn->super.state >= QUICLY_STATE_CLOSING) |
5137 | 0 | return QUICLY_ERROR_IS_CLOSING; |
5138 | 0 | if (stream_is_destroyable(stream)) |
5139 | 0 | destroy_stream(stream, 0); |
5140 | 0 | } |
5141 | | |
5142 | 0 | return 0; |
5143 | 0 | } |
5144 | | |
5145 | | static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5146 | 0 | { |
5147 | 0 | quicly_ack_frame_t frame; |
5148 | 0 | quicly_sentmap_iter_t iter; |
5149 | 0 | struct { |
5150 | 0 | uint64_t pn; |
5151 | 0 | int64_t sent_at; |
5152 | 0 | } largest_newly_acked = {UINT64_MAX, INT64_MAX}; |
5153 | 0 | size_t bytes_acked = 0; |
5154 | 0 | int includes_ack_eliciting = 0, includes_late_ack = 0, ret; |
5155 | |
|
5156 | 0 | if ((ret = quicly_decode_ack_frame(&state->src, state->end, &frame, state->frame_type == QUICLY_FRAME_TYPE_ACK_ECN)) != 0) |
5157 | 0 | return ret; |
5158 | | |
5159 | 0 | uint64_t pn_acked = frame.smallest_acknowledged; |
5160 | |
|
5161 | 0 | switch (state->epoch) { |
5162 | 0 | case QUICLY_EPOCH_0RTT: |
5163 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
5164 | 0 | case QUICLY_EPOCH_HANDSHAKE: |
5165 | 0 | conn->super.remote.address_validation.send_probe = 0; |
5166 | 0 | break; |
5167 | 0 | default: |
5168 | 0 | break; |
5169 | 0 | } |
5170 | | |
5171 | 0 | if ((ret = init_acks_iter(conn, &iter)) != 0) |
5172 | 0 | return ret; |
5173 | | |
5174 | | /* TODO log PNs being ACKed too late */ |
5175 | | |
5176 | 0 | size_t gap_index = frame.num_gaps; |
5177 | 0 | while (1) { |
5178 | 0 | assert(frame.ack_block_lengths[gap_index] != 0); |
5179 | | /* Ack blocks are organized in the ACK frame and consequently in the ack_block_lengths array from the largest acked down. |
5180 | | * Processing acks in packet number order requires processing the ack blocks in reverse order. */ |
5181 | 0 | uint64_t pn_block_max = pn_acked + frame.ack_block_lengths[gap_index] - 1; |
5182 | 0 | QUICLY_PROBE(ACK_BLOCK_RECEIVED, conn, conn->stash.now, pn_acked, pn_block_max); |
5183 | 0 | QUICLY_LOG_CONN(ack_block_received, conn, { |
5184 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(ack_block_begin, pn_acked); |
5185 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(ack_block_end, pn_block_max); |
5186 | 0 | }); |
5187 | 0 | while (quicly_sentmap_get(&iter)->packet_number < pn_acked) |
5188 | 0 | quicly_sentmap_skip(&iter); |
5189 | 0 | do { |
5190 | 0 | const quicly_sent_packet_t *sent = quicly_sentmap_get(&iter); |
5191 | 0 | uint64_t pn_sent = sent->packet_number; |
5192 | 0 | assert(pn_acked <= pn_sent); |
5193 | 0 | if (pn_acked < pn_sent) { |
5194 | | /* set pn_acked to pn_sent; or past the end of the ack block, for use with the next ack block */ |
5195 | 0 | if (pn_sent <= pn_block_max) { |
5196 | 0 | pn_acked = pn_sent; |
5197 | 0 | } else { |
5198 | 0 | pn_acked = pn_block_max + 1; |
5199 | 0 | break; |
5200 | 0 | } |
5201 | 0 | } |
5202 | | /* process newly acked packet */ |
5203 | 0 | if (state->epoch != sent->ack_epoch) |
5204 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
5205 | 0 | int is_late_ack = 0; |
5206 | 0 | if (sent->ack_eliciting) { |
5207 | 0 | includes_ack_eliciting = 1; |
5208 | 0 | if (sent->cc_bytes_in_flight == 0) { |
5209 | 0 | is_late_ack = 1; |
5210 | 0 | includes_late_ack = 1; |
5211 | 0 | ++conn->super.stats.num_packets.late_acked; |
5212 | 0 | } |
5213 | 0 | } |
5214 | 0 | ++conn->super.stats.num_packets.ack_received; |
5215 | 0 | largest_newly_acked.pn = pn_acked; |
5216 | 0 | largest_newly_acked.sent_at = sent->sent_at; |
5217 | 0 | QUICLY_PROBE(PACKET_ACKED, conn, conn->stash.now, pn_acked, is_late_ack); |
5218 | 0 | QUICLY_LOG_CONN(packet_acked, conn, { |
5219 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(pn, pn_acked); |
5220 | 0 | PTLS_LOG_ELEMENT_BOOL(is_late_ack, is_late_ack); |
5221 | 0 | }); |
5222 | 0 | if (sent->cc_bytes_in_flight != 0) { |
5223 | 0 | bytes_acked += sent->cc_bytes_in_flight; |
5224 | 0 | conn->super.stats.num_bytes.ack_received += sent->cc_bytes_in_flight; |
5225 | 0 | } |
5226 | 0 | if ((ret = quicly_sentmap_update(&conn->egress.loss.sentmap, &iter, QUICLY_SENTMAP_EVENT_ACKED)) != 0) |
5227 | 0 | return ret; |
5228 | 0 | if (state->epoch == QUICLY_EPOCH_1RTT) { |
5229 | 0 | struct st_quicly_application_space_t *space = conn->application; |
5230 | 0 | if (space->cipher.egress.key_update_pn.last <= pn_acked) { |
5231 | 0 | space->cipher.egress.key_update_pn.last = UINT64_MAX; |
5232 | 0 | space->cipher.egress.key_update_pn.next = conn->egress.packet_number + conn->super.ctx->max_packets_per_key; |
5233 | 0 | QUICLY_PROBE(CRYPTO_SEND_KEY_UPDATE_CONFIRMED, conn, conn->stash.now, space->cipher.egress.key_update_pn.next); |
5234 | 0 | QUICLY_LOG_CONN(crypto_send_key_update_confirmed, conn, |
5235 | 0 | { PTLS_LOG_ELEMENT_UNSIGNED(next_pn, space->cipher.egress.key_update_pn.next); }); |
5236 | 0 | } |
5237 | 0 | } |
5238 | 0 | ++pn_acked; |
5239 | 0 | } while (pn_acked <= pn_block_max); |
5240 | 0 | assert(pn_acked == pn_block_max + 1); |
5241 | 0 | if (gap_index-- == 0) |
5242 | 0 | break; |
5243 | 0 | pn_acked += frame.gaps[gap_index]; |
5244 | 0 | } |
5245 | | |
5246 | 0 | if ((ret = on_ack_stream_ack_cached(conn)) != 0) |
5247 | 0 | return ret; |
5248 | | |
5249 | 0 | QUICLY_PROBE(ACK_DELAY_RECEIVED, conn, conn->stash.now, frame.ack_delay); |
5250 | 0 | QUICLY_LOG_CONN(ack_delay_received, conn, { PTLS_LOG_ELEMENT_UNSIGNED(ack_delay, frame.ack_delay); }); |
5251 | | |
5252 | 0 | quicly_ratemeter_on_ack(&conn->egress.ratemeter, conn->stash.now, conn->super.stats.num_bytes.ack_received, |
5253 | 0 | largest_newly_acked.pn); |
5254 | | |
5255 | | /* Update loss detection engine on ack. The function uses ack_delay only when the largest_newly_acked is also the largest acked |
5256 | | * so far. So, it does not matter if the ack_delay being passed in does not apply to the largest_newly_acked. */ |
5257 | 0 | quicly_loss_on_ack_received(&conn->egress.loss, largest_newly_acked.pn, state->epoch, conn->stash.now, |
5258 | 0 | largest_newly_acked.sent_at, frame.ack_delay, |
5259 | 0 | includes_ack_eliciting ? includes_late_ack ? QUICLY_LOSS_ACK_RECEIVED_KIND_ACK_ELICITING_LATE_ACK |
5260 | 0 | : QUICLY_LOSS_ACK_RECEIVED_KIND_ACK_ELICITING |
5261 | 0 | : QUICLY_LOSS_ACK_RECEIVED_KIND_NON_ACK_ELICITING); |
5262 | | |
5263 | | /* OnPacketAcked and OnPacketAckedCC */ |
5264 | 0 | if (bytes_acked > 0) { |
5265 | 0 | conn->egress.cc.type->cc_on_acked(&conn->egress.cc, &conn->egress.loss, (uint32_t)bytes_acked, frame.largest_acknowledged, |
5266 | 0 | (uint32_t)(conn->egress.loss.sentmap.bytes_in_flight + bytes_acked), |
5267 | 0 | conn->egress.packet_number, conn->stash.now, conn->egress.max_udp_payload_size); |
5268 | 0 | QUICLY_PROBE(QUICTRACE_CC_ACK, conn, conn->stash.now, &conn->egress.loss.rtt, conn->egress.cc.cwnd, |
5269 | 0 | conn->egress.loss.sentmap.bytes_in_flight); |
5270 | 0 | } |
5271 | |
|
5272 | 0 | QUICLY_PROBE(CC_ACK_RECEIVED, conn, conn->stash.now, frame.largest_acknowledged, bytes_acked, conn->egress.cc.cwnd, |
5273 | 0 | conn->egress.loss.sentmap.bytes_in_flight); |
5274 | 0 | QUICLY_LOG_CONN(cc_ack_received, conn, { |
5275 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(largest_acked, frame.largest_acknowledged); |
5276 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(bytes_acked, bytes_acked); |
5277 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(cwnd, conn->egress.cc.cwnd); |
5278 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(inflight, conn->egress.loss.sentmap.bytes_in_flight); |
5279 | 0 | }); |
5280 | | |
5281 | | /* loss-detection */ |
5282 | 0 | if ((ret = quicly_loss_detect_loss(&conn->egress.loss, conn->stash.now, conn->super.remote.transport_params.max_ack_delay, |
5283 | 0 | conn->initial == NULL && conn->handshake == NULL, on_loss_detected)) != 0) |
5284 | 0 | return ret; |
5285 | 0 | setup_next_send(conn); |
5286 | |
|
5287 | 0 | return 0; |
5288 | 0 | } |
5289 | | |
5290 | | static int handle_max_stream_data_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5291 | 0 | { |
5292 | 0 | quicly_max_stream_data_frame_t frame; |
5293 | 0 | quicly_stream_t *stream; |
5294 | 0 | int ret; |
5295 | |
|
5296 | 0 | if ((ret = quicly_decode_max_stream_data_frame(&state->src, state->end, &frame)) != 0) |
5297 | 0 | return ret; |
5298 | | |
5299 | 0 | QUICLY_PROBE(MAX_STREAM_DATA_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.max_stream_data); |
5300 | 0 | QUICLY_LOG_CONN(max_stream_data_receive, conn, { |
5301 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, (quicly_stream_id_t)frame.stream_id); |
5302 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(max_stream_data, frame.max_stream_data); |
5303 | 0 | }); |
5304 | | |
5305 | 0 | if (!quicly_stream_has_send_side(quicly_is_client(conn), frame.stream_id)) |
5306 | 0 | return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; |
5307 | | |
5308 | 0 | if ((stream = quicly_get_stream(conn, frame.stream_id)) == NULL) |
5309 | 0 | return 0; |
5310 | | |
5311 | 0 | if (frame.max_stream_data <= stream->_send_aux.max_stream_data) |
5312 | 0 | return 0; |
5313 | 0 | stream->_send_aux.max_stream_data = frame.max_stream_data; |
5314 | 0 | stream->_send_aux.blocked = QUICLY_SENDER_STATE_NONE; |
5315 | |
|
5316 | 0 | if (stream->_send_aux.reset_stream.sender_state == QUICLY_SENDER_STATE_NONE) |
5317 | 0 | resched_stream_data(stream); |
5318 | |
|
5319 | 0 | return 0; |
5320 | 0 | } |
5321 | | |
5322 | | static int handle_data_blocked_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5323 | 0 | { |
5324 | 0 | quicly_data_blocked_frame_t frame; |
5325 | 0 | int ret; |
5326 | |
|
5327 | 0 | if ((ret = quicly_decode_data_blocked_frame(&state->src, state->end, &frame)) != 0) |
5328 | 0 | return ret; |
5329 | | |
5330 | 0 | QUICLY_PROBE(DATA_BLOCKED_RECEIVE, conn, conn->stash.now, frame.offset); |
5331 | 0 | QUICLY_LOG_CONN(data_blocked_receive, conn, { PTLS_LOG_ELEMENT_UNSIGNED(off, frame.offset); }); |
5332 | | |
5333 | 0 | quicly_maxsender_request_transmit(&conn->ingress.max_data.sender); |
5334 | 0 | if (should_send_max_data(conn)) |
5335 | 0 | conn->egress.send_ack_at = 0; |
5336 | |
|
5337 | 0 | return 0; |
5338 | 0 | } |
5339 | | |
5340 | | static int handle_stream_data_blocked_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5341 | 0 | { |
5342 | 0 | quicly_stream_data_blocked_frame_t frame; |
5343 | 0 | quicly_stream_t *stream; |
5344 | 0 | int ret; |
5345 | |
|
5346 | 0 | if ((ret = quicly_decode_stream_data_blocked_frame(&state->src, state->end, &frame)) != 0) |
5347 | 0 | return ret; |
5348 | | |
5349 | 0 | QUICLY_PROBE(STREAM_DATA_BLOCKED_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.offset); |
5350 | 0 | QUICLY_LOG_CONN(stream_data_blocked_receive, conn, { |
5351 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, frame.stream_id); |
5352 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.offset); |
5353 | 0 | }); |
5354 | | |
5355 | 0 | if (!quicly_stream_has_receive_side(quicly_is_client(conn), frame.stream_id)) |
5356 | 0 | return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; |
5357 | | |
5358 | 0 | if ((stream = quicly_get_stream(conn, frame.stream_id)) != NULL) { |
5359 | 0 | quicly_maxsender_request_transmit(&stream->_send_aux.max_stream_data_sender); |
5360 | 0 | if (should_send_max_stream_data(stream)) |
5361 | 0 | sched_stream_control(stream); |
5362 | 0 | } |
5363 | |
|
5364 | 0 | return 0; |
5365 | 0 | } |
5366 | | |
5367 | | static int handle_streams_blocked_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5368 | 0 | { |
5369 | 0 | quicly_streams_blocked_frame_t frame; |
5370 | 0 | int uni = state->frame_type == QUICLY_FRAME_TYPE_STREAMS_BLOCKED_UNI, ret; |
5371 | |
|
5372 | 0 | if ((ret = quicly_decode_streams_blocked_frame(&state->src, state->end, &frame)) != 0) |
5373 | 0 | return ret; |
5374 | | |
5375 | 0 | QUICLY_PROBE(STREAMS_BLOCKED_RECEIVE, conn, conn->stash.now, frame.count, uni); |
5376 | 0 | QUICLY_LOG_CONN(streams_blocked_receive, conn, { |
5377 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.count); |
5378 | 0 | PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); |
5379 | 0 | }); |
5380 | | |
5381 | 0 | if (should_send_max_streams(conn, uni)) { |
5382 | 0 | quicly_maxsender_t *maxsender = uni ? &conn->ingress.max_streams.uni : &conn->ingress.max_streams.bidi; |
5383 | 0 | quicly_maxsender_request_transmit(maxsender); |
5384 | 0 | conn->egress.send_ack_at = 0; |
5385 | 0 | } |
5386 | |
|
5387 | 0 | return 0; |
5388 | 0 | } |
5389 | | |
5390 | | static int handle_max_streams_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state, int uni) |
5391 | 0 | { |
5392 | 0 | quicly_max_streams_frame_t frame; |
5393 | 0 | int ret; |
5394 | |
|
5395 | 0 | if ((ret = quicly_decode_max_streams_frame(&state->src, state->end, &frame)) != 0) |
5396 | 0 | return ret; |
5397 | | |
5398 | 0 | QUICLY_PROBE(MAX_STREAMS_RECEIVE, conn, conn->stash.now, frame.count, uni); |
5399 | 0 | QUICLY_LOG_CONN(max_streams_receive, conn, { |
5400 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.count); |
5401 | 0 | PTLS_LOG_ELEMENT_BOOL(is_unidirectional, uni); |
5402 | 0 | }); |
5403 | | |
5404 | 0 | if ((ret = update_max_streams(uni ? &conn->egress.max_streams.uni : &conn->egress.max_streams.bidi, frame.count)) != 0) |
5405 | 0 | return ret; |
5406 | | |
5407 | 0 | open_blocked_streams(conn, uni); |
5408 | |
|
5409 | 0 | return 0; |
5410 | 0 | } |
5411 | | |
5412 | | static int handle_max_streams_bidi_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5413 | 0 | { |
5414 | 0 | return handle_max_streams_frame(conn, state, 0); |
5415 | 0 | } |
5416 | | |
5417 | | static int handle_max_streams_uni_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5418 | 0 | { |
5419 | 0 | return handle_max_streams_frame(conn, state, 1); |
5420 | 0 | } |
5421 | | |
5422 | | static int handle_path_challenge_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5423 | 0 | { |
5424 | 0 | quicly_path_challenge_frame_t frame; |
5425 | 0 | int ret; |
5426 | |
|
5427 | 0 | if ((ret = quicly_decode_path_challenge_frame(&state->src, state->end, &frame)) != 0) |
5428 | 0 | return ret; |
5429 | 0 | return schedule_path_challenge_frame(conn, 1, frame.data); |
5430 | 0 | } |
5431 | | |
5432 | | static int handle_path_response_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5433 | 0 | { |
5434 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
5435 | 0 | } |
5436 | | |
5437 | | static int handle_new_token_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5438 | 0 | { |
5439 | 0 | quicly_new_token_frame_t frame; |
5440 | 0 | int ret; |
5441 | |
|
5442 | 0 | if ((ret = quicly_decode_new_token_frame(&state->src, state->end, &frame)) != 0) |
5443 | 0 | return ret; |
5444 | 0 | QUICLY_PROBE(NEW_TOKEN_RECEIVE, conn, conn->stash.now, frame.token.base, frame.token.len); |
5445 | 0 | QUICLY_LOG_CONN(new_token_receive, conn, { PTLS_LOG_ELEMENT_HEXDUMP(token, frame.token.base, frame.token.len); }); |
5446 | 0 | if (conn->super.ctx->save_resumption_token == NULL) |
5447 | 0 | return 0; |
5448 | 0 | return conn->super.ctx->save_resumption_token->cb(conn->super.ctx->save_resumption_token, conn, frame.token); |
5449 | 0 | } |
5450 | | |
5451 | | static int handle_stop_sending_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5452 | 0 | { |
5453 | 0 | quicly_stop_sending_frame_t frame; |
5454 | 0 | quicly_stream_t *stream; |
5455 | 0 | int ret; |
5456 | |
|
5457 | 0 | if ((ret = quicly_decode_stop_sending_frame(&state->src, state->end, &frame)) != 0) |
5458 | 0 | return ret; |
5459 | 0 | QUICLY_PROBE(STOP_SENDING_RECEIVE, conn, conn->stash.now, frame.stream_id, frame.app_error_code); |
5460 | 0 | QUICLY_LOG_CONN(stop_sending_receive, conn, { |
5461 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(stream_id, (quicly_stream_id_t)frame.stream_id); |
5462 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(error_code, frame.app_error_code); |
5463 | 0 | }); |
5464 | | |
5465 | 0 | if ((ret = quicly_get_or_open_stream(conn, frame.stream_id, &stream)) != 0 || stream == NULL) |
5466 | 0 | return ret; |
5467 | | |
5468 | 0 | if (quicly_sendstate_is_open(&stream->sendstate)) { |
5469 | | /* reset the stream, then notify the application */ |
5470 | 0 | int err = QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.app_error_code); |
5471 | 0 | quicly_reset_stream(stream, err); |
5472 | 0 | QUICLY_PROBE(STREAM_ON_SEND_STOP, stream->conn, stream->conn->stash.now, stream, err); |
5473 | 0 | QUICLY_LOG_CONN(stream_on_send_stop, stream->conn, { |
5474 | 0 | PTLS_LOG_ELEMENT_SIGNED(stream_id, stream->stream_id); |
5475 | 0 | PTLS_LOG_ELEMENT_SIGNED(err, err); |
5476 | 0 | }); |
5477 | 0 | stream->callbacks->on_send_stop(stream, err); |
5478 | 0 | if (stream->conn->super.state >= QUICLY_STATE_CLOSING) |
5479 | 0 | return QUICLY_ERROR_IS_CLOSING; |
5480 | 0 | } |
5481 | | |
5482 | 0 | return 0; |
5483 | 0 | } |
5484 | | |
5485 | | static int handle_max_data_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5486 | 0 | { |
5487 | 0 | quicly_max_data_frame_t frame; |
5488 | 0 | int ret; |
5489 | |
|
5490 | 0 | if ((ret = quicly_decode_max_data_frame(&state->src, state->end, &frame)) != 0) |
5491 | 0 | return ret; |
5492 | | |
5493 | 0 | QUICLY_PROBE(MAX_DATA_RECEIVE, conn, conn->stash.now, frame.max_data); |
5494 | 0 | QUICLY_LOG_CONN(max_data_receive, conn, { PTLS_LOG_ELEMENT_UNSIGNED(maximum, frame.max_data); }); |
5495 | | |
5496 | 0 | if (frame.max_data <= conn->egress.max_data.permitted) |
5497 | 0 | return 0; |
5498 | 0 | conn->egress.max_data.permitted = frame.max_data; |
5499 | 0 | conn->egress.data_blocked = QUICLY_SENDER_STATE_NONE; /* DATA_BLOCKED has not been sent for the new limit */ |
5500 | |
|
5501 | 0 | return 0; |
5502 | 0 | } |
5503 | | |
5504 | | static int negotiate_using_version(quicly_conn_t *conn, uint32_t version) |
5505 | 0 | { |
5506 | 0 | int ret; |
5507 | | |
5508 | | /* set selected version, update transport parameters extension ID */ |
5509 | 0 | conn->super.version = version; |
5510 | 0 | QUICLY_PROBE(VERSION_SWITCH, conn, conn->stash.now, version); |
5511 | 0 | QUICLY_LOG_CONN(version_switch, conn, { PTLS_LOG_ELEMENT_UNSIGNED(new_version, version); }); |
5512 | | |
5513 | | /* replace initial keys */ |
5514 | 0 | if ((ret = reinstall_initial_encryption(conn, PTLS_ERROR_LIBRARY)) != 0) |
5515 | 0 | return ret; |
5516 | | |
5517 | | /* reschedule all the packets that have been sent for immediate resend */ |
5518 | 0 | if ((ret = discard_sentmap_by_epoch(conn, ~0u)) != 0) |
5519 | 0 | return ret; |
5520 | | |
5521 | 0 | return 0; |
5522 | 0 | } |
5523 | | |
5524 | | static int handle_version_negotiation_packet(quicly_conn_t *conn, quicly_decoded_packet_t *packet) |
5525 | 0 | { |
5526 | 0 | const uint8_t *src = packet->octets.base + packet->encrypted_off, *end = packet->octets.base + packet->octets.len; |
5527 | 0 | uint32_t selected_version = 0; |
5528 | |
|
5529 | 0 | if (src == end || (end - src) % 4 != 0) |
5530 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
5531 | | |
5532 | | /* select in the precedence of V1 -> draft29 -> draft27 -> fail */ |
5533 | 0 | while (src != end) { |
5534 | 0 | uint32_t supported_version = quicly_decode32(&src); |
5535 | 0 | switch (supported_version) { |
5536 | 0 | case QUICLY_PROTOCOL_VERSION_1: |
5537 | 0 | selected_version = QUICLY_PROTOCOL_VERSION_1; |
5538 | 0 | break; |
5539 | 0 | case QUICLY_PROTOCOL_VERSION_DRAFT29: |
5540 | 0 | if (selected_version == 0 || selected_version == QUICLY_PROTOCOL_VERSION_DRAFT27) |
5541 | 0 | selected_version = QUICLY_PROTOCOL_VERSION_DRAFT29; |
5542 | 0 | break; |
5543 | 0 | case QUICLY_PROTOCOL_VERSION_DRAFT27: |
5544 | 0 | if (selected_version == 0) |
5545 | 0 | selected_version = QUICLY_PROTOCOL_VERSION_DRAFT27; |
5546 | 0 | break; |
5547 | 0 | } |
5548 | 0 | } |
5549 | 0 | if (selected_version == 0) |
5550 | 0 | return handle_close(conn, QUICLY_ERROR_NO_COMPATIBLE_VERSION, UINT64_MAX, ptls_iovec_init("", 0)); |
5551 | | |
5552 | 0 | return negotiate_using_version(conn, selected_version); |
5553 | 0 | } |
5554 | | |
5555 | | static int compare_socket_address(struct sockaddr *x, struct sockaddr *y) |
5556 | 0 | { |
5557 | 0 | #define CMP(a, b) \ |
5558 | 0 | if (a != b) \ |
5559 | 0 | return a < b ? -1 : 1 |
5560 | |
|
5561 | 0 | CMP(x->sa_family, y->sa_family); |
5562 | | |
5563 | 0 | if (x->sa_family == AF_INET) { |
5564 | 0 | struct sockaddr_in *xin = (void *)x, *yin = (void *)y; |
5565 | 0 | CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr)); |
5566 | 0 | CMP(ntohs(xin->sin_port), ntohs(yin->sin_port)); |
5567 | 0 | } else if (x->sa_family == AF_INET6) { |
5568 | 0 | struct sockaddr_in6 *xin6 = (void *)x, *yin6 = (void *)y; |
5569 | 0 | int r = memcmp(xin6->sin6_addr.s6_addr, yin6->sin6_addr.s6_addr, sizeof(xin6->sin6_addr.s6_addr)); |
5570 | 0 | if (r != 0) |
5571 | 0 | return r; |
5572 | 0 | CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port)); |
5573 | 0 | CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo); |
5574 | 0 | CMP(xin6->sin6_scope_id, yin6->sin6_scope_id); |
5575 | 0 | } else if (x->sa_family == AF_UNSPEC) { |
5576 | 0 | return 1; |
5577 | 0 | } else { |
5578 | 0 | assert(!"unknown sa_family"); |
5579 | 0 | } |
5580 | | |
5581 | 0 | #undef CMP |
5582 | 0 | return 0; |
5583 | 0 | } |
5584 | | |
5585 | | static int is_stateless_reset(quicly_conn_t *conn, quicly_decoded_packet_t *decoded) |
5586 | 0 | { |
5587 | 0 | switch (decoded->_is_stateless_reset_cached) { |
5588 | 0 | case QUICLY__DECODED_PACKET_CACHED_IS_STATELESS_RESET: |
5589 | 0 | return 1; |
5590 | 0 | case QUICLY__DECODED_PACKET_CACHED_NOT_STATELESS_RESET: |
5591 | 0 | return 0; |
5592 | 0 | default: |
5593 | 0 | break; |
5594 | 0 | } |
5595 | | |
5596 | 0 | if (!conn->super.remote.cid_set.cids[0].is_active) |
5597 | 0 | return 0; |
5598 | 0 | if (decoded->octets.len < QUICLY_STATELESS_RESET_PACKET_MIN_LEN) |
5599 | 0 | return 0; |
5600 | 0 | if (memcmp(decoded->octets.base + decoded->octets.len - QUICLY_STATELESS_RESET_TOKEN_LEN, |
5601 | 0 | conn->super.remote.cid_set.cids[0].stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN) != 0) |
5602 | 0 | return 0; |
5603 | | |
5604 | 0 | return 1; |
5605 | 0 | } |
5606 | | |
5607 | | int quicly_is_destination(quicly_conn_t *conn, struct sockaddr *dest_addr, struct sockaddr *src_addr, |
5608 | | quicly_decoded_packet_t *decoded) |
5609 | 0 | { |
5610 | 0 | if (QUICLY_PACKET_IS_LONG_HEADER(decoded->octets.base[0])) { |
5611 | | /* long header: validate address, then consult the CID */ |
5612 | 0 | if (compare_socket_address(&conn->super.remote.address.sa, src_addr) != 0) |
5613 | 0 | return 0; |
5614 | 0 | if (conn->super.local.address.sa.sa_family != AF_UNSPEC && |
5615 | 0 | compare_socket_address(&conn->super.local.address.sa, dest_addr) != 0) |
5616 | 0 | return 0; |
5617 | | /* server may see the CID generated by the client for Initial and 0-RTT packets */ |
5618 | 0 | if (!quicly_is_client(conn) && decoded->cid.dest.might_be_client_generated) { |
5619 | 0 | const quicly_cid_t *odcid = is_retry(conn) ? &conn->retry_scid : &conn->super.original_dcid; |
5620 | 0 | if (quicly_cid_is_equal(odcid, decoded->cid.dest.encrypted)) |
5621 | 0 | goto Found; |
5622 | 0 | } |
5623 | 0 | } |
5624 | | |
5625 | 0 | if (conn->super.ctx->cid_encryptor != NULL) { |
5626 | | /* Note on multiple CIDs |
5627 | | * Multiple CIDs issued by this host are always based on the same 3-tuple (master_id, thread_id, node_id) |
5628 | | * and the only difference is path_id. Therefore comparing the 3-tuple is enough to cover all CIDs issued by |
5629 | | * this host. |
5630 | | */ |
5631 | 0 | if (conn->super.local.cid_set.plaintext.master_id == decoded->cid.dest.plaintext.master_id && |
5632 | 0 | conn->super.local.cid_set.plaintext.thread_id == decoded->cid.dest.plaintext.thread_id && |
5633 | 0 | conn->super.local.cid_set.plaintext.node_id == decoded->cid.dest.plaintext.node_id) |
5634 | 0 | goto Found; |
5635 | 0 | if (is_stateless_reset(conn, decoded)) |
5636 | 0 | goto Found_StatelessReset; |
5637 | 0 | } else { |
5638 | 0 | if (compare_socket_address(&conn->super.remote.address.sa, src_addr) == 0) |
5639 | 0 | goto Found; |
5640 | 0 | if (conn->super.local.address.sa.sa_family != AF_UNSPEC && |
5641 | 0 | compare_socket_address(&conn->super.local.address.sa, dest_addr) != 0) |
5642 | 0 | return 0; |
5643 | 0 | } |
5644 | | |
5645 | | /* not found */ |
5646 | 0 | return 0; |
5647 | | |
5648 | 0 | Found: |
5649 | 0 | decoded->_is_stateless_reset_cached = QUICLY__DECODED_PACKET_CACHED_NOT_STATELESS_RESET; |
5650 | 0 | return 1; |
5651 | | |
5652 | 0 | Found_StatelessReset: |
5653 | 0 | decoded->_is_stateless_reset_cached = QUICLY__DECODED_PACKET_CACHED_IS_STATELESS_RESET; |
5654 | 0 | return 1; |
5655 | 0 | } |
5656 | | |
5657 | | int handle_close(quicly_conn_t *conn, int err, uint64_t frame_type, ptls_iovec_t reason_phrase) |
5658 | 0 | { |
5659 | 0 | int ret; |
5660 | |
|
5661 | 0 | if (conn->super.state >= QUICLY_STATE_CLOSING) |
5662 | 0 | return 0; |
5663 | | |
5664 | | /* switch to closing state, notify the app (at this moment the streams are accessible), then destroy the streams */ |
5665 | 0 | if ((ret = enter_close(conn, 0, |
5666 | 0 | !(err == QUICLY_ERROR_RECEIVED_STATELESS_RESET || err == QUICLY_ERROR_NO_COMPATIBLE_VERSION))) != 0) |
5667 | 0 | return ret; |
5668 | 0 | if (conn->super.ctx->closed_by_remote != NULL) |
5669 | 0 | conn->super.ctx->closed_by_remote->cb(conn->super.ctx->closed_by_remote, conn, err, frame_type, |
5670 | 0 | (const char *)reason_phrase.base, reason_phrase.len); |
5671 | 0 | destroy_all_streams(conn, err, 0); |
5672 | |
|
5673 | 0 | return 0; |
5674 | 0 | } |
5675 | | |
5676 | | static int handle_transport_close_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5677 | 0 | { |
5678 | 0 | quicly_transport_close_frame_t frame; |
5679 | 0 | int ret; |
5680 | |
|
5681 | 0 | if ((ret = quicly_decode_transport_close_frame(&state->src, state->end, &frame)) != 0) |
5682 | 0 | return ret; |
5683 | | |
5684 | 0 | QUICLY_PROBE(TRANSPORT_CLOSE_RECEIVE, conn, conn->stash.now, frame.error_code, frame.frame_type, |
5685 | 0 | QUICLY_PROBE_ESCAPE_UNSAFE_STRING(frame.reason_phrase.base, frame.reason_phrase.len)); |
5686 | 0 | QUICLY_LOG_CONN(transport_close_receive, conn, { |
5687 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(error_code, frame.error_code); |
5688 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(frame_type, frame.frame_type); |
5689 | 0 | PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); |
5690 | 0 | }); |
5691 | 0 | return handle_close(conn, QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(frame.error_code), frame.frame_type, frame.reason_phrase); |
5692 | 0 | } |
5693 | | |
5694 | | static int handle_application_close_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5695 | 0 | { |
5696 | 0 | quicly_application_close_frame_t frame; |
5697 | 0 | int ret; |
5698 | |
|
5699 | 0 | if ((ret = quicly_decode_application_close_frame(&state->src, state->end, &frame)) != 0) |
5700 | 0 | return ret; |
5701 | | |
5702 | 0 | QUICLY_PROBE(APPLICATION_CLOSE_RECEIVE, conn, conn->stash.now, frame.error_code, |
5703 | 0 | QUICLY_PROBE_ESCAPE_UNSAFE_STRING(frame.reason_phrase.base, frame.reason_phrase.len)); |
5704 | 0 | QUICLY_LOG_CONN(application_close_receive, conn, { |
5705 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(error_code, frame.error_code); |
5706 | 0 | PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); |
5707 | 0 | }); |
5708 | 0 | return handle_close(conn, QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(frame.error_code), UINT64_MAX, frame.reason_phrase); |
5709 | 0 | } |
5710 | | |
5711 | | static int handle_padding_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5712 | 0 | { |
5713 | 0 | return 0; |
5714 | 0 | } |
5715 | | |
5716 | | static int handle_ping_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5717 | 0 | { |
5718 | 0 | QUICLY_PROBE(PING_RECEIVE, conn, conn->stash.now); |
5719 | 0 | QUICLY_LOG_CONN(ping_receive, conn, {}); |
5720 | | |
5721 | 0 | return 0; |
5722 | 0 | } |
5723 | | |
5724 | | static int handle_new_connection_id_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5725 | 0 | { |
5726 | 0 | int ret; |
5727 | 0 | quicly_new_connection_id_frame_t frame; |
5728 | | |
5729 | | /* TODO: return error when using zero-length CID */ |
5730 | |
|
5731 | 0 | if ((ret = quicly_decode_new_connection_id_frame(&state->src, state->end, &frame)) != 0) |
5732 | 0 | return ret; |
5733 | | |
5734 | 0 | QUICLY_PROBE(NEW_CONNECTION_ID_RECEIVE, conn, conn->stash.now, frame.sequence, frame.retire_prior_to, |
5735 | 0 | QUICLY_PROBE_HEXDUMP(frame.cid.base, frame.cid.len), |
5736 | 0 | QUICLY_PROBE_HEXDUMP(frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN)); |
5737 | 0 | QUICLY_LOG_CONN(new_connection_id_receive, conn, { |
5738 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); |
5739 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(retire_prior_to, frame.retire_prior_to); |
5740 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(cid, frame.cid.base, frame.cid.len); |
5741 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(stateless_reset_token, frame.stateless_reset_token, QUICLY_STATELESS_RESET_TOKEN_LEN); |
5742 | 0 | }); |
5743 | | |
5744 | 0 | if (frame.sequence < conn->super.remote.largest_retire_prior_to) { |
5745 | | /* An endpoint that receives a NEW_CONNECTION_ID frame with a sequence number smaller than the Retire Prior To |
5746 | | * field of a previously received NEW_CONNECTION_ID frame MUST send a corresponding RETIRE_CONNECTION_ID frame |
5747 | | * that retires the newly received connection ID, unless it has already done so for that sequence number. (19.15) |
5748 | | * TODO: "unless ..." part may not be properly addressed here (we may already have sent the RCID frame for this |
5749 | | * sequence) */ |
5750 | 0 | schedule_retire_connection_id_frame(conn, frame.sequence); |
5751 | | /* do not install this CID */ |
5752 | 0 | return 0; |
5753 | 0 | } |
5754 | | |
5755 | 0 | uint64_t unregistered_seqs[QUICLY_LOCAL_ACTIVE_CONNECTION_ID_LIMIT]; |
5756 | 0 | size_t num_unregistered_seqs; |
5757 | 0 | if ((ret = quicly_remote_cid_register(&conn->super.remote.cid_set, frame.sequence, frame.cid.base, frame.cid.len, |
5758 | 0 | frame.stateless_reset_token, frame.retire_prior_to, unregistered_seqs, |
5759 | 0 | &num_unregistered_seqs)) != 0) |
5760 | 0 | return ret; |
5761 | | |
5762 | 0 | for (size_t i = 0; i < num_unregistered_seqs; i++) |
5763 | 0 | schedule_retire_connection_id_frame(conn, unregistered_seqs[i]); |
5764 | |
|
5765 | 0 | if (frame.retire_prior_to > conn->super.remote.largest_retire_prior_to) |
5766 | 0 | conn->super.remote.largest_retire_prior_to = frame.retire_prior_to; |
5767 | |
|
5768 | 0 | return 0; |
5769 | 0 | } |
5770 | | |
5771 | | static int handle_retire_connection_id_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5772 | 0 | { |
5773 | 0 | int ret, has_pending; |
5774 | 0 | quicly_retire_connection_id_frame_t frame; |
5775 | |
|
5776 | 0 | if ((ret = quicly_decode_retire_connection_id_frame(&state->src, state->end, &frame)) != 0) |
5777 | 0 | return ret; |
5778 | | |
5779 | 0 | QUICLY_PROBE(RETIRE_CONNECTION_ID_RECEIVE, conn, conn->stash.now, frame.sequence); |
5780 | 0 | QUICLY_LOG_CONN(retire_connection_id_receive, conn, { PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); }); |
5781 | | |
5782 | 0 | if (frame.sequence >= conn->super.local.cid_set.plaintext.path_id) { |
5783 | | /* Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number greater than any previously sent to the remote peer |
5784 | | * MUST be treated as a connection error of type PROTOCOL_VIOLATION. (19.16) */ |
5785 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
5786 | 0 | } |
5787 | | |
5788 | 0 | if ((ret = quicly_local_cid_retire(&conn->super.local.cid_set, frame.sequence, &has_pending)) != 0) |
5789 | 0 | return ret; |
5790 | 0 | if (has_pending) |
5791 | 0 | conn->egress.pending_flows |= QUICLY_PENDING_FLOW_CID_FRAME_BIT; |
5792 | |
|
5793 | 0 | return 0; |
5794 | 0 | } |
5795 | | |
5796 | | static int handle_handshake_done_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5797 | 0 | { |
5798 | 0 | int ret; |
5799 | |
|
5800 | 0 | QUICLY_PROBE(HANDSHAKE_DONE_RECEIVE, conn, conn->stash.now); |
5801 | 0 | QUICLY_LOG_CONN(handshake_done_receive, conn, {}); |
5802 | | |
5803 | 0 | if (!quicly_is_client(conn)) |
5804 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
5805 | | |
5806 | 0 | assert(conn->initial == NULL); |
5807 | 0 | if (conn->handshake == NULL) |
5808 | 0 | return 0; |
5809 | | |
5810 | 0 | conn->super.remote.address_validation.send_probe = 0; |
5811 | 0 | if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_HANDSHAKE)) != 0) |
5812 | 0 | return ret; |
5813 | 0 | setup_next_send(conn); |
5814 | 0 | return 0; |
5815 | 0 | } |
5816 | | |
5817 | | static int handle_datagram_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5818 | 0 | { |
5819 | 0 | quicly_datagram_frame_t frame; |
5820 | 0 | int ret; |
5821 | | |
5822 | | /* check if we advertised support for DATAGRAM frames on this connection */ |
5823 | 0 | if (conn->super.ctx->transport_params.max_datagram_frame_size == 0) |
5824 | 0 | return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; |
5825 | | |
5826 | | /* decode the frame */ |
5827 | 0 | if ((ret = quicly_decode_datagram_frame(state->frame_type, &state->src, state->end, &frame)) != 0) |
5828 | 0 | return ret; |
5829 | 0 | QUICLY_PROBE(DATAGRAM_RECEIVE, conn, conn->stash.now, frame.payload.base, frame.payload.len); |
5830 | 0 | QUICLY_LOG_CONN(datagram_receive, conn, { PTLS_LOG_ELEMENT_UNSIGNED(payload_len, frame.payload.len); }); |
5831 | | |
5832 | | /* handle the frame. Applications might call quicly_close or other functions that modify the connection state. */ |
5833 | 0 | conn->super.ctx->receive_datagram_frame->cb(conn->super.ctx->receive_datagram_frame, conn, frame.payload); |
5834 | |
|
5835 | 0 | return 0; |
5836 | 0 | } |
5837 | | |
5838 | | static int handle_ack_frequency_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) |
5839 | 0 | { |
5840 | 0 | quicly_ack_frequency_frame_t frame; |
5841 | 0 | int ret; |
5842 | | |
5843 | | /* recognize the frame only when the support has been advertised */ |
5844 | 0 | if (conn->super.ctx->transport_params.min_ack_delay_usec == UINT64_MAX) |
5845 | 0 | return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; |
5846 | | |
5847 | 0 | if ((ret = quicly_decode_ack_frequency_frame(&state->src, state->end, &frame)) != 0) |
5848 | 0 | return ret; |
5849 | | |
5850 | 0 | QUICLY_PROBE(ACK_FREQUENCY_RECEIVE, conn, conn->stash.now, frame.sequence, frame.packet_tolerance, frame.max_ack_delay, |
5851 | 0 | (int)frame.ignore_order, (int)frame.ignore_ce); |
5852 | 0 | QUICLY_LOG_CONN(ack_frequency_receive, conn, { |
5853 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(sequence, frame.sequence); |
5854 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(packet_tolerance, frame.packet_tolerance); |
5855 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(max_ack_delay, frame.max_ack_delay); |
5856 | 0 | PTLS_LOG_ELEMENT_SIGNED(ignore_order, (int)frame.ignore_order); |
5857 | 0 | PTLS_LOG_ELEMENT_SIGNED(ignore_ce, (int)frame.ignore_ce); |
5858 | 0 | }); |
5859 | | |
5860 | | /* Reject Request Max Ack Delay below our TP.min_ack_delay (which is at the moment equal to LOCAL_MAX_ACK_DELAY). */ |
5861 | 0 | if (frame.max_ack_delay < QUICLY_LOCAL_MAX_ACK_DELAY * 1000) |
5862 | 0 | return QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
5863 | | |
5864 | 0 | if (frame.sequence >= conn->ingress.ack_frequency.next_sequence) { |
5865 | 0 | conn->ingress.ack_frequency.next_sequence = frame.sequence + 1; |
5866 | 0 | conn->application->super.packet_tolerance = |
5867 | 0 | (uint32_t)(frame.packet_tolerance < QUICLY_MAX_PACKET_TOLERANCE ? frame.packet_tolerance : QUICLY_MAX_PACKET_TOLERANCE); |
5868 | 0 | conn->application->super.ignore_order = frame.ignore_order; |
5869 | 0 | } |
5870 | |
|
5871 | 0 | return 0; |
5872 | 0 | } |
5873 | | |
5874 | | static int handle_payload(quicly_conn_t *conn, size_t epoch, const uint8_t *_src, size_t _len, uint64_t *offending_frame_type, |
5875 | | int *is_ack_only) |
5876 | 0 | { |
5877 | | /* clang-format off */ |
5878 | | |
5879 | | /* `frame_handlers` is an array of frame handlers and the properties of the frames, indexed by the ID of the frame. */ |
5880 | 0 | static const struct st_quicly_frame_handler_t { |
5881 | 0 | int (*cb)(quicly_conn_t *, struct st_quicly_handle_payload_state_t *); /* callback function that handles the frame */ |
5882 | 0 | uint8_t permitted_epochs; /* the epochs the frame can appear, calculated as bitwise-or of `1 << epoch` */ |
5883 | 0 | uint8_t ack_eliciting; /* boolean indicating if the frame is ack-eliciting */ |
5884 | 0 | size_t counter_offset; /* offset of corresponding `conn->super.stats.num_frames_received.type` within quicly_conn_t */ |
5885 | 0 | } frame_handlers[] = { |
5886 | 0 | #define FRAME(n, i, z, h, o, ae) \ |
5887 | 0 | { \ |
5888 | 0 | handle_##n##_frame, \ |
5889 | 0 | (i << QUICLY_EPOCH_INITIAL) | (z << QUICLY_EPOCH_0RTT) | (h << QUICLY_EPOCH_HANDSHAKE) | (o << QUICLY_EPOCH_1RTT), \ |
5890 | 0 | ae, \ |
5891 | 0 | offsetof(quicly_conn_t, super.stats.num_frames_received.n) \ |
5892 | 0 | } |
5893 | | /* +----------------------+-------------------+---------------+ |
5894 | | * | | permitted epochs | | |
5895 | | * | frame +----+----+----+----+ ack-eliciting | |
5896 | | * | | IN | 0R | HS | 1R | | |
5897 | | * +----------------------+----+----+----+----+---------------+ */ |
5898 | 0 | FRAME( padding , 1 , 1 , 1 , 1 , 0 ), /* 0 */ |
5899 | 0 | FRAME( ping , 1 , 1 , 1 , 1 , 1 ), |
5900 | 0 | FRAME( ack , 1 , 0 , 1 , 1 , 0 ), |
5901 | 0 | FRAME( ack , 1 , 0 , 1 , 1 , 0 ), |
5902 | 0 | FRAME( reset_stream , 0 , 1 , 0 , 1 , 1 ), |
5903 | 0 | FRAME( stop_sending , 0 , 1 , 0 , 1 , 1 ), |
5904 | 0 | FRAME( crypto , 1 , 0 , 1 , 1 , 1 ), |
5905 | 0 | FRAME( new_token , 0 , 0 , 0 , 1 , 1 ), |
5906 | 0 | FRAME( stream , 0 , 1 , 0 , 1 , 1 ), /* 8 */ |
5907 | 0 | FRAME( stream , 0 , 1 , 0 , 1 , 1 ), |
5908 | 0 | FRAME( stream , 0 , 1 , 0 , 1 , 1 ), |
5909 | 0 | FRAME( stream , 0 , 1 , 0 , 1 , 1 ), |
5910 | 0 | FRAME( stream , 0 , 1 , 0 , 1 , 1 ), |
5911 | 0 | FRAME( stream , 0 , 1 , 0 , 1 , 1 ), |
5912 | 0 | FRAME( stream , 0 , 1 , 0 , 1 , 1 ), |
5913 | 0 | FRAME( stream , 0 , 1 , 0 , 1 , 1 ), |
5914 | 0 | FRAME( max_data , 0 , 1 , 0 , 1 , 1 ), /* 16 */ |
5915 | 0 | FRAME( max_stream_data , 0 , 1 , 0 , 1 , 1 ), |
5916 | 0 | FRAME( max_streams_bidi , 0 , 1 , 0 , 1 , 1 ), |
5917 | 0 | FRAME( max_streams_uni , 0 , 1 , 0 , 1 , 1 ), |
5918 | 0 | FRAME( data_blocked , 0 , 1 , 0 , 1 , 1 ), |
5919 | 0 | FRAME( stream_data_blocked , 0 , 1 , 0 , 1 , 1 ), |
5920 | 0 | FRAME( streams_blocked , 0 , 1 , 0 , 1 , 1 ), |
5921 | 0 | FRAME( streams_blocked , 0 , 1 , 0 , 1 , 1 ), |
5922 | 0 | FRAME( new_connection_id , 0 , 1 , 0 , 1 , 1 ), /* 24 */ |
5923 | 0 | FRAME( retire_connection_id , 0 , 0 , 0 , 1 , 1 ), |
5924 | 0 | FRAME( path_challenge , 0 , 1 , 0 , 1 , 1 ), |
5925 | 0 | FRAME( path_response , 0 , 0 , 0 , 1 , 1 ), |
5926 | 0 | FRAME( transport_close , 1 , 1 , 1 , 1 , 0 ), |
5927 | 0 | FRAME( application_close , 0 , 1 , 0 , 1 , 0 ), |
5928 | 0 | FRAME( handshake_done , 0, 0 , 0 , 1 , 1 ), |
5929 | | /* +----------------------+----+----+----+----+---------------+ */ |
5930 | 0 | #undef FRAME |
5931 | 0 | }; |
5932 | 0 | static const struct { |
5933 | 0 | uint64_t type; |
5934 | 0 | struct st_quicly_frame_handler_t _; |
5935 | 0 | } ex_frame_handlers[] = { |
5936 | 0 | #define FRAME(uc, lc, i, z, h, o, ae) \ |
5937 | 0 | { \ |
5938 | 0 | QUICLY_FRAME_TYPE_##uc, \ |
5939 | 0 | { \ |
5940 | 0 | handle_##lc##_frame, \ |
5941 | 0 | (i << QUICLY_EPOCH_INITIAL) | (z << QUICLY_EPOCH_0RTT) | (h << QUICLY_EPOCH_HANDSHAKE) | (o << QUICLY_EPOCH_1RTT), \ |
5942 | 0 | ae, \ |
5943 | 0 | offsetof(quicly_conn_t, super.stats.num_frames_received.lc) \ |
5944 | 0 | }, \ |
5945 | 0 | } |
5946 | | /* +----------------------------------+-------------------+---------------+ |
5947 | | * | frame | permitted epochs | | |
5948 | | * |------------------+---------------+----+----+----+----+ ack-eliciting | |
5949 | | * | upper-case | lower-case | IN | 0R | HS | 1R | | |
5950 | | * +------------------+---------------+----+----+----+----+---------------+ */ |
5951 | 0 | FRAME( DATAGRAM_NOLEN , datagram , 0 , 1, 0, 1 , 1 ), |
5952 | 0 | FRAME( DATAGRAM_WITHLEN , datagram , 0 , 1, 0, 1 , 1 ), |
5953 | 0 | FRAME( ACK_FREQUENCY , ack_frequency , 0 , 0 , 0 , 1 , 1 ), |
5954 | | /* +------------------+---------------+-------------------+---------------+ */ |
5955 | 0 | #undef FRAME |
5956 | 0 | {UINT64_MAX}, |
5957 | 0 | }; |
5958 | | /* clang-format on */ |
5959 | |
|
5960 | 0 | struct st_quicly_handle_payload_state_t state = {_src, _src + _len, epoch}; |
5961 | 0 | size_t num_frames_ack_eliciting = 0; |
5962 | 0 | int ret; |
5963 | |
|
5964 | 0 | do { |
5965 | | /* determine the frame type; fast path is available for frame types below 64 */ |
5966 | 0 | const struct st_quicly_frame_handler_t *frame_handler; |
5967 | 0 | state.frame_type = *state.src++; |
5968 | 0 | if (state.frame_type < PTLS_ELEMENTSOF(frame_handlers)) { |
5969 | 0 | frame_handler = frame_handlers + state.frame_type; |
5970 | 0 | } else { |
5971 | | /* slow path */ |
5972 | 0 | --state.src; |
5973 | 0 | if ((state.frame_type = quicly_decodev(&state.src, state.end)) == UINT64_MAX) { |
5974 | 0 | state.frame_type = |
5975 | 0 | QUICLY_FRAME_TYPE_PADDING; /* we cannot signal the offending frame type when failing to decode the frame type */ |
5976 | 0 | ret = QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; |
5977 | 0 | break; |
5978 | 0 | } |
5979 | 0 | size_t i; |
5980 | 0 | for (i = 0; ex_frame_handlers[i].type < state.frame_type; ++i) |
5981 | 0 | ; |
5982 | 0 | if (ex_frame_handlers[i].type != state.frame_type) { |
5983 | 0 | ret = QUICLY_TRANSPORT_ERROR_FRAME_ENCODING; /* not found */ |
5984 | 0 | break; |
5985 | 0 | } |
5986 | 0 | frame_handler = &ex_frame_handlers[i]._; |
5987 | 0 | } |
5988 | | /* check if frame is allowed, then process */ |
5989 | 0 | if ((frame_handler->permitted_epochs & (1 << epoch)) == 0) { |
5990 | 0 | ret = QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
5991 | 0 | break; |
5992 | 0 | } |
5993 | 0 | ++*(uint64_t *)((uint8_t *)conn + frame_handler->counter_offset); |
5994 | 0 | num_frames_ack_eliciting += frame_handler->ack_eliciting; |
5995 | 0 | if ((ret = frame_handler->cb(conn, &state)) != 0) |
5996 | 0 | break; |
5997 | 0 | } while (state.src != state.end); |
5998 | | |
5999 | 0 | *is_ack_only = num_frames_ack_eliciting == 0; |
6000 | 0 | if (ret != 0) |
6001 | 0 | *offending_frame_type = state.frame_type; |
6002 | 0 | return ret; |
6003 | 0 | } |
6004 | | |
6005 | | static int handle_stateless_reset(quicly_conn_t *conn) |
6006 | 0 | { |
6007 | 0 | QUICLY_PROBE(STATELESS_RESET_RECEIVE, conn, conn->stash.now); |
6008 | 0 | QUICLY_LOG_CONN(stateless_reset_receive, conn, {}); |
6009 | 0 | return handle_close(conn, QUICLY_ERROR_RECEIVED_STATELESS_RESET, UINT64_MAX, ptls_iovec_init("", 0)); |
6010 | 0 | } |
6011 | | |
6012 | | static int validate_retry_tag(quicly_decoded_packet_t *packet, quicly_cid_t *odcid, ptls_aead_context_t *retry_aead) |
6013 | 0 | { |
6014 | 0 | size_t pseudo_packet_len = 1 + odcid->len + packet->encrypted_off; |
6015 | 0 | uint8_t pseudo_packet[pseudo_packet_len]; |
6016 | 0 | pseudo_packet[0] = odcid->len; |
6017 | 0 | memcpy(pseudo_packet + 1, odcid->cid, odcid->len); |
6018 | 0 | memcpy(pseudo_packet + 1 + odcid->len, packet->octets.base, packet->encrypted_off); |
6019 | 0 | return ptls_aead_decrypt(retry_aead, packet->octets.base + packet->encrypted_off, packet->octets.base + packet->encrypted_off, |
6020 | 0 | PTLS_AESGCM_TAG_SIZE, 0, pseudo_packet, pseudo_packet_len) == 0; |
6021 | 0 | } |
6022 | | |
6023 | | int quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr *dest_addr, struct sockaddr *src_addr, |
6024 | | quicly_decoded_packet_t *packet, quicly_address_token_plaintext_t *address_token, |
6025 | | const quicly_cid_plaintext_t *new_cid, ptls_handshake_properties_t *handshake_properties, void *appdata) |
6026 | 0 | { |
6027 | 0 | const struct st_ptls_salt_t *salt; |
6028 | 0 | struct { |
6029 | 0 | struct st_quicly_cipher_context_t ingress, egress; |
6030 | 0 | int alive; |
6031 | 0 | } cipher = {}; |
6032 | 0 | ptls_iovec_t payload; |
6033 | 0 | uint64_t next_expected_pn, pn, offending_frame_type = QUICLY_FRAME_TYPE_PADDING; |
6034 | 0 | int is_ack_only, ret; |
6035 | |
|
6036 | 0 | *conn = NULL; |
6037 | | |
6038 | | /* process initials only */ |
6039 | 0 | if ((packet->octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) != QUICLY_PACKET_TYPE_INITIAL) { |
6040 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6041 | 0 | goto Exit; |
6042 | 0 | } |
6043 | 0 | if ((salt = get_salt(packet->version)) == NULL) { |
6044 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6045 | 0 | goto Exit; |
6046 | 0 | } |
6047 | 0 | if (packet->datagram_size < QUICLY_MIN_CLIENT_INITIAL_SIZE) { |
6048 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6049 | 0 | goto Exit; |
6050 | 0 | } |
6051 | 0 | if (packet->cid.dest.encrypted.len < 8) { |
6052 | 0 | ret = QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION; |
6053 | 0 | goto Exit; |
6054 | 0 | } |
6055 | 0 | if ((ret = setup_initial_encryption(get_aes128gcmsha256(ctx), &cipher.ingress, &cipher.egress, packet->cid.dest.encrypted, 0, |
6056 | 0 | ptls_iovec_init(salt->initial, sizeof(salt->initial)), NULL)) != 0) |
6057 | 0 | goto Exit; |
6058 | 0 | cipher.alive = 1; |
6059 | 0 | next_expected_pn = 0; /* is this correct? do we need to take care of underflow? */ |
6060 | 0 | if ((ret = decrypt_packet(cipher.ingress.header_protection, aead_decrypt_fixed_key, cipher.ingress.aead, &next_expected_pn, |
6061 | 0 | packet, &pn, &payload)) != 0) { |
6062 | 0 | ret = QUICLY_ERROR_DECRYPTION_FAILED; |
6063 | 0 | goto Exit; |
6064 | 0 | } |
6065 | | |
6066 | | /* create connection */ |
6067 | 0 | if ((*conn = create_connection( |
6068 | 0 | ctx, packet->version, NULL, src_addr, dest_addr, &packet->cid.src, new_cid, handshake_properties, appdata, |
6069 | 0 | quicly_cc_calc_initial_cwnd(ctx->initcwnd_packets, ctx->transport_params.max_udp_payload_size))) == NULL) { |
6070 | 0 | ret = PTLS_ERROR_NO_MEMORY; |
6071 | 0 | goto Exit; |
6072 | 0 | } |
6073 | 0 | (*conn)->super.state = QUICLY_STATE_ACCEPTING; |
6074 | 0 | quicly_set_cid(&(*conn)->super.original_dcid, packet->cid.dest.encrypted); |
6075 | 0 | if (address_token != NULL) { |
6076 | 0 | (*conn)->super.remote.address_validation.validated = 1; |
6077 | 0 | if (address_token->type == QUICLY_ADDRESS_TOKEN_TYPE_RETRY) { |
6078 | 0 | (*conn)->retry_scid = (*conn)->super.original_dcid; |
6079 | 0 | (*conn)->super.original_dcid = address_token->retry.original_dcid; |
6080 | 0 | } |
6081 | 0 | } |
6082 | 0 | if ((ret = setup_handshake_space_and_flow(*conn, QUICLY_EPOCH_INITIAL)) != 0) |
6083 | 0 | goto Exit; |
6084 | 0 | (*conn)->initial->super.next_expected_packet_number = next_expected_pn; |
6085 | 0 | (*conn)->initial->cipher.ingress = cipher.ingress; |
6086 | 0 | (*conn)->initial->cipher.egress = cipher.egress; |
6087 | 0 | cipher.alive = 0; |
6088 | 0 | (*conn)->crypto.handshake_properties.collected_extensions = server_collected_extensions; |
6089 | 0 | (*conn)->initial->largest_ingress_udp_payload_size = packet->datagram_size; |
6090 | |
|
6091 | 0 | QUICLY_PROBE(ACCEPT, *conn, (*conn)->stash.now, |
6092 | 0 | QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), address_token); |
6093 | 0 | QUICLY_LOG_CONN(accept, *conn, { |
6094 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); |
6095 | 0 | PTLS_LOG_ELEMENT_PTR(address_token, address_token); |
6096 | 0 | }); |
6097 | 0 | QUICLY_PROBE(PACKET_RECEIVED, *conn, (*conn)->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); |
6098 | 0 | QUICLY_LOG_CONN(packet_received, *conn, { |
6099 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(pn, pn); |
6100 | 0 | PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(decrypted, payload.base, payload.len); |
6101 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); |
6102 | 0 | }); |
6103 | | |
6104 | | /* handle the input; we ignore is_ack_only, we consult if there's any output from TLS in response to CH anyways */ |
6105 | 0 | (*conn)->super.stats.num_packets.received += 1; |
6106 | 0 | (*conn)->super.stats.num_bytes.received += packet->datagram_size; |
6107 | 0 | if ((ret = handle_payload(*conn, QUICLY_EPOCH_INITIAL, payload.base, payload.len, &offending_frame_type, &is_ack_only)) != 0) |
6108 | 0 | goto Exit; |
6109 | 0 | if ((ret = record_receipt(&(*conn)->initial->super, pn, 0, (*conn)->stash.now, &(*conn)->egress.send_ack_at)) != 0) |
6110 | 0 | goto Exit; |
6111 | | |
6112 | 0 | Exit: |
6113 | 0 | if (*conn != NULL) { |
6114 | 0 | if (ret == 0) { |
6115 | 0 | (*conn)->super.state = QUICLY_STATE_CONNECTED; |
6116 | 0 | } else { |
6117 | 0 | initiate_close(*conn, ret, offending_frame_type, ""); |
6118 | 0 | ret = 0; |
6119 | 0 | } |
6120 | 0 | unlock_now(*conn); |
6121 | 0 | } |
6122 | 0 | if (cipher.alive) { |
6123 | 0 | dispose_cipher(&cipher.ingress); |
6124 | 0 | dispose_cipher(&cipher.egress); |
6125 | 0 | } |
6126 | 0 | return ret; |
6127 | 0 | } |
6128 | | |
6129 | | int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct sockaddr *src_addr, quicly_decoded_packet_t *packet) |
6130 | 0 | { |
6131 | 0 | ptls_cipher_context_t *header_protection; |
6132 | 0 | struct { |
6133 | 0 | int (*cb)(void *, uint64_t, quicly_decoded_packet_t *, size_t, size_t *); |
6134 | 0 | void *ctx; |
6135 | 0 | } aead; |
6136 | 0 | struct st_quicly_pn_space_t **space; |
6137 | 0 | size_t epoch; |
6138 | 0 | ptls_iovec_t payload; |
6139 | 0 | uint64_t pn, offending_frame_type = QUICLY_FRAME_TYPE_PADDING; |
6140 | 0 | int is_ack_only, ret; |
6141 | |
|
6142 | 0 | assert(src_addr->sa_family == AF_INET || src_addr->sa_family == AF_INET6); |
6143 | | |
6144 | 0 | lock_now(conn, 0); |
6145 | |
|
6146 | 0 | QUICLY_PROBE(RECEIVE, conn, conn->stash.now, |
6147 | 0 | QUICLY_PROBE_HEXDUMP(packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len), packet->octets.base, |
6148 | 0 | packet->octets.len); |
6149 | 0 | QUICLY_LOG_CONN(receive, conn, { |
6150 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(dcid, packet->cid.dest.encrypted.base, packet->cid.dest.encrypted.len); |
6151 | 0 | PTLS_LOG_ELEMENT_HEXDUMP(bytes, packet->octets.base, packet->octets.len); |
6152 | 0 | }); |
6153 | | |
6154 | 0 | if (is_stateless_reset(conn, packet)) { |
6155 | 0 | ret = handle_stateless_reset(conn); |
6156 | 0 | goto Exit; |
6157 | 0 | } |
6158 | | |
6159 | | /* FIXME check peer address */ |
6160 | | |
6161 | | /* add unconditionally, as packet->datagram_size is set only for the first packet within the UDP datagram */ |
6162 | 0 | conn->super.stats.num_bytes.received += packet->datagram_size; |
6163 | |
|
6164 | 0 | switch (conn->super.state) { |
6165 | 0 | case QUICLY_STATE_CLOSING: |
6166 | 0 | ++conn->egress.connection_close.num_packets_received; |
6167 | | /* respond with a CONNECTION_CLOSE frame using exponential back-off */ |
6168 | 0 | if (__builtin_popcountl(conn->egress.connection_close.num_packets_received) == 1) |
6169 | 0 | conn->egress.send_ack_at = 0; |
6170 | 0 | ret = 0; |
6171 | 0 | goto Exit; |
6172 | 0 | case QUICLY_STATE_DRAINING: |
6173 | 0 | ret = 0; |
6174 | 0 | goto Exit; |
6175 | 0 | default: |
6176 | 0 | break; |
6177 | 0 | } |
6178 | | |
6179 | 0 | if (QUICLY_PACKET_IS_LONG_HEADER(packet->octets.base[0])) { |
6180 | 0 | if (conn->super.state == QUICLY_STATE_FIRSTFLIGHT) { |
6181 | 0 | if (packet->version == 0) { |
6182 | 0 | ret = handle_version_negotiation_packet(conn, packet); |
6183 | 0 | goto Exit; |
6184 | 0 | } |
6185 | 0 | } |
6186 | 0 | if (packet->version != conn->super.version) { |
6187 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6188 | 0 | goto Exit; |
6189 | 0 | } |
6190 | 0 | switch (packet->octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) { |
6191 | 0 | case QUICLY_PACKET_TYPE_RETRY: { |
6192 | 0 | assert(packet->encrypted_off + PTLS_AESGCM_TAG_SIZE == packet->octets.len); |
6193 | | /* handle only if the connection is the client */ |
6194 | 0 | if (!quicly_is_client(conn)) { |
6195 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6196 | 0 | goto Exit; |
6197 | 0 | } |
6198 | | /* server CID has to change */ |
6199 | 0 | if (quicly_cid_is_equal(&conn->super.remote.cid_set.cids[0].cid, packet->cid.src)) { |
6200 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6201 | 0 | goto Exit; |
6202 | 0 | } |
6203 | | /* do not accept a second Retry */ |
6204 | 0 | if (is_retry(conn)) { |
6205 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6206 | 0 | goto Exit; |
6207 | 0 | } |
6208 | 0 | ptls_aead_context_t *retry_aead = create_retry_aead(conn->super.ctx, conn->super.version, 0); |
6209 | 0 | int retry_ok = validate_retry_tag(packet, &conn->super.remote.cid_set.cids[0].cid, retry_aead); |
6210 | 0 | ptls_aead_free(retry_aead); |
6211 | 0 | if (!retry_ok) { |
6212 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6213 | 0 | goto Exit; |
6214 | 0 | } |
6215 | | /* check size of the Retry packet */ |
6216 | 0 | if (packet->token.len > QUICLY_MAX_TOKEN_LEN) { |
6217 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; /* TODO this is a immediate fatal error, chose a better error code */ |
6218 | 0 | goto Exit; |
6219 | 0 | } |
6220 | | /* store token and ODCID */ |
6221 | 0 | free(conn->token.base); |
6222 | 0 | if ((conn->token.base = malloc(packet->token.len)) == NULL) { |
6223 | 0 | ret = PTLS_ERROR_NO_MEMORY; |
6224 | 0 | goto Exit; |
6225 | 0 | } |
6226 | 0 | memcpy(conn->token.base, packet->token.base, packet->token.len); |
6227 | 0 | conn->token.len = packet->token.len; |
6228 | | /* update DCID */ |
6229 | 0 | quicly_set_cid(&conn->super.remote.cid_set.cids[0].cid, packet->cid.src); |
6230 | 0 | conn->retry_scid = conn->super.remote.cid_set.cids[0].cid; |
6231 | | /* replace initial keys, or drop the keys if this is a response packet to a greased version */ |
6232 | 0 | if ((ret = reinstall_initial_encryption(conn, QUICLY_ERROR_PACKET_IGNORED)) != 0) |
6233 | 0 | goto Exit; |
6234 | | /* schedule retransmit */ |
6235 | 0 | ret = discard_sentmap_by_epoch(conn, ~0u); |
6236 | 0 | goto Exit; |
6237 | 0 | } break; |
6238 | 0 | case QUICLY_PACKET_TYPE_INITIAL: |
6239 | 0 | if (conn->initial == NULL || (header_protection = conn->initial->cipher.ingress.header_protection) == NULL) { |
6240 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6241 | 0 | goto Exit; |
6242 | 0 | } |
6243 | 0 | if (quicly_is_client(conn)) { |
6244 | | /* client: update cid if this is the first Initial packet that's being received */ |
6245 | 0 | if (conn->super.state == QUICLY_STATE_FIRSTFLIGHT) |
6246 | 0 | quicly_set_cid(&conn->super.remote.cid_set.cids[0].cid, packet->cid.src); |
6247 | 0 | } else { |
6248 | | /* server: ignore packets that are too small */ |
6249 | 0 | if (packet->datagram_size < QUICLY_MIN_CLIENT_INITIAL_SIZE) { |
6250 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6251 | 0 | goto Exit; |
6252 | 0 | } |
6253 | 0 | } |
6254 | 0 | aead.cb = aead_decrypt_fixed_key; |
6255 | 0 | aead.ctx = conn->initial->cipher.ingress.aead; |
6256 | 0 | space = (void *)&conn->initial; |
6257 | 0 | epoch = QUICLY_EPOCH_INITIAL; |
6258 | 0 | break; |
6259 | 0 | case QUICLY_PACKET_TYPE_HANDSHAKE: |
6260 | 0 | if (conn->handshake == NULL || (header_protection = conn->handshake->cipher.ingress.header_protection) == NULL) { |
6261 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6262 | 0 | goto Exit; |
6263 | 0 | } |
6264 | 0 | aead.cb = aead_decrypt_fixed_key; |
6265 | 0 | aead.ctx = conn->handshake->cipher.ingress.aead; |
6266 | 0 | space = (void *)&conn->handshake; |
6267 | 0 | epoch = QUICLY_EPOCH_HANDSHAKE; |
6268 | 0 | break; |
6269 | 0 | case QUICLY_PACKET_TYPE_0RTT: |
6270 | 0 | if (quicly_is_client(conn)) { |
6271 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6272 | 0 | goto Exit; |
6273 | 0 | } |
6274 | 0 | if (conn->application == NULL || |
6275 | 0 | (header_protection = conn->application->cipher.ingress.header_protection.zero_rtt) == NULL) { |
6276 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6277 | 0 | goto Exit; |
6278 | 0 | } |
6279 | 0 | aead.cb = aead_decrypt_fixed_key; |
6280 | 0 | aead.ctx = conn->application->cipher.ingress.aead[1]; |
6281 | 0 | space = (void *)&conn->application; |
6282 | 0 | epoch = QUICLY_EPOCH_0RTT; |
6283 | 0 | break; |
6284 | 0 | default: |
6285 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6286 | 0 | goto Exit; |
6287 | 0 | } |
6288 | 0 | } else { |
6289 | | /* short header packet */ |
6290 | 0 | if (conn->application == NULL || |
6291 | 0 | (header_protection = conn->application->cipher.ingress.header_protection.one_rtt) == NULL) { |
6292 | 0 | ret = QUICLY_ERROR_PACKET_IGNORED; |
6293 | 0 | goto Exit; |
6294 | 0 | } |
6295 | 0 | aead.cb = aead_decrypt_1rtt; |
6296 | 0 | aead.ctx = conn; |
6297 | 0 | space = (void *)&conn->application; |
6298 | 0 | epoch = QUICLY_EPOCH_1RTT; |
6299 | 0 | } |
6300 | | |
6301 | | /* decrypt */ |
6302 | 0 | if ((ret = decrypt_packet(header_protection, aead.cb, aead.ctx, &(*space)->next_expected_packet_number, packet, &pn, |
6303 | 0 | &payload)) != 0) { |
6304 | 0 | ++conn->super.stats.num_packets.decryption_failed; |
6305 | 0 | QUICLY_PROBE(PACKET_DECRYPTION_FAILED, conn, conn->stash.now, pn); |
6306 | 0 | goto Exit; |
6307 | 0 | } |
6308 | | |
6309 | 0 | QUICLY_PROBE(PACKET_RECEIVED, conn, conn->stash.now, pn, payload.base, payload.len, get_epoch(packet->octets.base[0])); |
6310 | 0 | QUICLY_LOG_CONN(packet_received, conn, { |
6311 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(pn, pn); |
6312 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(decrypted_len, payload.len); |
6313 | 0 | PTLS_LOG_ELEMENT_UNSIGNED(packet_type, get_epoch(packet->octets.base[0])); |
6314 | 0 | }); |
6315 | | |
6316 | | /* update states */ |
6317 | 0 | if (conn->super.state == QUICLY_STATE_FIRSTFLIGHT) |
6318 | 0 | conn->super.state = QUICLY_STATE_CONNECTED; |
6319 | 0 | conn->super.stats.num_packets.received += 1; |
6320 | | |
6321 | | /* state updates, that are triggered by the receipt of a packet */ |
6322 | 0 | switch (epoch) { |
6323 | 0 | case QUICLY_EPOCH_INITIAL: |
6324 | | /* update max_ingress_udp_payload_size if necessary */ |
6325 | 0 | if (conn->initial->largest_ingress_udp_payload_size < packet->datagram_size) |
6326 | 0 | conn->initial->largest_ingress_udp_payload_size = packet->datagram_size; |
6327 | 0 | break; |
6328 | 0 | case QUICLY_EPOCH_HANDSHAKE: |
6329 | | /* Discard Initial space before processing the payload of the Handshake packet to avoid the chance of an ACK frame included |
6330 | | * in the Handshake packet setting a loss timer for the Initial packet. */ |
6331 | 0 | if (conn->initial != NULL) { |
6332 | 0 | if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_INITIAL)) != 0) |
6333 | 0 | goto Exit; |
6334 | 0 | setup_next_send(conn); |
6335 | 0 | conn->super.remote.address_validation.validated = 1; |
6336 | 0 | } |
6337 | 0 | break; |
6338 | 0 | default: |
6339 | 0 | break; |
6340 | 0 | } |
6341 | | |
6342 | | /* handle the payload */ |
6343 | 0 | if ((ret = handle_payload(conn, epoch, payload.base, payload.len, &offending_frame_type, &is_ack_only)) != 0) |
6344 | 0 | goto Exit; |
6345 | 0 | if (*space != NULL && conn->super.state < QUICLY_STATE_CLOSING) { |
6346 | 0 | if ((ret = record_receipt(*space, pn, is_ack_only, conn->stash.now, &conn->egress.send_ack_at)) != 0) |
6347 | 0 | goto Exit; |
6348 | 0 | } |
6349 | | |
6350 | | /* state updates post payload processing */ |
6351 | 0 | switch (epoch) { |
6352 | 0 | case QUICLY_EPOCH_INITIAL: |
6353 | 0 | assert(conn->initial != NULL); |
6354 | 0 | if (quicly_is_client(conn) && conn->handshake != NULL && conn->handshake->cipher.egress.aead != NULL) { |
6355 | 0 | if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_INITIAL)) != 0) |
6356 | 0 | goto Exit; |
6357 | 0 | setup_next_send(conn); |
6358 | 0 | } |
6359 | 0 | break; |
6360 | 0 | case QUICLY_EPOCH_HANDSHAKE: |
6361 | 0 | if (quicly_is_client(conn)) { |
6362 | | /* Running as a client. |
6363 | | * Respect "disable_migration" TP sent by the remote peer at the end of the TLS handshake. */ |
6364 | 0 | if (conn->super.local.address.sa.sa_family == AF_UNSPEC && dest_addr != NULL && dest_addr->sa_family != AF_UNSPEC && |
6365 | 0 | ptls_handshake_is_complete(conn->crypto.tls) && conn->super.remote.transport_params.disable_active_migration) |
6366 | 0 | set_address(&conn->super.local.address, dest_addr); |
6367 | 0 | } else { |
6368 | | /* Running as a server. |
6369 | | * If handshake was just completed, drop handshake context, schedule the first emission of HANDSHAKE_DONE frame. */ |
6370 | 0 | if (ptls_handshake_is_complete(conn->crypto.tls)) { |
6371 | 0 | if ((ret = discard_handshake_context(conn, QUICLY_EPOCH_HANDSHAKE)) != 0) |
6372 | 0 | goto Exit; |
6373 | 0 | assert(conn->handshake == NULL); |
6374 | 0 | conn->egress.pending_flows |= QUICLY_PENDING_FLOW_HANDSHAKE_DONE_BIT; |
6375 | 0 | setup_next_send(conn); |
6376 | 0 | } |
6377 | 0 | } |
6378 | 0 | break; |
6379 | 0 | case QUICLY_EPOCH_1RTT: |
6380 | 0 | if (!is_ack_only && should_send_max_data(conn)) |
6381 | 0 | conn->egress.send_ack_at = 0; |
6382 | 0 | break; |
6383 | 0 | default: |
6384 | 0 | break; |
6385 | 0 | } |
6386 | | |
6387 | 0 | update_idle_timeout(conn, 1); |
6388 | |
|
6389 | 0 | Exit: |
6390 | 0 | switch (ret) { |
6391 | 0 | case 0: |
6392 | | /* Avoid time in the past being emitted by quicly_get_first_timeout. We hit the condition below when retransmission is |
6393 | | * suspended by the 3x limit (in which case we have loss.alarm_at set but return INT64_MAX from quicly_get_first_timeout |
6394 | | * until we receive something from the client). |
6395 | | */ |
6396 | 0 | if (conn->egress.loss.alarm_at < conn->stash.now) |
6397 | 0 | conn->egress.loss.alarm_at = conn->stash.now; |
6398 | 0 | assert_consistency(conn, 0); |
6399 | 0 | break; |
6400 | 0 | case PTLS_ERROR_NO_MEMORY: |
6401 | 0 | case QUICLY_ERROR_STATE_EXHAUSTION: |
6402 | 0 | case QUICLY_ERROR_PACKET_IGNORED: |
6403 | 0 | break; |
6404 | 0 | default: /* close connection */ |
6405 | 0 | initiate_close(conn, ret, offending_frame_type, ""); |
6406 | 0 | ret = 0; |
6407 | 0 | break; |
6408 | 0 | } |
6409 | 0 | unlock_now(conn); |
6410 | 0 | return ret; |
6411 | 0 | } |
6412 | | |
6413 | | int quicly_open_stream(quicly_conn_t *conn, quicly_stream_t **_stream, int uni) |
6414 | 0 | { |
6415 | 0 | quicly_stream_t *stream; |
6416 | 0 | struct st_quicly_conn_streamgroup_state_t *group; |
6417 | 0 | uint64_t *max_stream_count; |
6418 | 0 | uint32_t max_stream_data_local; |
6419 | 0 | uint64_t max_stream_data_remote; |
6420 | 0 | int ret; |
6421 | | |
6422 | | /* determine the states */ |
6423 | 0 | if (uni) { |
6424 | 0 | group = &conn->super.local.uni; |
6425 | 0 | max_stream_count = &conn->egress.max_streams.uni.count; |
6426 | 0 | max_stream_data_local = 0; |
6427 | 0 | max_stream_data_remote = conn->super.remote.transport_params.max_stream_data.uni; |
6428 | 0 | } else { |
6429 | 0 | group = &conn->super.local.bidi; |
6430 | 0 | max_stream_count = &conn->egress.max_streams.bidi.count; |
6431 | 0 | max_stream_data_local = (uint32_t)conn->super.ctx->transport_params.max_stream_data.bidi_local; |
6432 | 0 | max_stream_data_remote = conn->super.remote.transport_params.max_stream_data.bidi_remote; |
6433 | 0 | } |
6434 | | |
6435 | | /* open */ |
6436 | 0 | if ((stream = open_stream(conn, group->next_stream_id, max_stream_data_local, max_stream_data_remote)) == NULL) |
6437 | 0 | return PTLS_ERROR_NO_MEMORY; |
6438 | 0 | ++group->num_streams; |
6439 | 0 | group->next_stream_id += 4; |
6440 | | |
6441 | | /* adjust blocked */ |
6442 | 0 | if (stream->stream_id / 4 >= *max_stream_count) { |
6443 | 0 | stream->streams_blocked = 1; |
6444 | 0 | quicly_linklist_insert((uni ? &conn->egress.pending_streams.blocked.uni : &conn->egress.pending_streams.blocked.bidi)->prev, |
6445 | 0 | &stream->_send_aux.pending_link.control); |
6446 | 0 | } |
6447 | | |
6448 | | /* application-layer initialization */ |
6449 | 0 | QUICLY_PROBE(STREAM_ON_OPEN, conn, conn->stash.now, stream); |
6450 | 0 | QUICLY_LOG_CONN(stream_on_open, conn, {}); |
6451 | | |
6452 | 0 | if ((ret = conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, stream)) != 0) |
6453 | 0 | return ret; |
6454 | | |
6455 | 0 | *_stream = stream; |
6456 | 0 | return 0; |
6457 | 0 | } |
6458 | | |
6459 | | void quicly_reset_stream(quicly_stream_t *stream, int err) |
6460 | 0 | { |
6461 | 0 | assert(quicly_stream_has_send_side(quicly_is_client(stream->conn), stream->stream_id)); |
6462 | 0 | assert(QUICLY_ERROR_IS_QUIC_APPLICATION(err)); |
6463 | 0 | assert(stream->_send_aux.reset_stream.sender_state == QUICLY_SENDER_STATE_NONE); |
6464 | 0 | assert(!quicly_sendstate_transfer_complete(&stream->sendstate)); |
6465 | | |
6466 | | /* dispose sendbuf state */ |
6467 | 0 | quicly_sendstate_reset(&stream->sendstate); |
6468 | | |
6469 | | /* setup RESET_STREAM */ |
6470 | 0 | stream->_send_aux.reset_stream.sender_state = QUICLY_SENDER_STATE_SEND; |
6471 | 0 | stream->_send_aux.reset_stream.error_code = QUICLY_ERROR_GET_ERROR_CODE(err); |
6472 | | |
6473 | | /* schedule for delivery */ |
6474 | 0 | sched_stream_control(stream); |
6475 | 0 | resched_stream_data(stream); |
6476 | 0 | } |
6477 | | |
6478 | | void quicly_request_stop(quicly_stream_t *stream, int err) |
6479 | 0 | { |
6480 | 0 | assert(quicly_stream_has_receive_side(quicly_is_client(stream->conn), stream->stream_id)); |
6481 | 0 | assert(QUICLY_ERROR_IS_QUIC_APPLICATION(err)); |
6482 | | |
6483 | | /* send STOP_SENDING if the incoming side of the stream is still open */ |
6484 | 0 | if (stream->recvstate.eos == UINT64_MAX && stream->_send_aux.stop_sending.sender_state == QUICLY_SENDER_STATE_NONE) { |
6485 | 0 | stream->_send_aux.stop_sending.sender_state = QUICLY_SENDER_STATE_SEND; |
6486 | 0 | stream->_send_aux.stop_sending.error_code = QUICLY_ERROR_GET_ERROR_CODE(err); |
6487 | 0 | sched_stream_control(stream); |
6488 | 0 | } |
6489 | 0 | } |
6490 | | |
6491 | | socklen_t quicly_get_socklen(struct sockaddr *sa) |
6492 | 0 | { |
6493 | 0 | switch (sa->sa_family) { |
6494 | 0 | case AF_INET: |
6495 | 0 | return sizeof(struct sockaddr_in); |
6496 | 0 | case AF_INET6: |
6497 | 0 | return sizeof(struct sockaddr_in6); |
6498 | 0 | default: |
6499 | 0 | assert(!"unexpected socket type"); |
6500 | 0 | return 0; |
6501 | 0 | } |
6502 | 0 | } |
6503 | | |
6504 | | char *quicly_escape_unsafe_string(char *buf, const void *bytes, size_t len) |
6505 | 0 | { |
6506 | 0 | char *dst = buf; |
6507 | 0 | const char *src = bytes, *end = src + len; |
6508 | |
|
6509 | 0 | for (; src != end; ++src) { |
6510 | 0 | if ((0x20 <= *src && *src <= 0x7e) && !(*src == '"' || *src == '\'' || *src == '\\')) { |
6511 | 0 | *dst++ = *src; |
6512 | 0 | } else { |
6513 | 0 | *dst++ = '\\'; |
6514 | 0 | *dst++ = 'x'; |
6515 | 0 | quicly_byte_to_hex(dst, (uint8_t)*src); |
6516 | 0 | dst += 2; |
6517 | 0 | } |
6518 | 0 | } |
6519 | 0 | *dst = '\0'; |
6520 | |
|
6521 | 0 | return buf; |
6522 | 0 | } |
6523 | | |
6524 | | char *quicly_hexdump(const uint8_t *bytes, size_t len, size_t indent) |
6525 | 0 | { |
6526 | 0 | size_t i, line, row, bufsize = indent == SIZE_MAX ? len * 2 + 1 : (indent + 5 + 3 * 16 + 2 + 16 + 1) * ((len + 15) / 16) + 1; |
6527 | 0 | char *buf, *p; |
6528 | |
|
6529 | 0 | if ((buf = malloc(bufsize)) == NULL) |
6530 | 0 | return NULL; |
6531 | 0 | p = buf; |
6532 | 0 | if (indent == SIZE_MAX) { |
6533 | 0 | for (i = 0; i != len; ++i) { |
6534 | 0 | quicly_byte_to_hex(p, bytes[i]); |
6535 | 0 | p += 2; |
6536 | 0 | } |
6537 | 0 | } else { |
6538 | 0 | for (line = 0; line * 16 < len; ++line) { |
6539 | 0 | for (i = 0; i < indent; ++i) |
6540 | 0 | *p++ = ' '; |
6541 | 0 | quicly_byte_to_hex(p, (line >> 4) & 0xff); |
6542 | 0 | p += 2; |
6543 | 0 | quicly_byte_to_hex(p, (line << 4) & 0xff); |
6544 | 0 | p += 2; |
6545 | 0 | *p++ = ' '; |
6546 | 0 | for (row = 0; row < 16; ++row) { |
6547 | 0 | *p++ = row == 8 ? '-' : ' '; |
6548 | 0 | if (line * 16 + row < len) { |
6549 | 0 | quicly_byte_to_hex(p, bytes[line * 16 + row]); |
6550 | 0 | p += 2; |
6551 | 0 | } else { |
6552 | 0 | *p++ = ' '; |
6553 | 0 | *p++ = ' '; |
6554 | 0 | } |
6555 | 0 | } |
6556 | 0 | *p++ = ' '; |
6557 | 0 | *p++ = ' '; |
6558 | 0 | for (row = 0; row < 16; ++row) { |
6559 | 0 | if (line * 16 + row < len) { |
6560 | 0 | int ch = bytes[line * 16 + row]; |
6561 | 0 | *p++ = 0x20 <= ch && ch < 0x7f ? ch : '.'; |
6562 | 0 | } else { |
6563 | 0 | *p++ = ' '; |
6564 | 0 | } |
6565 | 0 | } |
6566 | 0 | *p++ = '\n'; |
6567 | 0 | } |
6568 | 0 | } |
6569 | 0 | *p++ = '\0'; |
6570 | |
|
6571 | 0 | assert(p - buf <= bufsize); |
6572 | | |
6573 | 0 | return buf; |
6574 | 0 | } |
6575 | | |
6576 | | void quicly_amend_ptls_context(ptls_context_t *ptls) |
6577 | 0 | { |
6578 | 0 | static ptls_update_traffic_key_t update_traffic_key = {update_traffic_key_cb}; |
6579 | |
|
6580 | 0 | ptls->omit_end_of_early_data = 1; |
6581 | 0 | ptls->update_traffic_key = &update_traffic_key; |
6582 | | |
6583 | | /* if TLS 1.3 config permits use of early data, convert the value to 0xffffffff in accordance with QUIC-TLS */ |
6584 | 0 | if (ptls->max_early_data_size != 0) |
6585 | 0 | ptls->max_early_data_size = UINT32_MAX; |
6586 | 0 | } |
6587 | | |
6588 | | int quicly_encrypt_address_token(void (*random_bytes)(void *, size_t), ptls_aead_context_t *aead, ptls_buffer_t *buf, |
6589 | | size_t start_off, const quicly_address_token_plaintext_t *plaintext) |
6590 | 0 | { |
6591 | 0 | int ret; |
6592 | | |
6593 | | /* type and IV */ |
6594 | 0 | if ((ret = ptls_buffer_reserve(buf, 1 + aead->algo->iv_size)) != 0) |
6595 | 0 | goto Exit; |
6596 | 0 | buf->base[buf->off++] = plaintext->type; |
6597 | 0 | random_bytes(buf->base + buf->off, aead->algo->iv_size); |
6598 | 0 | buf->off += aead->algo->iv_size; |
6599 | |
|
6600 | 0 | size_t enc_start = buf->off; |
6601 | | |
6602 | | /* data */ |
6603 | 0 | ptls_buffer_push64(buf, plaintext->issued_at); |
6604 | 0 | { |
6605 | 0 | uint16_t port; |
6606 | 0 | ptls_buffer_push_block(buf, 1, { |
6607 | 0 | switch (plaintext->remote.sa.sa_family) { |
6608 | 0 | case AF_INET: |
6609 | 0 | ptls_buffer_pushv(buf, &plaintext->remote.sin.sin_addr.s_addr, 4); |
6610 | 0 | port = ntohs(plaintext->remote.sin.sin_port); |
6611 | 0 | break; |
6612 | 0 | case AF_INET6: |
6613 | 0 | ptls_buffer_pushv(buf, &plaintext->remote.sin6.sin6_addr, 16); |
6614 | 0 | port = ntohs(plaintext->remote.sin6.sin6_port); |
6615 | 0 | break; |
6616 | 0 | default: |
6617 | 0 | assert(!"unsupported address type"); |
6618 | 0 | break; |
6619 | 0 | } |
6620 | 0 | }); |
6621 | 0 | ptls_buffer_push16(buf, port); |
6622 | 0 | } |
6623 | 0 | switch (plaintext->type) { |
6624 | 0 | case QUICLY_ADDRESS_TOKEN_TYPE_RETRY: |
6625 | 0 | ptls_buffer_push_block(buf, 1, |
6626 | 0 | { ptls_buffer_pushv(buf, plaintext->retry.original_dcid.cid, plaintext->retry.original_dcid.len); }); |
6627 | 0 | ptls_buffer_push_block(buf, 1, |
6628 | 0 | { ptls_buffer_pushv(buf, plaintext->retry.client_cid.cid, plaintext->retry.client_cid.len); }); |
6629 | 0 | ptls_buffer_push_block(buf, 1, |
6630 | 0 | { ptls_buffer_pushv(buf, plaintext->retry.server_cid.cid, plaintext->retry.server_cid.len); }); |
6631 | 0 | break; |
6632 | 0 | case QUICLY_ADDRESS_TOKEN_TYPE_RESUMPTION: |
6633 | 0 | ptls_buffer_push_block(buf, 1, { ptls_buffer_pushv(buf, plaintext->resumption.bytes, plaintext->resumption.len); }); |
6634 | 0 | break; |
6635 | 0 | default: |
6636 | 0 | assert(!"unexpected token type"); |
6637 | 0 | abort(); |
6638 | 0 | } |
6639 | 0 | ptls_buffer_push_block(buf, 1, { ptls_buffer_pushv(buf, plaintext->appdata.bytes, plaintext->appdata.len); }); |
6640 | | |
6641 | | /* encrypt, supplying full IV */ |
6642 | 0 | if ((ret = ptls_buffer_reserve(buf, aead->algo->tag_size)) != 0) |
6643 | 0 | goto Exit; |
6644 | 0 | ptls_aead_set_iv(aead, buf->base + enc_start - aead->algo->iv_size); |
6645 | 0 | ptls_aead_encrypt(aead, buf->base + enc_start, buf->base + enc_start, buf->off - enc_start, 0, buf->base + start_off, |
6646 | 0 | enc_start - start_off); |
6647 | 0 | buf->off += aead->algo->tag_size; |
6648 | |
|
6649 | 0 | Exit: |
6650 | 0 | return ret; |
6651 | 0 | } |
6652 | | |
6653 | | int quicly_decrypt_address_token(ptls_aead_context_t *aead, quicly_address_token_plaintext_t *plaintext, const void *_token, |
6654 | | size_t len, size_t prefix_len, const char **err_desc) |
6655 | 0 | { |
6656 | 0 | const uint8_t *const token = _token; |
6657 | 0 | uint8_t ptbuf[QUICLY_MIN_CLIENT_INITIAL_SIZE]; |
6658 | 0 | size_t ptlen; |
6659 | |
|
6660 | 0 | *err_desc = NULL; |
6661 | | |
6662 | | /* check if we can get type and decrypt */ |
6663 | 0 | if (len < prefix_len + 1 + aead->algo->iv_size + aead->algo->tag_size) { |
6664 | 0 | *err_desc = "token too small"; |
6665 | 0 | return PTLS_ALERT_DECODE_ERROR; |
6666 | 0 | } |
6667 | 0 | if (prefix_len + 1 + aead->algo->iv_size + sizeof(ptbuf) + aead->algo->tag_size < len) { |
6668 | 0 | *err_desc = "token too large"; |
6669 | 0 | return PTLS_ALERT_DECODE_ERROR; |
6670 | 0 | } |
6671 | | |
6672 | | /* check type */ |
6673 | 0 | switch (token[prefix_len]) { |
6674 | 0 | case QUICLY_ADDRESS_TOKEN_TYPE_RETRY: |
6675 | 0 | plaintext->type = QUICLY_ADDRESS_TOKEN_TYPE_RETRY; |
6676 | 0 | break; |
6677 | 0 | case QUICLY_ADDRESS_TOKEN_TYPE_RESUMPTION: |
6678 | 0 | plaintext->type = QUICLY_ADDRESS_TOKEN_TYPE_RESUMPTION; |
6679 | 0 | break; |
6680 | 0 | default: |
6681 | 0 | *err_desc = "unknown token type"; |
6682 | 0 | return PTLS_ALERT_DECODE_ERROR; |
6683 | 0 | } |
6684 | | |
6685 | | /* `goto Exit` can only happen below this line, and that is guaranteed by declaring `ret` here */ |
6686 | 0 | int ret; |
6687 | | |
6688 | | /* decrypt */ |
6689 | 0 | ptls_aead_set_iv(aead, token + prefix_len + 1); |
6690 | 0 | if ((ptlen = ptls_aead_decrypt(aead, ptbuf, token + prefix_len + 1 + aead->algo->iv_size, |
6691 | 0 | len - (prefix_len + 1 + aead->algo->iv_size), 0, token, prefix_len + 1 + aead->algo->iv_size)) == |
6692 | 0 | SIZE_MAX) { |
6693 | 0 | ret = PTLS_ALERT_DECRYPT_ERROR; |
6694 | 0 | *err_desc = "token decryption failure"; |
6695 | 0 | goto Exit; |
6696 | 0 | } |
6697 | | |
6698 | | /* parse */ |
6699 | 0 | const uint8_t *src = ptbuf, *end = src + ptlen; |
6700 | 0 | if ((ret = ptls_decode64(&plaintext->issued_at, &src, end)) != 0) |
6701 | 0 | goto Exit; |
6702 | 0 | { |
6703 | 0 | in_port_t *portaddr; |
6704 | 0 | ptls_decode_open_block(src, end, 1, { |
6705 | 0 | switch (end - src) { |
6706 | 0 | case 4: /* ipv4 */ |
6707 | 0 | plaintext->remote.sin.sin_family = AF_INET; |
6708 | 0 | memcpy(&plaintext->remote.sin.sin_addr.s_addr, src, 4); |
6709 | 0 | portaddr = &plaintext->remote.sin.sin_port; |
6710 | 0 | break; |
6711 | 0 | case 16: /* ipv6 */ |
6712 | 0 | plaintext->remote.sin6.sin6_family = AF_INET6; |
6713 | 0 | memcpy(&plaintext->remote.sin6.sin6_addr, src, 16); |
6714 | 0 | portaddr = &plaintext->remote.sin6.sin6_port; |
6715 | 0 | break; |
6716 | 0 | default: |
6717 | 0 | ret = PTLS_ALERT_DECODE_ERROR; |
6718 | 0 | goto Exit; |
6719 | 0 | } |
6720 | 0 | src = end; |
6721 | 0 | }); |
6722 | 0 | uint16_t port; |
6723 | 0 | if ((ret = ptls_decode16(&port, &src, end)) != 0) |
6724 | 0 | goto Exit; |
6725 | 0 | *portaddr = htons(port); |
6726 | 0 | } |
6727 | 0 | switch (plaintext->type) { |
6728 | 0 | case QUICLY_ADDRESS_TOKEN_TYPE_RETRY: |
6729 | 0 | #define DECODE_CID(field) \ |
6730 | 0 | do { \ |
6731 | 0 | ptls_decode_open_block(src, end, 1, { \ |
6732 | 0 | if (end - src > sizeof(plaintext->retry.field.cid)) { \ |
6733 | 0 | ret = PTLS_ALERT_DECODE_ERROR; \ |
6734 | 0 | goto Exit; \ |
6735 | 0 | } \ |
6736 | 0 | quicly_set_cid(&plaintext->retry.field, ptls_iovec_init(src, end - src)); \ |
6737 | 0 | src = end; \ |
6738 | 0 | }); \ |
6739 | 0 | } while (0) |
6740 | 0 | DECODE_CID(original_dcid); |
6741 | 0 | DECODE_CID(client_cid); |
6742 | 0 | DECODE_CID(server_cid); |
6743 | 0 | #undef DECODE_CID |
6744 | 0 | break; |
6745 | 0 | case QUICLY_ADDRESS_TOKEN_TYPE_RESUMPTION: |
6746 | 0 | ptls_decode_open_block(src, end, 1, { |
6747 | 0 | PTLS_BUILD_ASSERT(sizeof(plaintext->resumption.bytes) >= 256); |
6748 | 0 | plaintext->resumption.len = end - src; |
6749 | 0 | memcpy(plaintext->resumption.bytes, src, plaintext->resumption.len); |
6750 | 0 | src = end; |
6751 | 0 | }); |
6752 | 0 | break; |
6753 | 0 | default: |
6754 | 0 | assert(!"unexpected token type"); |
6755 | 0 | abort(); |
6756 | 0 | } |
6757 | 0 | ptls_decode_block(src, end, 1, { |
6758 | 0 | PTLS_BUILD_ASSERT(sizeof(plaintext->appdata.bytes) >= 256); |
6759 | 0 | plaintext->appdata.len = end - src; |
6760 | 0 | memcpy(plaintext->appdata.bytes, src, plaintext->appdata.len); |
6761 | 0 | src = end; |
6762 | 0 | }); |
6763 | 0 | ret = 0; |
6764 | |
|
6765 | 0 | Exit: |
6766 | 0 | if (ret != 0) { |
6767 | 0 | if (*err_desc == NULL) |
6768 | 0 | *err_desc = "token decode error"; |
6769 | | /* promote the error to one that triggers the emission of INVALID_TOKEN_ERROR, if the token looked like a retry */ |
6770 | 0 | if (plaintext->type == QUICLY_ADDRESS_TOKEN_TYPE_RETRY) |
6771 | 0 | ret = QUICLY_TRANSPORT_ERROR_INVALID_TOKEN; |
6772 | 0 | } |
6773 | 0 | return ret; |
6774 | 0 | } |
6775 | | |
6776 | | int quicly_build_session_ticket_auth_data(ptls_buffer_t *auth_data, const quicly_context_t *ctx) |
6777 | 0 | { |
6778 | 0 | int ret; |
6779 | |
|
6780 | 0 | #define PUSH_TP(id, block) \ |
6781 | 0 | do { \ |
6782 | 0 | ptls_buffer_push_quicint(auth_data, id); \ |
6783 | 0 | ptls_buffer_push_block(auth_data, -1, block); \ |
6784 | 0 | } while (0) |
6785 | |
|
6786 | 0 | ptls_buffer_push_block(auth_data, -1, { |
6787 | 0 | PUSH_TP(QUICLY_TRANSPORT_PARAMETER_ID_ACTIVE_CONNECTION_ID_LIMIT, |
6788 | 0 | { ptls_buffer_push_quicint(auth_data, ctx->transport_params.active_connection_id_limit); }); |
6789 | 0 | PUSH_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_DATA, |
6790 | 0 | { ptls_buffer_push_quicint(auth_data, ctx->transport_params.max_data); }); |
6791 | 0 | PUSH_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, |
6792 | 0 | { ptls_buffer_push_quicint(auth_data, ctx->transport_params.max_stream_data.bidi_local); }); |
6793 | 0 | PUSH_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, |
6794 | 0 | { ptls_buffer_push_quicint(auth_data, ctx->transport_params.max_stream_data.bidi_remote); }); |
6795 | 0 | PUSH_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAM_DATA_UNI, |
6796 | 0 | { ptls_buffer_push_quicint(auth_data, ctx->transport_params.max_stream_data.uni); }); |
6797 | 0 | PUSH_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAMS_BIDI, |
6798 | 0 | { ptls_buffer_push_quicint(auth_data, ctx->transport_params.max_streams_bidi); }); |
6799 | 0 | PUSH_TP(QUICLY_TRANSPORT_PARAMETER_ID_INITIAL_MAX_STREAMS_UNI, |
6800 | 0 | { ptls_buffer_push_quicint(auth_data, ctx->transport_params.max_streams_uni); }); |
6801 | 0 | }); |
6802 | | |
6803 | 0 | #undef PUSH_TP |
6804 | | |
6805 | 0 | ret = 0; |
6806 | 0 | Exit: |
6807 | 0 | return ret; |
6808 | 0 | } |
6809 | | |
6810 | | void quicly_stream_noop_on_destroy(quicly_stream_t *stream, int err) |
6811 | 0 | { |
6812 | 0 | } |
6813 | | |
6814 | | void quicly_stream_noop_on_send_shift(quicly_stream_t *stream, size_t delta) |
6815 | 0 | { |
6816 | 0 | } |
6817 | | |
6818 | | void quicly_stream_noop_on_send_emit(quicly_stream_t *stream, size_t off, void *dst, size_t *len, int *wrote_all) |
6819 | 0 | { |
6820 | 0 | } |
6821 | | |
6822 | | void quicly_stream_noop_on_send_stop(quicly_stream_t *stream, int err) |
6823 | 0 | { |
6824 | 0 | } |
6825 | | |
6826 | | void quicly_stream_noop_on_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len) |
6827 | 0 | { |
6828 | 0 | } |
6829 | | |
6830 | | void quicly_stream_noop_on_receive_reset(quicly_stream_t *stream, int err) |
6831 | 0 | { |
6832 | 0 | } |
6833 | | |
6834 | | const quicly_stream_callbacks_t quicly_stream_noop_callbacks = { |
6835 | | quicly_stream_noop_on_destroy, quicly_stream_noop_on_send_shift, quicly_stream_noop_on_send_emit, |
6836 | | quicly_stream_noop_on_send_stop, quicly_stream_noop_on_receive, quicly_stream_noop_on_receive_reset}; |
6837 | | |
6838 | | void quicly__debug_printf(quicly_conn_t *conn, const char *function, int line, const char *fmt, ...) |
6839 | 0 | { |
6840 | | #if QUICLY_USE_DTRACE |
6841 | | char buf[1024]; |
6842 | | va_list args; |
6843 | | |
6844 | | if (!QUICLY_DEBUG_MESSAGE_ENABLED()) |
6845 | | return; |
6846 | | |
6847 | | va_start(args, fmt); |
6848 | | vsnprintf(buf, sizeof(buf), fmt, args); |
6849 | | va_end(args); |
6850 | | |
6851 | | QUICLY_DEBUG_MESSAGE(conn, function, line, buf); |
6852 | | #endif |
6853 | 0 | } |
6854 | | |
6855 | | const uint32_t quicly_supported_versions[] = {QUICLY_PROTOCOL_VERSION_1, QUICLY_PROTOCOL_VERSION_DRAFT29, |
6856 | | QUICLY_PROTOCOL_VERSION_DRAFT27, 0}; |