Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_output.c @ 8751:bc910a5ec737 quic
QUIC: separate files for output and ack related processing.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Tue, 13 Apr 2021 14:41:20 +0300 |
parents | |
children | 4117aa7fa38e |
comparison
equal
deleted
inserted
replaced
8750:41807e581de9 | 8751:bc910a5ec737 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Nginx, Inc. | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_event_quic_connection.h> | |
11 | |
12 | |
13 #define NGX_QUIC_MAX_SHORT_HEADER 25 /* 1 flags + 20 dcid + 4 pn */ | |
14 #define NGX_QUIC_MAX_LONG_HEADER 56 | |
15 /* 1 flags + 4 version + 2 x (1 + 20) s/dcid + 4 pn + 4 len + token len */ | |
16 | |
17 #define NGX_QUIC_MAX_UDP_PAYLOAD_OUT 1252 | |
18 #define NGX_QUIC_MAX_UDP_PAYLOAD_OUT6 1232 | |
19 | |
20 #define NGX_QUIC_RETRY_TOKEN_LIFETIME 3 /* seconds */ | |
21 #define NGX_QUIC_NEW_TOKEN_LIFETIME 600 /* seconds */ | |
22 #define NGX_QUIC_RETRY_BUFFER_SIZE 256 | |
23 /* 1 flags + 4 version + 3 x (1 + 20) s/o/dcid + itag + token(64) */ | |
24 | |
25 /* | |
26 * Endpoints MUST discard packets that are too small to be valid QUIC | |
27 * packets. With the set of AEAD functions defined in [QUIC-TLS], | |
28 * packets that are smaller than 21 bytes are never valid. | |
29 */ | |
30 #define NGX_QUIC_MIN_PKT_LEN 21 | |
31 | |
32 #define NGX_QUIC_MIN_SR_PACKET 43 /* 5 rand + 16 srt + 22 padding */ | |
33 #define NGX_QUIC_MAX_SR_PACKET 1200 | |
34 | |
35 #define NGX_QUIC_CC_MIN_INTERVAL 1000 /* 1s */ | |
36 | |
37 | |
38 static ssize_t ngx_quic_output_packet(ngx_connection_t *c, | |
39 ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min); | |
40 static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c); | |
41 static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len); | |
42 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, | |
43 ngx_quic_send_ctx_t *ctx); | |
44 | |
45 | |
46 size_t | |
47 ngx_quic_max_udp_payload(ngx_connection_t *c) | |
48 { | |
49 /* TODO: path MTU discovery */ | |
50 | |
51 #if (NGX_HAVE_INET6) | |
52 if (c->sockaddr->sa_family == AF_INET6) { | |
53 return NGX_QUIC_MAX_UDP_PAYLOAD_OUT6; | |
54 } | |
55 #endif | |
56 | |
57 return NGX_QUIC_MAX_UDP_PAYLOAD_OUT; | |
58 } | |
59 | |
60 | |
61 ngx_int_t | |
62 ngx_quic_output(ngx_connection_t *c) | |
63 { | |
64 off_t max; | |
65 size_t len, min, in_flight; | |
66 ssize_t n; | |
67 u_char *p; | |
68 ngx_uint_t i, pad; | |
69 ngx_quic_send_ctx_t *ctx; | |
70 ngx_quic_congestion_t *cg; | |
71 ngx_quic_connection_t *qc; | |
72 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
73 | |
74 c->log->action = "sending frames"; | |
75 | |
76 qc = ngx_quic_get_connection(c); | |
77 cg = &qc->congestion; | |
78 | |
79 in_flight = cg->in_flight; | |
80 | |
81 for ( ;; ) { | |
82 p = dst; | |
83 | |
84 len = ngx_min(qc->ctp.max_udp_payload_size, | |
85 NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); | |
86 | |
87 if (!qc->validated) { | |
88 max = qc->received * 3; | |
89 max = (c->sent >= max) ? 0 : max - c->sent; | |
90 len = ngx_min(len, (size_t) max); | |
91 } | |
92 | |
93 pad = ngx_quic_get_padding_level(c); | |
94 | |
95 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | |
96 | |
97 ctx = &qc->send_ctx[i]; | |
98 | |
99 if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { | |
100 return NGX_ERROR; | |
101 } | |
102 | |
103 min = (i == pad && p - dst < NGX_QUIC_MIN_INITIAL_SIZE) | |
104 ? NGX_QUIC_MIN_INITIAL_SIZE - (p - dst) : 0; | |
105 | |
106 n = ngx_quic_output_packet(c, ctx, p, len, min); | |
107 if (n == NGX_ERROR) { | |
108 return NGX_ERROR; | |
109 } | |
110 | |
111 p += n; | |
112 len -= n; | |
113 } | |
114 | |
115 len = p - dst; | |
116 if (len == 0) { | |
117 break; | |
118 } | |
119 | |
120 n = ngx_quic_send(c, dst, len); | |
121 if (n == NGX_ERROR) { | |
122 return NGX_ERROR; | |
123 } | |
124 } | |
125 | |
126 if (in_flight != cg->in_flight && !qc->send_timer_set && !qc->closing) { | |
127 qc->send_timer_set = 1; | |
128 ngx_add_timer(c->read, qc->tp.max_idle_timeout); | |
129 } | |
130 | |
131 ngx_quic_set_lost_timer(c); | |
132 | |
133 return NGX_OK; | |
134 } | |
135 | |
136 | |
137 static ngx_uint_t | |
138 ngx_quic_get_padding_level(ngx_connection_t *c) | |
139 { | |
140 ngx_queue_t *q; | |
141 ngx_quic_frame_t *f; | |
142 ngx_quic_send_ctx_t *ctx; | |
143 ngx_quic_connection_t *qc; | |
144 | |
145 /* | |
146 * 14.1. Initial Datagram Size | |
147 * | |
148 * Similarly, a server MUST expand the payload of all UDP datagrams | |
149 * carrying ack-eliciting Initial packets to at least the smallest | |
150 * allowed maximum datagram size of 1200 bytes | |
151 */ | |
152 | |
153 qc = ngx_quic_get_connection(c); | |
154 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial); | |
155 | |
156 for (q = ngx_queue_head(&ctx->frames); | |
157 q != ngx_queue_sentinel(&ctx->frames); | |
158 q = ngx_queue_next(q)) | |
159 { | |
160 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
161 | |
162 if (f->need_ack) { | |
163 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); | |
164 | |
165 if (ngx_queue_empty(&ctx->frames)) { | |
166 return 0; | |
167 } | |
168 | |
169 return 1; | |
170 } | |
171 } | |
172 | |
173 return NGX_QUIC_SEND_CTX_LAST; | |
174 } | |
175 | |
176 | |
177 static ssize_t | |
178 ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
179 u_char *data, size_t max, size_t min) | |
180 { | |
181 size_t len, hlen, pad_len; | |
182 u_char *p; | |
183 ssize_t flen; | |
184 ngx_str_t out, res; | |
185 ngx_int_t rc; | |
186 ngx_uint_t nframes; | |
187 ngx_msec_t now; | |
188 ngx_queue_t *q; | |
189 ngx_quic_frame_t *f; | |
190 ngx_quic_header_t pkt; | |
191 ngx_quic_congestion_t *cg; | |
192 ngx_quic_connection_t *qc; | |
193 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
194 | |
195 if (ngx_queue_empty(&ctx->frames)) { | |
196 return 0; | |
197 } | |
198 | |
199 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
200 "quic output %s packet max:%uz min:%uz", | |
201 ngx_quic_level_name(ctx->level), max, min); | |
202 | |
203 qc = ngx_quic_get_connection(c); | |
204 cg = &qc->congestion; | |
205 | |
206 hlen = (ctx->level == ssl_encryption_application) | |
207 ? NGX_QUIC_MAX_SHORT_HEADER | |
208 : NGX_QUIC_MAX_LONG_HEADER; | |
209 | |
210 hlen += EVP_GCM_TLS_TAG_LEN; | |
211 hlen -= NGX_QUIC_MAX_CID_LEN - qc->scid.len; | |
212 | |
213 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | |
214 | |
215 now = ngx_current_msec; | |
216 nframes = 0; | |
217 p = src; | |
218 len = 0; | |
219 | |
220 for (q = ngx_queue_head(&ctx->frames); | |
221 q != ngx_queue_sentinel(&ctx->frames); | |
222 q = ngx_queue_next(q)) | |
223 { | |
224 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
225 | |
226 if (!pkt.need_ack && f->need_ack && max > cg->window) { | |
227 max = cg->window; | |
228 } | |
229 | |
230 if (hlen + len >= max) { | |
231 break; | |
232 } | |
233 | |
234 if (hlen + len + f->len > max) { | |
235 rc = ngx_quic_split_frame(c, f, max - hlen - len); | |
236 | |
237 if (rc == NGX_ERROR) { | |
238 return NGX_ERROR; | |
239 } | |
240 | |
241 if (rc == NGX_DECLINED) { | |
242 break; | |
243 } | |
244 } | |
245 | |
246 if (f->need_ack) { | |
247 pkt.need_ack = 1; | |
248 } | |
249 | |
250 ngx_quic_log_frame(c->log, f, 1); | |
251 | |
252 flen = ngx_quic_create_frame(p, f); | |
253 if (flen == -1) { | |
254 return NGX_ERROR; | |
255 } | |
256 | |
257 len += flen; | |
258 p += flen; | |
259 | |
260 f->pnum = ctx->pnum; | |
261 f->first = now; | |
262 f->last = now; | |
263 f->plen = 0; | |
264 | |
265 nframes++; | |
266 | |
267 if (f->flush) { | |
268 break; | |
269 } | |
270 } | |
271 | |
272 if (nframes == 0) { | |
273 return 0; | |
274 } | |
275 | |
276 out.data = src; | |
277 out.len = len; | |
278 | |
279 pkt.keys = qc->keys; | |
280 pkt.flags = NGX_QUIC_PKT_FIXED_BIT; | |
281 | |
282 if (ctx->level == ssl_encryption_initial) { | |
283 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL; | |
284 | |
285 } else if (ctx->level == ssl_encryption_handshake) { | |
286 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_HANDSHAKE; | |
287 | |
288 } else { | |
289 if (qc->key_phase) { | |
290 pkt.flags |= NGX_QUIC_PKT_KPHASE; | |
291 } | |
292 } | |
293 | |
294 ngx_quic_set_packet_number(&pkt, ctx); | |
295 | |
296 pkt.version = qc->version; | |
297 pkt.log = c->log; | |
298 pkt.level = ctx->level; | |
299 pkt.dcid = qc->scid; | |
300 pkt.scid = qc->dcid; | |
301 | |
302 pad_len = 4; | |
303 | |
304 if (min) { | |
305 hlen = EVP_GCM_TLS_TAG_LEN | |
306 + ngx_quic_create_header(&pkt, NULL, out.len, NULL); | |
307 | |
308 if (min > hlen + pad_len) { | |
309 pad_len = min - hlen; | |
310 } | |
311 } | |
312 | |
313 if (out.len < pad_len) { | |
314 ngx_memset(p, NGX_QUIC_FT_PADDING, pad_len - out.len); | |
315 out.len = pad_len; | |
316 } | |
317 | |
318 pkt.payload = out; | |
319 | |
320 res.data = data; | |
321 | |
322 ngx_log_debug6(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
323 "quic packet tx %s bytes:%ui" | |
324 " need_ack:%d number:%L encoded nl:%d trunc:0x%xD", | |
325 ngx_quic_level_name(ctx->level), out.len, pkt.need_ack, | |
326 pkt.number, pkt.num_len, pkt.trunc); | |
327 | |
328 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { | |
329 return NGX_ERROR; | |
330 } | |
331 | |
332 ctx->pnum++; | |
333 | |
334 if (pkt.need_ack) { | |
335 /* move frames into the sent queue to wait for ack */ | |
336 | |
337 if (!qc->closing) { | |
338 q = ngx_queue_head(&ctx->frames); | |
339 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
340 f->plen = res.len; | |
341 | |
342 do { | |
343 q = ngx_queue_head(&ctx->frames); | |
344 ngx_queue_remove(q); | |
345 ngx_queue_insert_tail(&ctx->sent, q); | |
346 } while (--nframes); | |
347 } | |
348 | |
349 cg->in_flight += res.len; | |
350 | |
351 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
352 "quic congestion send if:%uz", cg->in_flight); | |
353 } | |
354 | |
355 while (nframes--) { | |
356 q = ngx_queue_head(&ctx->frames); | |
357 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
358 | |
359 ngx_queue_remove(q); | |
360 ngx_quic_free_frame(c, f); | |
361 } | |
362 | |
363 return res.len; | |
364 } | |
365 | |
366 | |
367 ssize_t | |
368 ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len) | |
369 { | |
370 ngx_buf_t b; | |
371 ngx_chain_t cl, *res; | |
372 | |
373 ngx_memzero(&b, sizeof(ngx_buf_t)); | |
374 | |
375 b.pos = b.start = buf; | |
376 b.last = b.end = buf + len; | |
377 b.last_buf = 1; | |
378 b.temporary = 1; | |
379 | |
380 cl.buf = &b; | |
381 cl.next= NULL; | |
382 | |
383 res = c->send_chain(c, &cl, 0); | |
384 if (res == NGX_CHAIN_ERROR) { | |
385 return NGX_ERROR; | |
386 } | |
387 | |
388 return len; | |
389 } | |
390 | |
391 | |
392 static void | |
393 ngx_quic_set_packet_number(ngx_quic_header_t *pkt, ngx_quic_send_ctx_t *ctx) | |
394 { | |
395 uint64_t delta; | |
396 | |
397 delta = ctx->pnum - ctx->largest_ack; | |
398 pkt->number = ctx->pnum; | |
399 | |
400 if (delta <= 0x7F) { | |
401 pkt->num_len = 1; | |
402 pkt->trunc = ctx->pnum & 0xff; | |
403 | |
404 } else if (delta <= 0x7FFF) { | |
405 pkt->num_len = 2; | |
406 pkt->flags |= 0x1; | |
407 pkt->trunc = ctx->pnum & 0xffff; | |
408 | |
409 } else if (delta <= 0x7FFFFF) { | |
410 pkt->num_len = 3; | |
411 pkt->flags |= 0x2; | |
412 pkt->trunc = ctx->pnum & 0xffffff; | |
413 | |
414 } else { | |
415 pkt->num_len = 4; | |
416 pkt->flags |= 0x3; | |
417 pkt->trunc = ctx->pnum & 0xffffffff; | |
418 } | |
419 } | |
420 | |
421 | |
422 ngx_int_t | |
423 ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt) | |
424 { | |
425 size_t len; | |
426 ngx_quic_header_t pkt; | |
427 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
428 | |
429 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
430 "sending version negotiation packet"); | |
431 | |
432 pkt.log = c->log; | |
433 pkt.flags = NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_FIXED_BIT; | |
434 pkt.dcid = inpkt->scid; | |
435 pkt.scid = inpkt->dcid; | |
436 | |
437 len = ngx_quic_create_version_negotiation(&pkt, buf); | |
438 | |
439 #ifdef NGX_QUIC_DEBUG_PACKETS | |
440 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
441 "quic vnego packet to send len:%uz %*xs", len, len, buf); | |
442 #endif | |
443 | |
444 (void) ngx_quic_send(c, buf, len); | |
445 | |
446 return NGX_ERROR; | |
447 } | |
448 | |
449 | |
450 int | |
451 ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, | |
452 uint8_t alert) | |
453 { | |
454 ngx_connection_t *c; | |
455 ngx_quic_connection_t *qc; | |
456 | |
457 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
458 | |
459 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
460 "quic ngx_quic_send_alert() lvl:%d alert:%d", | |
461 (int) level, (int) alert); | |
462 | |
463 qc = ngx_quic_get_connection(c); | |
464 if (qc == NULL) { | |
465 return 1; | |
466 } | |
467 | |
468 qc->error_level = level; | |
469 qc->error = NGX_QUIC_ERR_CRYPTO(alert); | |
470 qc->error_reason = "TLS alert"; | |
471 qc->error_app = 0; | |
472 qc->error_ftype = 0; | |
473 | |
474 if (ngx_quic_send_cc(c) != NGX_OK) { | |
475 return 0; | |
476 } | |
477 | |
478 return 1; | |
479 } | |
480 | |
481 | |
482 ngx_int_t | |
483 ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf, | |
484 ngx_quic_header_t *pkt) | |
485 { | |
486 u_char *token; | |
487 size_t len, max; | |
488 uint16_t rndbytes; | |
489 u_char buf[NGX_QUIC_MAX_SR_PACKET]; | |
490 | |
491 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
492 "quic handle stateless reset output"); | |
493 | |
494 if (pkt->len <= NGX_QUIC_MIN_PKT_LEN) { | |
495 return NGX_DECLINED; | |
496 } | |
497 | |
498 if (pkt->len <= NGX_QUIC_MIN_SR_PACKET) { | |
499 len = pkt->len - 1; | |
500 | |
501 } else { | |
502 max = ngx_min(NGX_QUIC_MAX_SR_PACKET, pkt->len * 3); | |
503 | |
504 if (RAND_bytes((u_char *) &rndbytes, sizeof(rndbytes)) != 1) { | |
505 return NGX_ERROR; | |
506 } | |
507 | |
508 len = (rndbytes % (max - NGX_QUIC_MIN_SR_PACKET + 1)) | |
509 + NGX_QUIC_MIN_SR_PACKET; | |
510 } | |
511 | |
512 if (RAND_bytes(buf, len - NGX_QUIC_SR_TOKEN_LEN) != 1) { | |
513 return NGX_ERROR; | |
514 } | |
515 | |
516 buf[0] &= ~NGX_QUIC_PKT_LONG; | |
517 buf[0] |= NGX_QUIC_PKT_FIXED_BIT; | |
518 | |
519 token = &buf[len - NGX_QUIC_SR_TOKEN_LEN]; | |
520 | |
521 if (ngx_quic_new_sr_token(c, &pkt->dcid, conf->sr_token_key, token) | |
522 != NGX_OK) | |
523 { | |
524 return NGX_ERROR; | |
525 } | |
526 | |
527 (void) ngx_quic_send(c, buf, len); | |
528 | |
529 return NGX_DECLINED; | |
530 } | |
531 | |
532 | |
533 ngx_int_t | |
534 ngx_quic_send_cc(ngx_connection_t *c) | |
535 { | |
536 ngx_quic_frame_t *frame; | |
537 ngx_quic_connection_t *qc; | |
538 | |
539 qc = ngx_quic_get_connection(c); | |
540 | |
541 if (qc->draining) { | |
542 return NGX_OK; | |
543 } | |
544 | |
545 if (qc->closing | |
546 && ngx_current_msec - qc->last_cc < NGX_QUIC_CC_MIN_INTERVAL) | |
547 { | |
548 /* dot not send CC too often */ | |
549 return NGX_OK; | |
550 } | |
551 | |
552 frame = ngx_quic_alloc_frame(c); | |
553 if (frame == NULL) { | |
554 return NGX_ERROR; | |
555 } | |
556 | |
557 frame->level = qc->error_level; | |
558 frame->type = qc->error_app ? NGX_QUIC_FT_CONNECTION_CLOSE_APP | |
559 : NGX_QUIC_FT_CONNECTION_CLOSE; | |
560 frame->u.close.error_code = qc->error; | |
561 frame->u.close.frame_type = qc->error_ftype; | |
562 | |
563 if (qc->error_reason) { | |
564 frame->u.close.reason.len = ngx_strlen(qc->error_reason); | |
565 frame->u.close.reason.data = (u_char *) qc->error_reason; | |
566 } | |
567 | |
568 ngx_quic_queue_frame(qc, frame); | |
569 | |
570 qc->last_cc = ngx_current_msec; | |
571 | |
572 return ngx_quic_output(c); | |
573 } | |
574 | |
575 | |
576 ngx_int_t | |
577 ngx_quic_send_early_cc(ngx_connection_t *c, ngx_quic_header_t *inpkt, | |
578 ngx_uint_t err, const char *reason) | |
579 { | |
580 ssize_t len; | |
581 ngx_str_t res; | |
582 ngx_quic_frame_t frame; | |
583 ngx_quic_header_t pkt; | |
584 | |
585 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
586 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
587 | |
588 ngx_memzero(&frame, sizeof(ngx_quic_frame_t)); | |
589 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | |
590 | |
591 frame.level = inpkt->level; | |
592 frame.type = NGX_QUIC_FT_CONNECTION_CLOSE; | |
593 frame.u.close.error_code = err; | |
594 | |
595 frame.u.close.reason.data = (u_char *) reason; | |
596 frame.u.close.reason.len = ngx_strlen(reason); | |
597 | |
598 len = ngx_quic_create_frame(NULL, &frame); | |
599 if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) { | |
600 return NGX_ERROR; | |
601 } | |
602 | |
603 ngx_quic_log_frame(c->log, &frame, 1); | |
604 | |
605 len = ngx_quic_create_frame(src, &frame); | |
606 if (len == -1) { | |
607 return NGX_ERROR; | |
608 } | |
609 | |
610 pkt.keys = ngx_quic_keys_new(c->pool); | |
611 if (pkt.keys == NULL) { | |
612 return NGX_ERROR; | |
613 } | |
614 | |
615 if (ngx_quic_keys_set_initial_secret(c->pool, pkt.keys, &inpkt->dcid, | |
616 inpkt->version) | |
617 != NGX_OK) | |
618 { | |
619 return NGX_ERROR; | |
620 } | |
621 | |
622 pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | |
623 | NGX_QUIC_PKT_INITIAL; | |
624 | |
625 pkt.num_len = 1; | |
626 /* | |
627 * pkt.num = 0; | |
628 * pkt.trunc = 0; | |
629 */ | |
630 | |
631 pkt.version = inpkt->version; | |
632 pkt.log = c->log; | |
633 pkt.level = inpkt->level; | |
634 pkt.dcid = inpkt->scid; | |
635 pkt.scid = inpkt->dcid; | |
636 pkt.payload.data = src; | |
637 pkt.payload.len = len; | |
638 | |
639 res.data = dst; | |
640 | |
641 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { | |
642 return NGX_ERROR; | |
643 } | |
644 | |
645 if (ngx_quic_send(c, res.data, res.len) == NGX_ERROR) { | |
646 return NGX_ERROR; | |
647 } | |
648 | |
649 return NGX_OK; | |
650 } | |
651 | |
652 | |
653 ngx_int_t | |
654 ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf, | |
655 ngx_quic_header_t *inpkt) | |
656 { | |
657 time_t expires; | |
658 ssize_t len; | |
659 ngx_str_t res, token; | |
660 ngx_quic_header_t pkt; | |
661 | |
662 u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE]; | |
663 u_char dcid[NGX_QUIC_SERVER_CID_LEN]; | |
664 | |
665 expires = ngx_time() + NGX_QUIC_RETRY_TOKEN_LIFETIME; | |
666 | |
667 if (ngx_quic_new_token(c, conf->av_token_key, &token, &inpkt->dcid, | |
668 expires, 1) | |
669 != NGX_OK) | |
670 { | |
671 return NGX_ERROR; | |
672 } | |
673 | |
674 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | |
675 pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_RETRY; | |
676 pkt.version = inpkt->version; | |
677 pkt.log = c->log; | |
678 | |
679 pkt.odcid = inpkt->dcid; | |
680 pkt.dcid = inpkt->scid; | |
681 | |
682 /* TODO: generate routable dcid */ | |
683 if (RAND_bytes(dcid, NGX_QUIC_SERVER_CID_LEN) != 1) { | |
684 return NGX_ERROR; | |
685 } | |
686 | |
687 pkt.scid.len = NGX_QUIC_SERVER_CID_LEN; | |
688 pkt.scid.data = dcid; | |
689 | |
690 pkt.token = token; | |
691 | |
692 res.data = buf; | |
693 | |
694 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { | |
695 return NGX_ERROR; | |
696 } | |
697 | |
698 #ifdef NGX_QUIC_DEBUG_PACKETS | |
699 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
700 "quic packet to send len:%uz %xV", res.len, &res); | |
701 #endif | |
702 | |
703 len = ngx_quic_send(c, res.data, res.len); | |
704 if (len == NGX_ERROR) { | |
705 return NGX_ERROR; | |
706 } | |
707 | |
708 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
709 "quic retry packet sent to %xV", &pkt.dcid); | |
710 | |
711 /* | |
712 * quic-transport 17.2.5.1: A server MUST NOT send more than one Retry | |
713 * packet in response to a single UDP datagram. | |
714 * NGX_DONE will stop quic_input() from processing further | |
715 */ | |
716 return NGX_DONE; | |
717 } | |
718 | |
719 | |
720 ngx_int_t | |
721 ngx_quic_send_new_token(ngx_connection_t *c) | |
722 { | |
723 time_t expires; | |
724 ngx_str_t token; | |
725 ngx_quic_frame_t *frame; | |
726 ngx_quic_connection_t *qc; | |
727 | |
728 qc = ngx_quic_get_connection(c); | |
729 | |
730 if (!qc->conf->retry) { | |
731 return NGX_OK; | |
732 } | |
733 | |
734 expires = ngx_time() + NGX_QUIC_NEW_TOKEN_LIFETIME; | |
735 | |
736 if (ngx_quic_new_token(c, qc->conf->av_token_key, &token, NULL, expires, 0) | |
737 != NGX_OK) | |
738 { | |
739 return NGX_ERROR; | |
740 } | |
741 | |
742 frame = ngx_quic_alloc_frame(c); | |
743 if (frame == NULL) { | |
744 return NGX_ERROR; | |
745 } | |
746 | |
747 frame->level = ssl_encryption_application; | |
748 frame->type = NGX_QUIC_FT_NEW_TOKEN; | |
749 frame->u.token.length = token.len; | |
750 frame->u.token.data = token.data; | |
751 | |
752 ngx_quic_queue_frame(qc, frame); | |
753 | |
754 return NGX_OK; | |
755 } | |
756 | |
757 | |
758 ngx_int_t | |
759 ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | |
760 { | |
761 size_t len, left; | |
762 uint64_t ack_delay; | |
763 ngx_buf_t *b; | |
764 ngx_uint_t i; | |
765 ngx_chain_t *cl, **ll; | |
766 ngx_quic_frame_t *frame; | |
767 ngx_quic_connection_t *qc; | |
768 | |
769 qc = ngx_quic_get_connection(c); | |
770 | |
771 ack_delay = ngx_current_msec - ctx->largest_received; | |
772 ack_delay *= 1000; | |
773 ack_delay >>= qc->tp.ack_delay_exponent; | |
774 | |
775 frame = ngx_quic_alloc_frame(c); | |
776 if (frame == NULL) { | |
777 return NGX_ERROR; | |
778 } | |
779 | |
780 ll = &frame->data; | |
781 b = NULL; | |
782 | |
783 for (i = 0; i < ctx->nranges; i++) { | |
784 len = ngx_quic_create_ack_range(NULL, ctx->ranges[i].gap, | |
785 ctx->ranges[i].range); | |
786 | |
787 left = b ? b->end - b->last : 0; | |
788 | |
789 if (left < len) { | |
790 cl = ngx_quic_alloc_buf(c); | |
791 if (cl == NULL) { | |
792 return NGX_ERROR; | |
793 } | |
794 | |
795 *ll = cl; | |
796 ll = &cl->next; | |
797 | |
798 b = cl->buf; | |
799 left = b->end - b->last; | |
800 | |
801 if (left < len) { | |
802 return NGX_ERROR; | |
803 } | |
804 } | |
805 | |
806 b->last += ngx_quic_create_ack_range(b->last, ctx->ranges[i].gap, | |
807 ctx->ranges[i].range); | |
808 | |
809 frame->u.ack.ranges_length += len; | |
810 } | |
811 | |
812 *ll = NULL; | |
813 | |
814 frame->level = ctx->level; | |
815 frame->type = NGX_QUIC_FT_ACK; | |
816 frame->u.ack.largest = ctx->largest_range; | |
817 frame->u.ack.delay = ack_delay; | |
818 frame->u.ack.range_count = ctx->nranges; | |
819 frame->u.ack.first_range = ctx->first_range; | |
820 | |
821 ngx_quic_queue_frame(qc, frame); | |
822 | |
823 return NGX_OK; | |
824 } | |
825 | |
826 | |
827 ngx_int_t | |
828 ngx_quic_send_ack_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
829 uint64_t smallest, uint64_t largest) | |
830 { | |
831 ngx_quic_frame_t *frame; | |
832 ngx_quic_connection_t *qc; | |
833 | |
834 qc = ngx_quic_get_connection(c); | |
835 | |
836 frame = ngx_quic_alloc_frame(c); | |
837 if (frame == NULL) { | |
838 return NGX_ERROR; | |
839 } | |
840 | |
841 frame->level = ctx->level; | |
842 frame->type = NGX_QUIC_FT_ACK; | |
843 frame->u.ack.largest = largest; | |
844 frame->u.ack.delay = 0; | |
845 frame->u.ack.range_count = 0; | |
846 frame->u.ack.first_range = largest - smallest; | |
847 | |
848 ngx_quic_queue_frame(qc, frame); | |
849 | |
850 return NGX_OK; | |
851 } |