Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic.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 | 41807e581de9 |
children | e19723c40d28 |
comparison
equal
deleted
inserted
replaced
8750:41807e581de9 | 8751:bc910a5ec737 |
---|---|
9 #include <ngx_event.h> | 9 #include <ngx_event.h> |
10 #include <ngx_sha1.h> | 10 #include <ngx_sha1.h> |
11 #include <ngx_event_quic_connection.h> | 11 #include <ngx_event_quic_connection.h> |
12 | 12 |
13 | 13 |
14 #define ngx_quic_lost_threshold(qc) \ | |
15 ngx_max(NGX_QUIC_TIME_THR * ngx_max((qc)->latest_rtt, (qc)->avg_rtt), \ | |
16 NGX_QUIC_TIME_GRANULARITY) | |
17 | |
18 /* | 14 /* |
19 * 7.4. Cryptographic Message Buffering | 15 * 7.4. Cryptographic Message Buffering |
20 * Implementations MUST support buffering at least 4096 bytes of data | 16 * Implementations MUST support buffering at least 4096 bytes of data |
21 */ | 17 */ |
22 #define NGX_QUIC_MAX_BUFFERED 65535 | 18 #define NGX_QUIC_MAX_BUFFERED 65535 |
23 | |
24 /* | |
25 * Endpoints MUST discard packets that are too small to be valid QUIC | |
26 * packets. With the set of AEAD functions defined in [QUIC-TLS], | |
27 * packets that are smaller than 21 bytes are never valid. | |
28 */ | |
29 #define NGX_QUIC_MIN_PKT_LEN 21 | |
30 | |
31 #define NGX_QUIC_MIN_SR_PACKET 43 /* 5 random + 16 srt + 22 padding */ | |
32 #define NGX_QUIC_MAX_SR_PACKET 1200 | |
33 | |
34 #define NGX_QUIC_MAX_ACK_GAP 2 | |
35 | 19 |
36 | 20 |
37 #if BORINGSSL_API_VERSION >= 10 | 21 #if BORINGSSL_API_VERSION >= 10 |
38 static int ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, | 22 static int ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, |
39 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, | 23 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, |
48 #endif | 32 #endif |
49 | 33 |
50 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | 34 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, |
51 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); | 35 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); |
52 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); | 36 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); |
53 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, | |
54 enum ssl_encryption_level_t level, uint8_t alert); | |
55 | 37 |
56 | 38 |
57 static ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c, | 39 static ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c, |
58 ngx_quic_tp_t *ctp); | 40 ngx_quic_tp_t *ctp); |
59 static ngx_quic_connection_t *ngx_quic_new_connection(ngx_connection_t *c, | 41 static ngx_quic_connection_t *ngx_quic_new_connection(ngx_connection_t *c, |
60 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); | 42 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); |
61 static ngx_int_t ngx_quic_send_stateless_reset(ngx_connection_t *c, | |
62 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); | |
63 static ngx_int_t ngx_quic_process_stateless_reset(ngx_connection_t *c, | 43 static ngx_int_t ngx_quic_process_stateless_reset(ngx_connection_t *c, |
64 ngx_quic_header_t *pkt); | 44 ngx_quic_header_t *pkt); |
65 static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c, | |
66 ngx_quic_header_t *inpkt); | |
67 static ngx_int_t ngx_quic_send_retry(ngx_connection_t *c, | |
68 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); | |
69 static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, u_char *key, | |
70 ngx_str_t *token, ngx_str_t *odcid, time_t expires, ngx_uint_t is_retry); | |
71 static void ngx_quic_address_hash(ngx_connection_t *c, ngx_uint_t no_port, | 45 static void ngx_quic_address_hash(ngx_connection_t *c, ngx_uint_t no_port, |
72 u_char buf[20]); | 46 u_char buf[20]); |
73 static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c, | 47 static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c, |
74 u_char *key, ngx_quic_header_t *pkt); | 48 u_char *key, ngx_quic_header_t *pkt); |
75 static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); | 49 static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); |
76 static ngx_inline size_t ngx_quic_max_udp_payload(ngx_connection_t *c); | |
77 static void ngx_quic_input_handler(ngx_event_t *rev); | 50 static void ngx_quic_input_handler(ngx_event_t *rev); |
78 | 51 |
79 static ngx_int_t ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc); | 52 static ngx_int_t ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc); |
80 static void ngx_quic_close_timer_handler(ngx_event_t *ev); | 53 static void ngx_quic_close_timer_handler(ngx_event_t *ev); |
81 | 54 |
83 ngx_quic_conf_t *conf); | 56 ngx_quic_conf_t *conf); |
84 static ngx_int_t ngx_quic_process_packet(ngx_connection_t *c, | 57 static ngx_int_t ngx_quic_process_packet(ngx_connection_t *c, |
85 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); | 58 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); |
86 static ngx_int_t ngx_quic_process_payload(ngx_connection_t *c, | 59 static ngx_int_t ngx_quic_process_payload(ngx_connection_t *c, |
87 ngx_quic_header_t *pkt); | 60 ngx_quic_header_t *pkt); |
88 static ngx_int_t ngx_quic_send_early_cc(ngx_connection_t *c, | |
89 ngx_quic_header_t *inpkt, ngx_uint_t err, const char *reason); | |
90 static void ngx_quic_discard_ctx(ngx_connection_t *c, | 61 static void ngx_quic_discard_ctx(ngx_connection_t *c, |
91 enum ssl_encryption_level_t level); | 62 enum ssl_encryption_level_t level); |
92 static ngx_int_t ngx_quic_check_csid(ngx_quic_connection_t *qc, | 63 static ngx_int_t ngx_quic_check_csid(ngx_quic_connection_t *qc, |
93 ngx_quic_header_t *pkt); | 64 ngx_quic_header_t *pkt); |
94 static ngx_int_t ngx_quic_handle_frames(ngx_connection_t *c, | 65 static ngx_int_t ngx_quic_handle_frames(ngx_connection_t *c, |
95 ngx_quic_header_t *pkt); | 66 ngx_quic_header_t *pkt); |
96 static ngx_int_t ngx_quic_ack_packet(ngx_connection_t *c, | 67 |
97 ngx_quic_header_t *pkt); | |
98 static ngx_int_t ngx_quic_send_ack_range(ngx_connection_t *c, | |
99 ngx_quic_send_ctx_t *ctx, uint64_t smallest, uint64_t largest); | |
100 static void ngx_quic_drop_ack_ranges(ngx_connection_t *c, | |
101 ngx_quic_send_ctx_t *ctx, uint64_t pn); | |
102 static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, | |
103 ngx_quic_send_ctx_t *ctx); | |
104 static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c); | |
105 static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c); | |
106 | |
107 static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c, | |
108 ngx_quic_header_t *pkt, ngx_quic_frame_t *f); | |
109 static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c, | |
110 ngx_quic_send_ctx_t *ctx, uint64_t min, uint64_t max, | |
111 ngx_msec_t *send_time); | |
112 static void ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack, | |
113 enum ssl_encryption_level_t level, ngx_msec_t send_time); | |
114 | 68 |
115 static ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c, | 69 static ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c, |
116 ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); | 70 ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); |
117 ngx_int_t ngx_quic_crypto_input(ngx_connection_t *c, | 71 ngx_int_t ngx_quic_crypto_input(ngx_connection_t *c, |
118 ngx_quic_frame_t *frame, void *data); | 72 ngx_quic_frame_t *frame, void *data); |
119 | 73 |
120 static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c); | |
121 static ngx_int_t ngx_quic_generate_ack(ngx_connection_t *c, | |
122 ngx_quic_send_ctx_t *ctx); | |
123 static ssize_t ngx_quic_output_packet(ngx_connection_t *c, | |
124 ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min); | |
125 static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len); | |
126 | |
127 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, | |
128 ngx_quic_send_ctx_t *ctx); | |
129 static void ngx_quic_pto_handler(ngx_event_t *ev); | |
130 static void ngx_quic_lost_handler(ngx_event_t *ev); | |
131 static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c); | |
132 static void ngx_quic_set_lost_timer(ngx_connection_t *c); | |
133 static void ngx_quic_resend_frames(ngx_connection_t *c, | |
134 ngx_quic_send_ctx_t *ctx); | |
135 static void ngx_quic_push_handler(ngx_event_t *ev); | 74 static void ngx_quic_push_handler(ngx_event_t *ev); |
136 | |
137 static void ngx_quic_congestion_ack(ngx_connection_t *c, | |
138 ngx_quic_frame_t *frame); | |
139 static void ngx_quic_congestion_lost(ngx_connection_t *c, | |
140 ngx_quic_frame_t *frame); | |
141 | 75 |
142 | 76 |
143 static ngx_core_module_t ngx_quic_module_ctx = { | 77 static ngx_core_module_t ngx_quic_module_ctx = { |
144 ngx_string("quic"), | 78 ngx_string("quic"), |
145 NULL, | 79 NULL, |
176 }; | 110 }; |
177 | 111 |
178 | 112 |
179 #if (NGX_DEBUG) | 113 #if (NGX_DEBUG) |
180 | 114 |
181 static void | 115 void |
182 ngx_quic_connstate_dbg(ngx_connection_t *c) | 116 ngx_quic_connstate_dbg(ngx_connection_t *c) |
183 { | 117 { |
184 u_char *p, *last; | 118 u_char *p, *last; |
185 ngx_quic_connection_t *qc; | 119 ngx_quic_connection_t *qc; |
186 u_char buf[NGX_MAX_ERROR_STR]; | 120 u_char buf[NGX_MAX_ERROR_STR]; |
238 } | 172 } |
239 | 173 |
240 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 174 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
241 "quic %*s", p - buf, buf); | 175 "quic %*s", p - buf, buf); |
242 } | 176 } |
243 | |
244 #else | |
245 | |
246 #define ngx_quic_connstate_dbg(c) | |
247 | 177 |
248 #endif | 178 #endif |
249 | 179 |
250 | 180 |
251 #if BORINGSSL_API_VERSION >= 10 | 181 #if BORINGSSL_API_VERSION >= 10 |
466 #endif | 396 #endif |
467 return 1; | 397 return 1; |
468 } | 398 } |
469 | 399 |
470 | 400 |
471 static int | |
472 ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, | |
473 uint8_t alert) | |
474 { | |
475 ngx_connection_t *c; | |
476 ngx_quic_connection_t *qc; | |
477 | |
478 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
479 | |
480 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
481 "quic ngx_quic_send_alert() lvl:%d alert:%d", | |
482 (int) level, (int) alert); | |
483 | |
484 qc = ngx_quic_get_connection(c); | |
485 if (qc == NULL) { | |
486 return 1; | |
487 } | |
488 | |
489 qc->error_level = level; | |
490 qc->error = NGX_QUIC_ERR_CRYPTO(alert); | |
491 qc->error_reason = "TLS alert"; | |
492 qc->error_app = 0; | |
493 qc->error_ftype = 0; | |
494 | |
495 if (ngx_quic_send_cc(c) != NGX_OK) { | |
496 return 0; | |
497 } | |
498 | |
499 return 1; | |
500 } | |
501 | |
502 | |
503 static ngx_int_t | 401 static ngx_int_t |
504 ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp) | 402 ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp) |
505 { | 403 { |
506 ngx_quic_connection_t *qc; | 404 ngx_quic_connection_t *qc; |
507 | 405 |
720 | 618 |
721 return qc; | 619 return qc; |
722 } | 620 } |
723 | 621 |
724 | 622 |
725 static ngx_int_t | |
726 ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf, | |
727 ngx_quic_header_t *pkt) | |
728 { | |
729 u_char *token; | |
730 size_t len, max; | |
731 uint16_t rndbytes; | |
732 u_char buf[NGX_QUIC_MAX_SR_PACKET]; | |
733 | |
734 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
735 "quic handle stateless reset output"); | |
736 | |
737 if (pkt->len <= NGX_QUIC_MIN_PKT_LEN) { | |
738 return NGX_DECLINED; | |
739 } | |
740 | |
741 if (pkt->len <= NGX_QUIC_MIN_SR_PACKET) { | |
742 len = pkt->len - 1; | |
743 | |
744 } else { | |
745 max = ngx_min(NGX_QUIC_MAX_SR_PACKET, pkt->len * 3); | |
746 | |
747 if (RAND_bytes((u_char *) &rndbytes, sizeof(rndbytes)) != 1) { | |
748 return NGX_ERROR; | |
749 } | |
750 | |
751 len = (rndbytes % (max - NGX_QUIC_MIN_SR_PACKET + 1)) | |
752 + NGX_QUIC_MIN_SR_PACKET; | |
753 } | |
754 | |
755 if (RAND_bytes(buf, len - NGX_QUIC_SR_TOKEN_LEN) != 1) { | |
756 return NGX_ERROR; | |
757 } | |
758 | |
759 buf[0] &= ~NGX_QUIC_PKT_LONG; | |
760 buf[0] |= NGX_QUIC_PKT_FIXED_BIT; | |
761 | |
762 token = &buf[len - NGX_QUIC_SR_TOKEN_LEN]; | |
763 | |
764 if (ngx_quic_new_sr_token(c, &pkt->dcid, conf->sr_token_key, token) | |
765 != NGX_OK) | |
766 { | |
767 return NGX_ERROR; | |
768 } | |
769 | |
770 (void) ngx_quic_send(c, buf, len); | |
771 | |
772 return NGX_DECLINED; | |
773 } | |
774 | |
775 | |
776 ngx_int_t | 623 ngx_int_t |
777 ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid, u_char *secret, | 624 ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid, u_char *secret, |
778 u_char *token) | 625 u_char *token) |
779 { | 626 { |
780 ngx_str_t tmp; | 627 ngx_str_t tmp; |
841 | 688 |
842 return NGX_DECLINED; | 689 return NGX_DECLINED; |
843 } | 690 } |
844 | 691 |
845 | 692 |
846 static ngx_int_t | 693 ngx_int_t |
847 ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt) | |
848 { | |
849 size_t len; | |
850 ngx_quic_header_t pkt; | |
851 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
852 | |
853 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
854 "sending version negotiation packet"); | |
855 | |
856 pkt.log = c->log; | |
857 pkt.flags = NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_FIXED_BIT; | |
858 pkt.dcid = inpkt->scid; | |
859 pkt.scid = inpkt->dcid; | |
860 | |
861 len = ngx_quic_create_version_negotiation(&pkt, buf); | |
862 | |
863 #ifdef NGX_QUIC_DEBUG_PACKETS | |
864 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
865 "quic vnego packet to send len:%uz %*xs", len, len, buf); | |
866 #endif | |
867 | |
868 (void) ngx_quic_send(c, buf, len); | |
869 | |
870 return NGX_ERROR; | |
871 } | |
872 | |
873 | |
874 static ngx_int_t | |
875 ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf, | |
876 ngx_quic_header_t *inpkt) | |
877 { | |
878 time_t expires; | |
879 ssize_t len; | |
880 ngx_str_t res, token; | |
881 ngx_quic_header_t pkt; | |
882 | |
883 u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE]; | |
884 u_char dcid[NGX_QUIC_SERVER_CID_LEN]; | |
885 | |
886 expires = ngx_time() + NGX_QUIC_RETRY_TOKEN_LIFETIME; | |
887 | |
888 if (ngx_quic_new_token(c, conf->av_token_key, &token, &inpkt->dcid, | |
889 expires, 1) | |
890 != NGX_OK) | |
891 { | |
892 return NGX_ERROR; | |
893 } | |
894 | |
895 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | |
896 pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_RETRY; | |
897 pkt.version = inpkt->version; | |
898 pkt.log = c->log; | |
899 | |
900 pkt.odcid = inpkt->dcid; | |
901 pkt.dcid = inpkt->scid; | |
902 | |
903 /* TODO: generate routable dcid */ | |
904 if (RAND_bytes(dcid, NGX_QUIC_SERVER_CID_LEN) != 1) { | |
905 return NGX_ERROR; | |
906 } | |
907 | |
908 pkt.scid.len = NGX_QUIC_SERVER_CID_LEN; | |
909 pkt.scid.data = dcid; | |
910 | |
911 pkt.token = token; | |
912 | |
913 res.data = buf; | |
914 | |
915 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { | |
916 return NGX_ERROR; | |
917 } | |
918 | |
919 #ifdef NGX_QUIC_DEBUG_PACKETS | |
920 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
921 "quic packet to send len:%uz %xV", res.len, &res); | |
922 #endif | |
923 | |
924 len = ngx_quic_send(c, res.data, res.len); | |
925 if (len == NGX_ERROR) { | |
926 return NGX_ERROR; | |
927 } | |
928 | |
929 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
930 "quic retry packet sent to %xV", &pkt.dcid); | |
931 | |
932 /* | |
933 * quic-transport 17.2.5.1: A server MUST NOT send more than one Retry | |
934 * packet in response to a single UDP datagram. | |
935 * NGX_DONE will stop quic_input() from processing further | |
936 */ | |
937 return NGX_DONE; | |
938 } | |
939 | |
940 | |
941 static ngx_int_t | |
942 ngx_quic_new_token(ngx_connection_t *c, u_char *key, ngx_str_t *token, | 694 ngx_quic_new_token(ngx_connection_t *c, u_char *key, ngx_str_t *token, |
943 ngx_str_t *odcid, time_t exp, ngx_uint_t is_retry) | 695 ngx_str_t *odcid, time_t exp, ngx_uint_t is_retry) |
944 { | 696 { |
945 int len, iv_len; | 697 int len, iv_len; |
946 u_char *p, *iv; | 698 u_char *p, *iv; |
1262 return NGX_ERROR; | 1014 return NGX_ERROR; |
1263 } | 1015 } |
1264 #endif | 1016 #endif |
1265 | 1017 |
1266 return NGX_OK; | 1018 return NGX_OK; |
1267 } | |
1268 | |
1269 | |
1270 static ngx_inline size_t | |
1271 ngx_quic_max_udp_payload(ngx_connection_t *c) | |
1272 { | |
1273 /* TODO: path MTU discovery */ | |
1274 | |
1275 #if (NGX_HAVE_INET6) | |
1276 if (c->sockaddr->sa_family == AF_INET6) { | |
1277 return NGX_QUIC_MAX_UDP_PAYLOAD_OUT6; | |
1278 } | |
1279 #endif | |
1280 | |
1281 return NGX_QUIC_MAX_UDP_PAYLOAD_OUT; | |
1282 } | 1019 } |
1283 | 1020 |
1284 | 1021 |
1285 static void | 1022 static void |
1286 ngx_quic_input_handler(ngx_event_t *rev) | 1023 ngx_quic_input_handler(ngx_event_t *rev) |
1900 | 1637 |
1901 return ngx_quic_keys_update(c, qc->keys); | 1638 return ngx_quic_keys_update(c, qc->keys); |
1902 } | 1639 } |
1903 | 1640 |
1904 | 1641 |
1905 static ngx_int_t | |
1906 ngx_quic_send_early_cc(ngx_connection_t *c, ngx_quic_header_t *inpkt, | |
1907 ngx_uint_t err, const char *reason) | |
1908 { | |
1909 ssize_t len; | |
1910 ngx_str_t res; | |
1911 ngx_quic_frame_t frame; | |
1912 ngx_quic_header_t pkt; | |
1913 | |
1914 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
1915 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
1916 | |
1917 ngx_memzero(&frame, sizeof(ngx_quic_frame_t)); | |
1918 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | |
1919 | |
1920 frame.level = inpkt->level; | |
1921 frame.type = NGX_QUIC_FT_CONNECTION_CLOSE; | |
1922 frame.u.close.error_code = err; | |
1923 | |
1924 frame.u.close.reason.data = (u_char *) reason; | |
1925 frame.u.close.reason.len = ngx_strlen(reason); | |
1926 | |
1927 len = ngx_quic_create_frame(NULL, &frame); | |
1928 if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) { | |
1929 return NGX_ERROR; | |
1930 } | |
1931 | |
1932 ngx_quic_log_frame(c->log, &frame, 1); | |
1933 | |
1934 len = ngx_quic_create_frame(src, &frame); | |
1935 if (len == -1) { | |
1936 return NGX_ERROR; | |
1937 } | |
1938 | |
1939 pkt.keys = ngx_quic_keys_new(c->pool); | |
1940 if (pkt.keys == NULL) { | |
1941 return NGX_ERROR; | |
1942 } | |
1943 | |
1944 if (ngx_quic_keys_set_initial_secret(c->pool, pkt.keys, &inpkt->dcid, | |
1945 inpkt->version) | |
1946 != NGX_OK) | |
1947 { | |
1948 return NGX_ERROR; | |
1949 } | |
1950 | |
1951 pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | |
1952 | NGX_QUIC_PKT_INITIAL; | |
1953 | |
1954 pkt.num_len = 1; | |
1955 /* | |
1956 * pkt.num = 0; | |
1957 * pkt.trunc = 0; | |
1958 */ | |
1959 | |
1960 pkt.version = inpkt->version; | |
1961 pkt.log = c->log; | |
1962 pkt.level = inpkt->level; | |
1963 pkt.dcid = inpkt->scid; | |
1964 pkt.scid = inpkt->dcid; | |
1965 pkt.payload.data = src; | |
1966 pkt.payload.len = len; | |
1967 | |
1968 res.data = dst; | |
1969 | |
1970 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { | |
1971 return NGX_ERROR; | |
1972 } | |
1973 | |
1974 if (ngx_quic_send(c, res.data, res.len) == NGX_ERROR) { | |
1975 return NGX_ERROR; | |
1976 } | |
1977 | |
1978 return NGX_OK; | |
1979 } | |
1980 | |
1981 | |
1982 static void | 1642 static void |
1983 ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level) | 1643 ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level) |
1984 { | 1644 { |
1985 ngx_queue_t *q; | 1645 ngx_queue_t *q; |
1986 ngx_quic_frame_t *f; | 1646 ngx_quic_frame_t *f; |
2289 return NGX_OK; | 1949 return NGX_OK; |
2290 } | 1950 } |
2291 | 1951 |
2292 | 1952 |
2293 static ngx_int_t | 1953 static ngx_int_t |
2294 ngx_quic_ack_packet(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
2295 { | |
2296 uint64_t base, largest, smallest, gs, ge, gap, range, pn; | |
2297 uint64_t prev_pending; | |
2298 ngx_uint_t i, nr; | |
2299 ngx_quic_send_ctx_t *ctx; | |
2300 ngx_quic_ack_range_t *r; | |
2301 ngx_quic_connection_t *qc; | |
2302 | |
2303 c->log->action = "preparing ack"; | |
2304 | |
2305 qc = ngx_quic_get_connection(c); | |
2306 | |
2307 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
2308 | |
2309 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
2310 "quic ngx_quic_ack_packet pn:%uL largest %L fr:%uL" | |
2311 " nranges:%ui", pkt->pn, (int64_t) ctx->largest_range, | |
2312 ctx->first_range, ctx->nranges); | |
2313 | |
2314 prev_pending = ctx->pending_ack; | |
2315 | |
2316 if (pkt->need_ack) { | |
2317 | |
2318 ngx_post_event(&qc->push, &ngx_posted_events); | |
2319 | |
2320 if (ctx->send_ack == 0) { | |
2321 ctx->ack_delay_start = ngx_current_msec; | |
2322 } | |
2323 | |
2324 ctx->send_ack++; | |
2325 | |
2326 if (ctx->pending_ack == NGX_QUIC_UNSET_PN | |
2327 || ctx->pending_ack < pkt->pn) | |
2328 { | |
2329 ctx->pending_ack = pkt->pn; | |
2330 } | |
2331 } | |
2332 | |
2333 base = ctx->largest_range; | |
2334 pn = pkt->pn; | |
2335 | |
2336 if (base == NGX_QUIC_UNSET_PN) { | |
2337 ctx->largest_range = pn; | |
2338 ctx->largest_received = pkt->received; | |
2339 return NGX_OK; | |
2340 } | |
2341 | |
2342 if (base == pn) { | |
2343 return NGX_OK; | |
2344 } | |
2345 | |
2346 largest = base; | |
2347 smallest = largest - ctx->first_range; | |
2348 | |
2349 if (pn > base) { | |
2350 | |
2351 if (pn - base == 1) { | |
2352 ctx->first_range++; | |
2353 ctx->largest_range = pn; | |
2354 ctx->largest_received = pkt->received; | |
2355 | |
2356 return NGX_OK; | |
2357 | |
2358 } else { | |
2359 /* new gap in front of current largest */ | |
2360 | |
2361 /* no place for new range, send current range as is */ | |
2362 if (ctx->nranges == NGX_QUIC_MAX_RANGES) { | |
2363 | |
2364 if (prev_pending != NGX_QUIC_UNSET_PN) { | |
2365 if (ngx_quic_send_ack(c, ctx) != NGX_OK) { | |
2366 return NGX_ERROR; | |
2367 } | |
2368 } | |
2369 | |
2370 if (prev_pending == ctx->pending_ack || !pkt->need_ack) { | |
2371 ctx->pending_ack = NGX_QUIC_UNSET_PN; | |
2372 } | |
2373 } | |
2374 | |
2375 gap = pn - base - 2; | |
2376 range = ctx->first_range; | |
2377 | |
2378 ctx->first_range = 0; | |
2379 ctx->largest_range = pn; | |
2380 ctx->largest_received = pkt->received; | |
2381 | |
2382 /* packet is out of order, force send */ | |
2383 if (pkt->need_ack) { | |
2384 ctx->send_ack = NGX_QUIC_MAX_ACK_GAP; | |
2385 } | |
2386 | |
2387 i = 0; | |
2388 | |
2389 goto insert; | |
2390 } | |
2391 } | |
2392 | |
2393 /* pn < base, perform lookup in existing ranges */ | |
2394 | |
2395 /* packet is out of order */ | |
2396 if (pkt->need_ack) { | |
2397 ctx->send_ack = NGX_QUIC_MAX_ACK_GAP; | |
2398 } | |
2399 | |
2400 if (pn >= smallest && pn <= largest) { | |
2401 return NGX_OK; | |
2402 } | |
2403 | |
2404 #if (NGX_SUPPRESS_WARN) | |
2405 r = NULL; | |
2406 #endif | |
2407 | |
2408 for (i = 0; i < ctx->nranges; i++) { | |
2409 r = &ctx->ranges[i]; | |
2410 | |
2411 ge = smallest - 1; | |
2412 gs = ge - r->gap; | |
2413 | |
2414 if (pn >= gs && pn <= ge) { | |
2415 | |
2416 if (gs == ge) { | |
2417 /* gap size is exactly one packet, now filled */ | |
2418 | |
2419 /* data moves to previous range, current is removed */ | |
2420 | |
2421 if (i == 0) { | |
2422 ctx->first_range += r->range + 2; | |
2423 | |
2424 } else { | |
2425 ctx->ranges[i - 1].range += r->range + 2; | |
2426 } | |
2427 | |
2428 nr = ctx->nranges - i - 1; | |
2429 if (nr) { | |
2430 ngx_memmove(&ctx->ranges[i], &ctx->ranges[i + 1], | |
2431 sizeof(ngx_quic_ack_range_t) * nr); | |
2432 } | |
2433 | |
2434 ctx->nranges--; | |
2435 | |
2436 } else if (pn == gs) { | |
2437 /* current gap shrinks from tail (current range grows) */ | |
2438 r->gap--; | |
2439 r->range++; | |
2440 | |
2441 } else if (pn == ge) { | |
2442 /* current gap shrinks from head (previous range grows) */ | |
2443 r->gap--; | |
2444 | |
2445 if (i == 0) { | |
2446 ctx->first_range++; | |
2447 | |
2448 } else { | |
2449 ctx->ranges[i - 1].range++; | |
2450 } | |
2451 | |
2452 } else { | |
2453 /* current gap is split into two parts */ | |
2454 | |
2455 gap = ge - pn - 1; | |
2456 range = 0; | |
2457 | |
2458 if (ctx->nranges == NGX_QUIC_MAX_RANGES) { | |
2459 if (prev_pending != NGX_QUIC_UNSET_PN) { | |
2460 if (ngx_quic_send_ack(c, ctx) != NGX_OK) { | |
2461 return NGX_ERROR; | |
2462 } | |
2463 } | |
2464 | |
2465 if (prev_pending == ctx->pending_ack || !pkt->need_ack) { | |
2466 ctx->pending_ack = NGX_QUIC_UNSET_PN; | |
2467 } | |
2468 } | |
2469 | |
2470 r->gap = pn - gs - 1; | |
2471 goto insert; | |
2472 } | |
2473 | |
2474 return NGX_OK; | |
2475 } | |
2476 | |
2477 largest = smallest - r->gap - 2; | |
2478 smallest = largest - r->range; | |
2479 | |
2480 if (pn >= smallest && pn <= largest) { | |
2481 /* this packet number is already known */ | |
2482 return NGX_OK; | |
2483 } | |
2484 | |
2485 } | |
2486 | |
2487 if (pn == smallest - 1) { | |
2488 /* extend first or last range */ | |
2489 | |
2490 if (i == 0) { | |
2491 ctx->first_range++; | |
2492 | |
2493 } else { | |
2494 r->range++; | |
2495 } | |
2496 | |
2497 return NGX_OK; | |
2498 } | |
2499 | |
2500 /* nothing found, add new range at the tail */ | |
2501 | |
2502 if (ctx->nranges == NGX_QUIC_MAX_RANGES) { | |
2503 /* packet is too old to keep it */ | |
2504 | |
2505 if (pkt->need_ack) { | |
2506 return ngx_quic_send_ack_range(c, ctx, pn, pn); | |
2507 } | |
2508 | |
2509 return NGX_OK; | |
2510 } | |
2511 | |
2512 gap = smallest - 2 - pn; | |
2513 range = 0; | |
2514 | |
2515 insert: | |
2516 | |
2517 if (ctx->nranges < NGX_QUIC_MAX_RANGES) { | |
2518 ctx->nranges++; | |
2519 } | |
2520 | |
2521 ngx_memmove(&ctx->ranges[i + 1], &ctx->ranges[i], | |
2522 sizeof(ngx_quic_ack_range_t) * (ctx->nranges - i - 1)); | |
2523 | |
2524 ctx->ranges[i].gap = gap; | |
2525 ctx->ranges[i].range = range; | |
2526 | |
2527 return NGX_OK; | |
2528 } | |
2529 | |
2530 | |
2531 static ngx_int_t | |
2532 ngx_quic_send_ack_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
2533 uint64_t smallest, uint64_t largest) | |
2534 { | |
2535 ngx_quic_frame_t *frame; | |
2536 ngx_quic_connection_t *qc; | |
2537 | |
2538 qc = ngx_quic_get_connection(c); | |
2539 | |
2540 frame = ngx_quic_alloc_frame(c); | |
2541 if (frame == NULL) { | |
2542 return NGX_ERROR; | |
2543 } | |
2544 | |
2545 frame->level = ctx->level; | |
2546 frame->type = NGX_QUIC_FT_ACK; | |
2547 frame->u.ack.largest = largest; | |
2548 frame->u.ack.delay = 0; | |
2549 frame->u.ack.range_count = 0; | |
2550 frame->u.ack.first_range = largest - smallest; | |
2551 | |
2552 ngx_quic_queue_frame(qc, frame); | |
2553 | |
2554 return NGX_OK; | |
2555 } | |
2556 | |
2557 | |
2558 static void | |
2559 ngx_quic_drop_ack_ranges(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
2560 uint64_t pn) | |
2561 { | |
2562 uint64_t base; | |
2563 ngx_uint_t i, smallest, largest; | |
2564 ngx_quic_ack_range_t *r; | |
2565 | |
2566 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
2567 "quic ngx_quic_drop_ack_ranges pn:%uL largest:%uL" | |
2568 " fr:%uL nranges:%ui", pn, ctx->largest_range, | |
2569 ctx->first_range, ctx->nranges); | |
2570 | |
2571 base = ctx->largest_range; | |
2572 | |
2573 if (base == NGX_QUIC_UNSET_PN) { | |
2574 return; | |
2575 } | |
2576 | |
2577 if (ctx->pending_ack != NGX_QUIC_UNSET_PN && pn >= ctx->pending_ack) { | |
2578 ctx->pending_ack = NGX_QUIC_UNSET_PN; | |
2579 } | |
2580 | |
2581 largest = base; | |
2582 smallest = largest - ctx->first_range; | |
2583 | |
2584 if (pn >= largest) { | |
2585 ctx->largest_range = NGX_QUIC_UNSET_PN; | |
2586 ctx->first_range = 0; | |
2587 ctx->nranges = 0; | |
2588 return; | |
2589 } | |
2590 | |
2591 if (pn >= smallest) { | |
2592 ctx->first_range = largest - pn - 1; | |
2593 ctx->nranges = 0; | |
2594 return; | |
2595 } | |
2596 | |
2597 for (i = 0; i < ctx->nranges; i++) { | |
2598 r = &ctx->ranges[i]; | |
2599 | |
2600 largest = smallest - r->gap - 2; | |
2601 smallest = largest - r->range; | |
2602 | |
2603 if (pn >= largest) { | |
2604 ctx->nranges = i; | |
2605 return; | |
2606 } | |
2607 if (pn >= smallest) { | |
2608 r->range = largest - pn - 1; | |
2609 ctx->nranges = i + 1; | |
2610 return; | |
2611 } | |
2612 } | |
2613 } | |
2614 | |
2615 | |
2616 static ngx_int_t | |
2617 ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | |
2618 { | |
2619 size_t len, left; | |
2620 uint64_t ack_delay; | |
2621 ngx_buf_t *b; | |
2622 ngx_uint_t i; | |
2623 ngx_chain_t *cl, **ll; | |
2624 ngx_quic_frame_t *frame; | |
2625 ngx_quic_connection_t *qc; | |
2626 | |
2627 qc = ngx_quic_get_connection(c); | |
2628 | |
2629 ack_delay = ngx_current_msec - ctx->largest_received; | |
2630 ack_delay *= 1000; | |
2631 ack_delay >>= qc->tp.ack_delay_exponent; | |
2632 | |
2633 frame = ngx_quic_alloc_frame(c); | |
2634 if (frame == NULL) { | |
2635 return NGX_ERROR; | |
2636 } | |
2637 | |
2638 ll = &frame->data; | |
2639 b = NULL; | |
2640 | |
2641 for (i = 0; i < ctx->nranges; i++) { | |
2642 len = ngx_quic_create_ack_range(NULL, ctx->ranges[i].gap, | |
2643 ctx->ranges[i].range); | |
2644 | |
2645 left = b ? b->end - b->last : 0; | |
2646 | |
2647 if (left < len) { | |
2648 cl = ngx_quic_alloc_buf(c); | |
2649 if (cl == NULL) { | |
2650 return NGX_ERROR; | |
2651 } | |
2652 | |
2653 *ll = cl; | |
2654 ll = &cl->next; | |
2655 | |
2656 b = cl->buf; | |
2657 left = b->end - b->last; | |
2658 | |
2659 if (left < len) { | |
2660 return NGX_ERROR; | |
2661 } | |
2662 } | |
2663 | |
2664 b->last += ngx_quic_create_ack_range(b->last, ctx->ranges[i].gap, | |
2665 ctx->ranges[i].range); | |
2666 | |
2667 frame->u.ack.ranges_length += len; | |
2668 } | |
2669 | |
2670 *ll = NULL; | |
2671 | |
2672 frame->level = ctx->level; | |
2673 frame->type = NGX_QUIC_FT_ACK; | |
2674 frame->u.ack.largest = ctx->largest_range; | |
2675 frame->u.ack.delay = ack_delay; | |
2676 frame->u.ack.range_count = ctx->nranges; | |
2677 frame->u.ack.first_range = ctx->first_range; | |
2678 | |
2679 ngx_quic_queue_frame(qc, frame); | |
2680 | |
2681 return NGX_OK; | |
2682 } | |
2683 | |
2684 | |
2685 static ngx_int_t | |
2686 ngx_quic_send_cc(ngx_connection_t *c) | |
2687 { | |
2688 ngx_quic_frame_t *frame; | |
2689 ngx_quic_connection_t *qc; | |
2690 | |
2691 qc = ngx_quic_get_connection(c); | |
2692 | |
2693 if (qc->draining) { | |
2694 return NGX_OK; | |
2695 } | |
2696 | |
2697 if (qc->closing | |
2698 && ngx_current_msec - qc->last_cc < NGX_QUIC_CC_MIN_INTERVAL) | |
2699 { | |
2700 /* dot not send CC too often */ | |
2701 return NGX_OK; | |
2702 } | |
2703 | |
2704 frame = ngx_quic_alloc_frame(c); | |
2705 if (frame == NULL) { | |
2706 return NGX_ERROR; | |
2707 } | |
2708 | |
2709 frame->level = qc->error_level; | |
2710 frame->type = qc->error_app ? NGX_QUIC_FT_CONNECTION_CLOSE_APP | |
2711 : NGX_QUIC_FT_CONNECTION_CLOSE; | |
2712 frame->u.close.error_code = qc->error; | |
2713 frame->u.close.frame_type = qc->error_ftype; | |
2714 | |
2715 if (qc->error_reason) { | |
2716 frame->u.close.reason.len = ngx_strlen(qc->error_reason); | |
2717 frame->u.close.reason.data = (u_char *) qc->error_reason; | |
2718 } | |
2719 | |
2720 ngx_quic_queue_frame(qc, frame); | |
2721 | |
2722 qc->last_cc = ngx_current_msec; | |
2723 | |
2724 return ngx_quic_output(c); | |
2725 } | |
2726 | |
2727 | |
2728 static ngx_int_t | |
2729 ngx_quic_send_new_token(ngx_connection_t *c) | |
2730 { | |
2731 time_t expires; | |
2732 ngx_str_t token; | |
2733 ngx_quic_frame_t *frame; | |
2734 ngx_quic_connection_t *qc; | |
2735 | |
2736 qc = ngx_quic_get_connection(c); | |
2737 | |
2738 if (!qc->conf->retry) { | |
2739 return NGX_OK; | |
2740 } | |
2741 | |
2742 expires = ngx_time() + NGX_QUIC_NEW_TOKEN_LIFETIME; | |
2743 | |
2744 if (ngx_quic_new_token(c, qc->conf->av_token_key, &token, NULL, expires, 0) | |
2745 != NGX_OK) | |
2746 { | |
2747 return NGX_ERROR; | |
2748 } | |
2749 | |
2750 frame = ngx_quic_alloc_frame(c); | |
2751 if (frame == NULL) { | |
2752 return NGX_ERROR; | |
2753 } | |
2754 | |
2755 frame->level = ssl_encryption_application; | |
2756 frame->type = NGX_QUIC_FT_NEW_TOKEN; | |
2757 frame->u.token.length = token.len; | |
2758 frame->u.token.data = token.data; | |
2759 | |
2760 ngx_quic_queue_frame(qc, frame); | |
2761 | |
2762 return NGX_OK; | |
2763 } | |
2764 | |
2765 | |
2766 static ngx_int_t | |
2767 ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, | |
2768 ngx_quic_frame_t *f) | |
2769 { | |
2770 ssize_t n; | |
2771 u_char *pos, *end; | |
2772 uint64_t min, max, gap, range; | |
2773 ngx_msec_t send_time; | |
2774 ngx_uint_t i; | |
2775 ngx_quic_send_ctx_t *ctx; | |
2776 ngx_quic_ack_frame_t *ack; | |
2777 ngx_quic_connection_t *qc; | |
2778 | |
2779 qc = ngx_quic_get_connection(c); | |
2780 | |
2781 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
2782 | |
2783 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
2784 "quic ngx_quic_handle_ack_frame level:%d", pkt->level); | |
2785 | |
2786 ack = &f->u.ack; | |
2787 | |
2788 /* | |
2789 * If any computed packet number is negative, an endpoint MUST | |
2790 * generate a connection error of type FRAME_ENCODING_ERROR. | |
2791 * (19.3.1) | |
2792 */ | |
2793 | |
2794 if (ack->first_range > ack->largest) { | |
2795 qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; | |
2796 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
2797 "quic invalid first range in ack frame"); | |
2798 return NGX_ERROR; | |
2799 } | |
2800 | |
2801 min = ack->largest - ack->first_range; | |
2802 max = ack->largest; | |
2803 | |
2804 if (ngx_quic_handle_ack_frame_range(c, ctx, min, max, &send_time) | |
2805 != NGX_OK) | |
2806 { | |
2807 return NGX_ERROR; | |
2808 } | |
2809 | |
2810 /* 13.2.3. Receiver Tracking of ACK Frames */ | |
2811 if (ctx->largest_ack < max || ctx->largest_ack == NGX_QUIC_UNSET_PN) { | |
2812 ctx->largest_ack = max; | |
2813 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
2814 "quic updated largest received ack:%uL", max); | |
2815 | |
2816 /* | |
2817 * An endpoint generates an RTT sample on receiving an | |
2818 * ACK frame that meets the following two conditions: | |
2819 * | |
2820 * - the largest acknowledged packet number is newly acknowledged | |
2821 * - at least one of the newly acknowledged packets was ack-eliciting. | |
2822 */ | |
2823 | |
2824 if (send_time != NGX_TIMER_INFINITE) { | |
2825 ngx_quic_rtt_sample(c, ack, pkt->level, send_time); | |
2826 } | |
2827 } | |
2828 | |
2829 if (f->data) { | |
2830 pos = f->data->buf->pos; | |
2831 end = f->data->buf->last; | |
2832 | |
2833 } else { | |
2834 pos = NULL; | |
2835 end = NULL; | |
2836 } | |
2837 | |
2838 for (i = 0; i < ack->range_count; i++) { | |
2839 | |
2840 n = ngx_quic_parse_ack_range(pkt->log, pos, end, &gap, &range); | |
2841 if (n == NGX_ERROR) { | |
2842 return NGX_ERROR; | |
2843 } | |
2844 pos += n; | |
2845 | |
2846 if (gap + 2 > min) { | |
2847 qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; | |
2848 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
2849 "quic invalid range:%ui in ack frame", i); | |
2850 return NGX_ERROR; | |
2851 } | |
2852 | |
2853 max = min - gap - 2; | |
2854 | |
2855 if (range > max) { | |
2856 qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; | |
2857 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
2858 "quic invalid range:%ui in ack frame", i); | |
2859 return NGX_ERROR; | |
2860 } | |
2861 | |
2862 min = max - range; | |
2863 | |
2864 if (ngx_quic_handle_ack_frame_range(c, ctx, min, max, &send_time) | |
2865 != NGX_OK) | |
2866 { | |
2867 return NGX_ERROR; | |
2868 } | |
2869 } | |
2870 | |
2871 return ngx_quic_detect_lost(c); | |
2872 } | |
2873 | |
2874 | |
2875 static ngx_int_t | |
2876 ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
2877 uint64_t min, uint64_t max, ngx_msec_t *send_time) | |
2878 { | |
2879 ngx_uint_t found; | |
2880 ngx_queue_t *q; | |
2881 ngx_quic_frame_t *f; | |
2882 ngx_quic_connection_t *qc; | |
2883 | |
2884 qc = ngx_quic_get_connection(c); | |
2885 | |
2886 *send_time = NGX_TIMER_INFINITE; | |
2887 found = 0; | |
2888 | |
2889 q = ngx_queue_last(&ctx->sent); | |
2890 | |
2891 while (q != ngx_queue_sentinel(&ctx->sent)) { | |
2892 | |
2893 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
2894 q = ngx_queue_prev(q); | |
2895 | |
2896 if (f->pnum >= min && f->pnum <= max) { | |
2897 ngx_quic_congestion_ack(c, f); | |
2898 | |
2899 switch (f->type) { | |
2900 case NGX_QUIC_FT_ACK: | |
2901 case NGX_QUIC_FT_ACK_ECN: | |
2902 ngx_quic_drop_ack_ranges(c, ctx, f->u.ack.largest); | |
2903 break; | |
2904 | |
2905 case NGX_QUIC_FT_STREAM0: | |
2906 case NGX_QUIC_FT_STREAM1: | |
2907 case NGX_QUIC_FT_STREAM2: | |
2908 case NGX_QUIC_FT_STREAM3: | |
2909 case NGX_QUIC_FT_STREAM4: | |
2910 case NGX_QUIC_FT_STREAM5: | |
2911 case NGX_QUIC_FT_STREAM6: | |
2912 case NGX_QUIC_FT_STREAM7: | |
2913 ngx_quic_handle_stream_ack(c, f); | |
2914 break; | |
2915 } | |
2916 | |
2917 if (f->pnum == max) { | |
2918 *send_time = f->last; | |
2919 } | |
2920 | |
2921 ngx_queue_remove(&f->queue); | |
2922 ngx_quic_free_frame(c, f); | |
2923 found = 1; | |
2924 } | |
2925 } | |
2926 | |
2927 if (!found) { | |
2928 | |
2929 if (max < ctx->pnum) { | |
2930 /* duplicate ACK or ACK for non-ack-eliciting frame */ | |
2931 return NGX_OK; | |
2932 } | |
2933 | |
2934 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
2935 "quic ACK for the packet not sent"); | |
2936 | |
2937 qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; | |
2938 qc->error_ftype = NGX_QUIC_FT_ACK; | |
2939 qc->error_reason = "unknown packet number"; | |
2940 | |
2941 return NGX_ERROR; | |
2942 } | |
2943 | |
2944 if (!qc->push.timer_set) { | |
2945 ngx_post_event(&qc->push, &ngx_posted_events); | |
2946 } | |
2947 | |
2948 qc->pto_count = 0; | |
2949 | |
2950 return NGX_OK; | |
2951 } | |
2952 | |
2953 | |
2954 static void | |
2955 ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack, | |
2956 enum ssl_encryption_level_t level, ngx_msec_t send_time) | |
2957 { | |
2958 ngx_msec_t latest_rtt, ack_delay, adjusted_rtt, rttvar_sample; | |
2959 ngx_quic_connection_t *qc; | |
2960 | |
2961 qc = ngx_quic_get_connection(c); | |
2962 | |
2963 latest_rtt = ngx_current_msec - send_time; | |
2964 qc->latest_rtt = latest_rtt; | |
2965 | |
2966 if (qc->min_rtt == NGX_TIMER_INFINITE) { | |
2967 qc->min_rtt = latest_rtt; | |
2968 qc->avg_rtt = latest_rtt; | |
2969 qc->rttvar = latest_rtt / 2; | |
2970 | |
2971 } else { | |
2972 qc->min_rtt = ngx_min(qc->min_rtt, latest_rtt); | |
2973 | |
2974 ack_delay = ack->delay * (1 << qc->ctp.ack_delay_exponent) / 1000; | |
2975 | |
2976 if (c->ssl->handshaked) { | |
2977 ack_delay = ngx_min(ack_delay, qc->ctp.max_ack_delay); | |
2978 } | |
2979 | |
2980 adjusted_rtt = latest_rtt; | |
2981 | |
2982 if (qc->min_rtt + ack_delay < latest_rtt) { | |
2983 adjusted_rtt -= ack_delay; | |
2984 } | |
2985 | |
2986 qc->avg_rtt = 0.875 * qc->avg_rtt + 0.125 * adjusted_rtt; | |
2987 rttvar_sample = ngx_abs((ngx_msec_int_t) (qc->avg_rtt - adjusted_rtt)); | |
2988 qc->rttvar = 0.75 * qc->rttvar + 0.25 * rttvar_sample; | |
2989 } | |
2990 | |
2991 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
2992 "quic rtt sample latest:%M min:%M avg:%M var:%M", | |
2993 latest_rtt, qc->min_rtt, qc->avg_rtt, qc->rttvar); | |
2994 } | |
2995 | |
2996 | |
2997 ngx_msec_t | |
2998 ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | |
2999 { | |
3000 ngx_msec_t duration; | |
3001 ngx_quic_connection_t *qc; | |
3002 | |
3003 qc = ngx_quic_get_connection(c); | |
3004 | |
3005 /* PTO calculation: quic-recovery, Appendix 8 */ | |
3006 duration = qc->avg_rtt; | |
3007 | |
3008 duration += ngx_max(4 * qc->rttvar, NGX_QUIC_TIME_GRANULARITY); | |
3009 duration <<= qc->pto_count; | |
3010 | |
3011 if (qc->congestion.in_flight == 0) { /* no in-flight packets */ | |
3012 return duration; | |
3013 } | |
3014 | |
3015 if (ctx->level == ssl_encryption_application && c->ssl->handshaked) { | |
3016 duration += qc->ctp.max_ack_delay << qc->pto_count; | |
3017 } | |
3018 | |
3019 return duration; | |
3020 } | |
3021 | |
3022 | |
3023 static ngx_int_t | |
3024 ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, | 1954 ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, |
3025 ngx_quic_frame_t *frame) | 1955 ngx_quic_frame_t *frame) |
3026 { | 1956 { |
3027 uint64_t last; | 1957 uint64_t last; |
3028 ngx_int_t rc; | 1958 ngx_int_t rc; |
3168 | 2098 |
3169 return NGX_OK; | 2099 return NGX_OK; |
3170 } | 2100 } |
3171 | 2101 |
3172 | 2102 |
3173 ngx_int_t | |
3174 ngx_quic_output(ngx_connection_t *c) | |
3175 { | |
3176 off_t max; | |
3177 size_t len, min, in_flight; | |
3178 ssize_t n; | |
3179 u_char *p; | |
3180 ngx_uint_t i, pad; | |
3181 ngx_quic_send_ctx_t *ctx; | |
3182 ngx_quic_congestion_t *cg; | |
3183 ngx_quic_connection_t *qc; | |
3184 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
3185 | |
3186 c->log->action = "sending frames"; | |
3187 | |
3188 qc = ngx_quic_get_connection(c); | |
3189 cg = &qc->congestion; | |
3190 | |
3191 in_flight = cg->in_flight; | |
3192 | |
3193 for ( ;; ) { | |
3194 p = dst; | |
3195 | |
3196 len = ngx_min(qc->ctp.max_udp_payload_size, | |
3197 NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); | |
3198 | |
3199 if (!qc->validated) { | |
3200 max = qc->received * 3; | |
3201 max = (c->sent >= max) ? 0 : max - c->sent; | |
3202 len = ngx_min(len, (size_t) max); | |
3203 } | |
3204 | |
3205 pad = ngx_quic_get_padding_level(c); | |
3206 | |
3207 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | |
3208 | |
3209 ctx = &qc->send_ctx[i]; | |
3210 | |
3211 if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { | |
3212 return NGX_ERROR; | |
3213 } | |
3214 | |
3215 min = (i == pad && p - dst < NGX_QUIC_MIN_INITIAL_SIZE) | |
3216 ? NGX_QUIC_MIN_INITIAL_SIZE - (p - dst) : 0; | |
3217 | |
3218 n = ngx_quic_output_packet(c, ctx, p, len, min); | |
3219 if (n == NGX_ERROR) { | |
3220 return NGX_ERROR; | |
3221 } | |
3222 | |
3223 p += n; | |
3224 len -= n; | |
3225 } | |
3226 | |
3227 len = p - dst; | |
3228 if (len == 0) { | |
3229 break; | |
3230 } | |
3231 | |
3232 n = ngx_quic_send(c, dst, len); | |
3233 if (n == NGX_ERROR) { | |
3234 return NGX_ERROR; | |
3235 } | |
3236 } | |
3237 | |
3238 if (in_flight != cg->in_flight && !qc->send_timer_set && !qc->closing) { | |
3239 qc->send_timer_set = 1; | |
3240 ngx_add_timer(c->read, qc->tp.max_idle_timeout); | |
3241 } | |
3242 | |
3243 ngx_quic_set_lost_timer(c); | |
3244 | |
3245 return NGX_OK; | |
3246 } | |
3247 | |
3248 | |
3249 static ngx_uint_t | |
3250 ngx_quic_get_padding_level(ngx_connection_t *c) | |
3251 { | |
3252 ngx_queue_t *q; | |
3253 ngx_quic_frame_t *f; | |
3254 ngx_quic_send_ctx_t *ctx; | |
3255 ngx_quic_connection_t *qc; | |
3256 | |
3257 /* | |
3258 * 14.1. Initial Datagram Size | |
3259 * | |
3260 * Similarly, a server MUST expand the payload of all UDP datagrams | |
3261 * carrying ack-eliciting Initial packets to at least the smallest | |
3262 * allowed maximum datagram size of 1200 bytes | |
3263 */ | |
3264 | |
3265 qc = ngx_quic_get_connection(c); | |
3266 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial); | |
3267 | |
3268 for (q = ngx_queue_head(&ctx->frames); | |
3269 q != ngx_queue_sentinel(&ctx->frames); | |
3270 q = ngx_queue_next(q)) | |
3271 { | |
3272 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3273 | |
3274 if (f->need_ack) { | |
3275 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); | |
3276 | |
3277 if (ngx_queue_empty(&ctx->frames)) { | |
3278 return 0; | |
3279 } | |
3280 | |
3281 return 1; | |
3282 } | |
3283 } | |
3284 | |
3285 return NGX_QUIC_SEND_CTX_LAST; | |
3286 } | |
3287 | |
3288 | |
3289 static ngx_int_t | |
3290 ngx_quic_generate_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | |
3291 { | |
3292 ngx_msec_t delay; | |
3293 ngx_quic_connection_t *qc; | |
3294 | |
3295 if (!ctx->send_ack) { | |
3296 return NGX_OK; | |
3297 } | |
3298 | |
3299 if (ctx->level == ssl_encryption_application) { | |
3300 | |
3301 delay = ngx_current_msec - ctx->ack_delay_start; | |
3302 qc = ngx_quic_get_connection(c); | |
3303 | |
3304 if (ctx->send_ack < NGX_QUIC_MAX_ACK_GAP | |
3305 && delay < qc->tp.max_ack_delay) | |
3306 { | |
3307 if (!qc->push.timer_set && !qc->closing) { | |
3308 ngx_add_timer(&qc->push, | |
3309 qc->tp.max_ack_delay - delay); | |
3310 } | |
3311 | |
3312 return NGX_OK; | |
3313 } | |
3314 } | |
3315 | |
3316 if (ngx_quic_send_ack(c, ctx) != NGX_OK) { | |
3317 return NGX_ERROR; | |
3318 } | |
3319 | |
3320 ctx->send_ack = 0; | |
3321 | |
3322 return NGX_OK; | |
3323 } | |
3324 | |
3325 | |
3326 static ssize_t | |
3327 ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
3328 u_char *data, size_t max, size_t min) | |
3329 { | |
3330 size_t len, hlen, pad_len; | |
3331 u_char *p; | |
3332 ssize_t flen; | |
3333 ngx_str_t out, res; | |
3334 ngx_int_t rc; | |
3335 ngx_uint_t nframes; | |
3336 ngx_msec_t now; | |
3337 ngx_queue_t *q; | |
3338 ngx_quic_frame_t *f; | |
3339 ngx_quic_header_t pkt; | |
3340 ngx_quic_congestion_t *cg; | |
3341 ngx_quic_connection_t *qc; | |
3342 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
3343 | |
3344 if (ngx_queue_empty(&ctx->frames)) { | |
3345 return 0; | |
3346 } | |
3347 | |
3348 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3349 "quic output %s packet max:%uz min:%uz", | |
3350 ngx_quic_level_name(ctx->level), max, min); | |
3351 | |
3352 qc = ngx_quic_get_connection(c); | |
3353 cg = &qc->congestion; | |
3354 | |
3355 hlen = (ctx->level == ssl_encryption_application) | |
3356 ? NGX_QUIC_MAX_SHORT_HEADER | |
3357 : NGX_QUIC_MAX_LONG_HEADER; | |
3358 | |
3359 hlen += EVP_GCM_TLS_TAG_LEN; | |
3360 hlen -= NGX_QUIC_MAX_CID_LEN - qc->scid.len; | |
3361 | |
3362 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | |
3363 | |
3364 now = ngx_current_msec; | |
3365 nframes = 0; | |
3366 p = src; | |
3367 len = 0; | |
3368 | |
3369 for (q = ngx_queue_head(&ctx->frames); | |
3370 q != ngx_queue_sentinel(&ctx->frames); | |
3371 q = ngx_queue_next(q)) | |
3372 { | |
3373 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3374 | |
3375 if (!pkt.need_ack && f->need_ack && max > cg->window) { | |
3376 max = cg->window; | |
3377 } | |
3378 | |
3379 if (hlen + len >= max) { | |
3380 break; | |
3381 } | |
3382 | |
3383 if (hlen + len + f->len > max) { | |
3384 rc = ngx_quic_split_frame(c, f, max - hlen - len); | |
3385 | |
3386 if (rc == NGX_ERROR) { | |
3387 return NGX_ERROR; | |
3388 } | |
3389 | |
3390 if (rc == NGX_DECLINED) { | |
3391 break; | |
3392 } | |
3393 } | |
3394 | |
3395 if (f->need_ack) { | |
3396 pkt.need_ack = 1; | |
3397 } | |
3398 | |
3399 ngx_quic_log_frame(c->log, f, 1); | |
3400 | |
3401 flen = ngx_quic_create_frame(p, f); | |
3402 if (flen == -1) { | |
3403 return NGX_ERROR; | |
3404 } | |
3405 | |
3406 len += flen; | |
3407 p += flen; | |
3408 | |
3409 f->pnum = ctx->pnum; | |
3410 f->first = now; | |
3411 f->last = now; | |
3412 f->plen = 0; | |
3413 | |
3414 nframes++; | |
3415 | |
3416 if (f->flush) { | |
3417 break; | |
3418 } | |
3419 } | |
3420 | |
3421 if (nframes == 0) { | |
3422 return 0; | |
3423 } | |
3424 | |
3425 out.data = src; | |
3426 out.len = len; | |
3427 | |
3428 pkt.keys = qc->keys; | |
3429 pkt.flags = NGX_QUIC_PKT_FIXED_BIT; | |
3430 | |
3431 if (ctx->level == ssl_encryption_initial) { | |
3432 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL; | |
3433 | |
3434 } else if (ctx->level == ssl_encryption_handshake) { | |
3435 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_HANDSHAKE; | |
3436 | |
3437 } else { | |
3438 if (qc->key_phase) { | |
3439 pkt.flags |= NGX_QUIC_PKT_KPHASE; | |
3440 } | |
3441 } | |
3442 | |
3443 ngx_quic_set_packet_number(&pkt, ctx); | |
3444 | |
3445 pkt.version = qc->version; | |
3446 pkt.log = c->log; | |
3447 pkt.level = ctx->level; | |
3448 pkt.dcid = qc->scid; | |
3449 pkt.scid = qc->dcid; | |
3450 | |
3451 pad_len = 4; | |
3452 | |
3453 if (min) { | |
3454 hlen = EVP_GCM_TLS_TAG_LEN | |
3455 + ngx_quic_create_header(&pkt, NULL, out.len, NULL); | |
3456 | |
3457 if (min > hlen + pad_len) { | |
3458 pad_len = min - hlen; | |
3459 } | |
3460 } | |
3461 | |
3462 if (out.len < pad_len) { | |
3463 ngx_memset(p, NGX_QUIC_FT_PADDING, pad_len - out.len); | |
3464 out.len = pad_len; | |
3465 } | |
3466 | |
3467 pkt.payload = out; | |
3468 | |
3469 res.data = data; | |
3470 | |
3471 ngx_log_debug6(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3472 "quic packet tx %s bytes:%ui" | |
3473 " need_ack:%d number:%L encoded nl:%d trunc:0x%xD", | |
3474 ngx_quic_level_name(ctx->level), out.len, pkt.need_ack, | |
3475 pkt.number, pkt.num_len, pkt.trunc); | |
3476 | |
3477 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { | |
3478 return NGX_ERROR; | |
3479 } | |
3480 | |
3481 ctx->pnum++; | |
3482 | |
3483 if (pkt.need_ack) { | |
3484 /* move frames into the sent queue to wait for ack */ | |
3485 | |
3486 if (!qc->closing) { | |
3487 q = ngx_queue_head(&ctx->frames); | |
3488 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3489 f->plen = res.len; | |
3490 | |
3491 do { | |
3492 q = ngx_queue_head(&ctx->frames); | |
3493 ngx_queue_remove(q); | |
3494 ngx_queue_insert_tail(&ctx->sent, q); | |
3495 } while (--nframes); | |
3496 } | |
3497 | |
3498 cg->in_flight += res.len; | |
3499 | |
3500 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3501 "quic congestion send if:%uz", cg->in_flight); | |
3502 } | |
3503 | |
3504 while (nframes--) { | |
3505 q = ngx_queue_head(&ctx->frames); | |
3506 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3507 | |
3508 ngx_queue_remove(q); | |
3509 ngx_quic_free_frame(c, f); | |
3510 } | |
3511 | |
3512 return res.len; | |
3513 } | |
3514 | |
3515 | |
3516 static ssize_t | |
3517 ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len) | |
3518 { | |
3519 ngx_buf_t b; | |
3520 ngx_chain_t cl, *res; | |
3521 | |
3522 ngx_memzero(&b, sizeof(ngx_buf_t)); | |
3523 | |
3524 b.pos = b.start = buf; | |
3525 b.last = b.end = buf + len; | |
3526 b.last_buf = 1; | |
3527 b.temporary = 1; | |
3528 | |
3529 cl.buf = &b; | |
3530 cl.next= NULL; | |
3531 | |
3532 res = c->send_chain(c, &cl, 0); | |
3533 if (res == NGX_CHAIN_ERROR) { | |
3534 return NGX_ERROR; | |
3535 } | |
3536 | |
3537 return len; | |
3538 } | |
3539 | |
3540 | |
3541 static void | |
3542 ngx_quic_set_packet_number(ngx_quic_header_t *pkt, ngx_quic_send_ctx_t *ctx) | |
3543 { | |
3544 uint64_t delta; | |
3545 | |
3546 delta = ctx->pnum - ctx->largest_ack; | |
3547 pkt->number = ctx->pnum; | |
3548 | |
3549 if (delta <= 0x7F) { | |
3550 pkt->num_len = 1; | |
3551 pkt->trunc = ctx->pnum & 0xff; | |
3552 | |
3553 } else if (delta <= 0x7FFF) { | |
3554 pkt->num_len = 2; | |
3555 pkt->flags |= 0x1; | |
3556 pkt->trunc = ctx->pnum & 0xffff; | |
3557 | |
3558 } else if (delta <= 0x7FFFFF) { | |
3559 pkt->num_len = 3; | |
3560 pkt->flags |= 0x2; | |
3561 pkt->trunc = ctx->pnum & 0xffffff; | |
3562 | |
3563 } else { | |
3564 pkt->num_len = 4; | |
3565 pkt->flags |= 0x3; | |
3566 pkt->trunc = ctx->pnum & 0xffffffff; | |
3567 } | |
3568 } | |
3569 | |
3570 | |
3571 static void | |
3572 ngx_quic_pto_handler(ngx_event_t *ev) | |
3573 { | |
3574 ngx_uint_t i; | |
3575 ngx_msec_t now; | |
3576 ngx_queue_t *q, *next; | |
3577 ngx_connection_t *c; | |
3578 ngx_quic_frame_t *f; | |
3579 ngx_quic_send_ctx_t *ctx; | |
3580 ngx_quic_connection_t *qc; | |
3581 | |
3582 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer"); | |
3583 | |
3584 c = ev->data; | |
3585 qc = ngx_quic_get_connection(c); | |
3586 now = ngx_current_msec; | |
3587 | |
3588 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | |
3589 | |
3590 ctx = &qc->send_ctx[i]; | |
3591 | |
3592 if (ngx_queue_empty(&ctx->sent)) { | |
3593 continue; | |
3594 } | |
3595 | |
3596 q = ngx_queue_head(&ctx->sent); | |
3597 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3598 | |
3599 if (f->pnum <= ctx->largest_ack | |
3600 && ctx->largest_ack != NGX_QUIC_UNSET_PN) | |
3601 { | |
3602 continue; | |
3603 } | |
3604 | |
3605 if ((ngx_msec_int_t) (f->last + ngx_quic_pto(c, ctx) - now) > 0) { | |
3606 continue; | |
3607 } | |
3608 | |
3609 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3610 "quic pto %s pto_count:%ui", | |
3611 ngx_quic_level_name(ctx->level), qc->pto_count); | |
3612 | |
3613 for (q = ngx_queue_head(&ctx->frames); | |
3614 q != ngx_queue_sentinel(&ctx->frames); | |
3615 /* void */) | |
3616 { | |
3617 next = ngx_queue_next(q); | |
3618 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3619 | |
3620 if (f->type == NGX_QUIC_FT_PING) { | |
3621 ngx_queue_remove(q); | |
3622 ngx_quic_free_frame(c, f); | |
3623 } | |
3624 | |
3625 q = next; | |
3626 } | |
3627 | |
3628 for (q = ngx_queue_head(&ctx->sent); | |
3629 q != ngx_queue_sentinel(&ctx->sent); | |
3630 /* void */) | |
3631 { | |
3632 next = ngx_queue_next(q); | |
3633 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3634 | |
3635 if (f->type == NGX_QUIC_FT_PING) { | |
3636 ngx_quic_congestion_lost(c, f); | |
3637 ngx_queue_remove(q); | |
3638 ngx_quic_free_frame(c, f); | |
3639 } | |
3640 | |
3641 q = next; | |
3642 } | |
3643 | |
3644 /* enforce 2 udp datagrams */ | |
3645 | |
3646 f = ngx_quic_alloc_frame(c); | |
3647 if (f == NULL) { | |
3648 break; | |
3649 } | |
3650 | |
3651 f->level = ctx->level; | |
3652 f->type = NGX_QUIC_FT_PING; | |
3653 f->flush = 1; | |
3654 | |
3655 ngx_quic_queue_frame(qc, f); | |
3656 | |
3657 f = ngx_quic_alloc_frame(c); | |
3658 if (f == NULL) { | |
3659 break; | |
3660 } | |
3661 | |
3662 f->level = ctx->level; | |
3663 f->type = NGX_QUIC_FT_PING; | |
3664 | |
3665 ngx_quic_queue_frame(qc, f); | |
3666 } | |
3667 | |
3668 qc->pto_count++; | |
3669 | |
3670 ngx_quic_connstate_dbg(c); | |
3671 } | |
3672 | |
3673 | |
3674 static void | 2103 static void |
3675 ngx_quic_push_handler(ngx_event_t *ev) | 2104 ngx_quic_push_handler(ngx_event_t *ev) |
3676 { | 2105 { |
3677 ngx_connection_t *c; | 2106 ngx_connection_t *c; |
3678 | 2107 |
3684 ngx_quic_close_connection(c, NGX_ERROR); | 2113 ngx_quic_close_connection(c, NGX_ERROR); |
3685 return; | 2114 return; |
3686 } | 2115 } |
3687 | 2116 |
3688 ngx_quic_connstate_dbg(c); | 2117 ngx_quic_connstate_dbg(c); |
3689 } | |
3690 | |
3691 | |
3692 static | |
3693 void ngx_quic_lost_handler(ngx_event_t *ev) | |
3694 { | |
3695 ngx_connection_t *c; | |
3696 | |
3697 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic lost timer"); | |
3698 | |
3699 c = ev->data; | |
3700 | |
3701 if (ngx_quic_detect_lost(c) != NGX_OK) { | |
3702 ngx_quic_close_connection(c, NGX_ERROR); | |
3703 } | |
3704 | |
3705 ngx_quic_connstate_dbg(c); | |
3706 } | |
3707 | |
3708 | |
3709 static ngx_int_t | |
3710 ngx_quic_detect_lost(ngx_connection_t *c) | |
3711 { | |
3712 ngx_uint_t i; | |
3713 ngx_msec_t now, wait, thr; | |
3714 ngx_queue_t *q; | |
3715 ngx_quic_frame_t *start; | |
3716 ngx_quic_send_ctx_t *ctx; | |
3717 ngx_quic_connection_t *qc; | |
3718 | |
3719 qc = ngx_quic_get_connection(c); | |
3720 now = ngx_current_msec; | |
3721 thr = ngx_quic_lost_threshold(qc); | |
3722 | |
3723 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | |
3724 | |
3725 ctx = &qc->send_ctx[i]; | |
3726 | |
3727 if (ctx->largest_ack == NGX_QUIC_UNSET_PN) { | |
3728 continue; | |
3729 } | |
3730 | |
3731 while (!ngx_queue_empty(&ctx->sent)) { | |
3732 | |
3733 q = ngx_queue_head(&ctx->sent); | |
3734 start = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3735 | |
3736 if (start->pnum > ctx->largest_ack) { | |
3737 break; | |
3738 } | |
3739 | |
3740 wait = start->last + thr - now; | |
3741 | |
3742 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3743 "quic detect_lost pnum:%uL thr:%M wait:%i level:%d", | |
3744 start->pnum, thr, (ngx_int_t) wait, start->level); | |
3745 | |
3746 if ((ngx_msec_int_t) wait > 0 | |
3747 && ctx->largest_ack - start->pnum < NGX_QUIC_PKT_THR) | |
3748 { | |
3749 break; | |
3750 } | |
3751 | |
3752 ngx_quic_resend_frames(c, ctx); | |
3753 } | |
3754 } | |
3755 | |
3756 ngx_quic_set_lost_timer(c); | |
3757 | |
3758 return NGX_OK; | |
3759 } | |
3760 | |
3761 | |
3762 static void | |
3763 ngx_quic_set_lost_timer(ngx_connection_t *c) | |
3764 { | |
3765 ngx_uint_t i; | |
3766 ngx_msec_t now; | |
3767 ngx_queue_t *q; | |
3768 ngx_msec_int_t lost, pto, w; | |
3769 ngx_quic_frame_t *f; | |
3770 ngx_quic_send_ctx_t *ctx; | |
3771 ngx_quic_connection_t *qc; | |
3772 | |
3773 qc = ngx_quic_get_connection(c); | |
3774 now = ngx_current_msec; | |
3775 | |
3776 lost = -1; | |
3777 pto = -1; | |
3778 | |
3779 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | |
3780 ctx = &qc->send_ctx[i]; | |
3781 | |
3782 if (ngx_queue_empty(&ctx->sent)) { | |
3783 continue; | |
3784 } | |
3785 | |
3786 if (ctx->largest_ack != NGX_QUIC_UNSET_PN) { | |
3787 q = ngx_queue_head(&ctx->sent); | |
3788 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3789 w = (ngx_msec_int_t) (f->last + ngx_quic_lost_threshold(qc) - now); | |
3790 | |
3791 if (f->pnum <= ctx->largest_ack) { | |
3792 if (w < 0 || ctx->largest_ack - f->pnum >= NGX_QUIC_PKT_THR) { | |
3793 w = 0; | |
3794 } | |
3795 | |
3796 if (lost == -1 || w < lost) { | |
3797 lost = w; | |
3798 } | |
3799 } | |
3800 } | |
3801 | |
3802 q = ngx_queue_last(&ctx->sent); | |
3803 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3804 w = (ngx_msec_int_t) (f->last + ngx_quic_pto(c, ctx) - now); | |
3805 | |
3806 if (w < 0) { | |
3807 w = 0; | |
3808 } | |
3809 | |
3810 if (pto == -1 || w < pto) { | |
3811 pto = w; | |
3812 } | |
3813 } | |
3814 | |
3815 if (qc->pto.timer_set) { | |
3816 ngx_del_timer(&qc->pto); | |
3817 } | |
3818 | |
3819 if (lost != -1) { | |
3820 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3821 "quic lost timer lost:%M", lost); | |
3822 | |
3823 qc->pto.handler = ngx_quic_lost_handler; | |
3824 ngx_add_timer(&qc->pto, lost); | |
3825 return; | |
3826 } | |
3827 | |
3828 if (pto != -1) { | |
3829 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3830 "quic lost timer pto:%M", pto); | |
3831 | |
3832 qc->pto.handler = ngx_quic_pto_handler; | |
3833 ngx_add_timer(&qc->pto, pto); | |
3834 return; | |
3835 } | |
3836 | |
3837 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic lost timer unset"); | |
3838 } | |
3839 | |
3840 | |
3841 static void | |
3842 ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | |
3843 { | |
3844 size_t n; | |
3845 ngx_buf_t *b; | |
3846 ngx_queue_t *q; | |
3847 ngx_quic_frame_t *f, *start; | |
3848 ngx_quic_stream_t *sn; | |
3849 ngx_quic_connection_t *qc; | |
3850 | |
3851 qc = ngx_quic_get_connection(c); | |
3852 q = ngx_queue_head(&ctx->sent); | |
3853 start = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3854 | |
3855 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3856 "quic resend packet pnum:%uL", start->pnum); | |
3857 | |
3858 ngx_quic_congestion_lost(c, start); | |
3859 | |
3860 do { | |
3861 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3862 | |
3863 if (f->pnum != start->pnum) { | |
3864 break; | |
3865 } | |
3866 | |
3867 q = ngx_queue_next(q); | |
3868 | |
3869 ngx_queue_remove(&f->queue); | |
3870 | |
3871 switch (f->type) { | |
3872 case NGX_QUIC_FT_ACK: | |
3873 case NGX_QUIC_FT_ACK_ECN: | |
3874 if (ctx->level == ssl_encryption_application) { | |
3875 /* force generation of most recent acknowledgment */ | |
3876 ctx->send_ack = NGX_QUIC_MAX_ACK_GAP; | |
3877 } | |
3878 | |
3879 ngx_quic_free_frame(c, f); | |
3880 break; | |
3881 | |
3882 case NGX_QUIC_FT_PING: | |
3883 case NGX_QUIC_FT_PATH_RESPONSE: | |
3884 case NGX_QUIC_FT_CONNECTION_CLOSE: | |
3885 ngx_quic_free_frame(c, f); | |
3886 break; | |
3887 | |
3888 case NGX_QUIC_FT_MAX_DATA: | |
3889 f->u.max_data.max_data = qc->streams.recv_max_data; | |
3890 ngx_quic_queue_frame(qc, f); | |
3891 break; | |
3892 | |
3893 case NGX_QUIC_FT_MAX_STREAMS: | |
3894 case NGX_QUIC_FT_MAX_STREAMS2: | |
3895 f->u.max_streams.limit = f->u.max_streams.bidi | |
3896 ? qc->streams.client_max_streams_bidi | |
3897 : qc->streams.client_max_streams_uni; | |
3898 ngx_quic_queue_frame(qc, f); | |
3899 break; | |
3900 | |
3901 case NGX_QUIC_FT_MAX_STREAM_DATA: | |
3902 sn = ngx_quic_find_stream(&qc->streams.tree, | |
3903 f->u.max_stream_data.id); | |
3904 if (sn == NULL) { | |
3905 ngx_quic_free_frame(c, f); | |
3906 break; | |
3907 } | |
3908 | |
3909 b = sn->b; | |
3910 n = sn->fs.received + (b->pos - b->start) + (b->end - b->last); | |
3911 | |
3912 if (f->u.max_stream_data.limit < n) { | |
3913 f->u.max_stream_data.limit = n; | |
3914 } | |
3915 | |
3916 ngx_quic_queue_frame(qc, f); | |
3917 break; | |
3918 | |
3919 case NGX_QUIC_FT_STREAM0: | |
3920 case NGX_QUIC_FT_STREAM1: | |
3921 case NGX_QUIC_FT_STREAM2: | |
3922 case NGX_QUIC_FT_STREAM3: | |
3923 case NGX_QUIC_FT_STREAM4: | |
3924 case NGX_QUIC_FT_STREAM5: | |
3925 case NGX_QUIC_FT_STREAM6: | |
3926 case NGX_QUIC_FT_STREAM7: | |
3927 sn = ngx_quic_find_stream(&qc->streams.tree, f->u.stream.stream_id); | |
3928 | |
3929 if (sn && sn->c->write->error) { | |
3930 /* RESET_STREAM was sent */ | |
3931 ngx_quic_free_frame(c, f); | |
3932 break; | |
3933 } | |
3934 | |
3935 /* fall through */ | |
3936 | |
3937 default: | |
3938 ngx_queue_insert_tail(&ctx->frames, &f->queue); | |
3939 } | |
3940 | |
3941 } while (q != ngx_queue_sentinel(&ctx->sent)); | |
3942 | |
3943 if (qc->closing) { | |
3944 return; | |
3945 } | |
3946 | |
3947 ngx_post_event(&qc->push, &ngx_posted_events); | |
3948 } | 2118 } |
3949 | 2119 |
3950 | 2120 |
3951 void | 2121 void |
3952 ngx_quic_shutdown_quic(ngx_connection_t *c) | 2122 ngx_quic_shutdown_quic(ngx_connection_t *c) |
3979 | 2149 |
3980 ngx_quic_finalize_connection(c, qc->shutdown_code, qc->shutdown_reason); | 2150 ngx_quic_finalize_connection(c, qc->shutdown_code, qc->shutdown_reason); |
3981 } | 2151 } |
3982 | 2152 |
3983 | 2153 |
3984 | |
3985 static void | |
3986 ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f) | |
3987 { | |
3988 ngx_msec_t timer; | |
3989 ngx_quic_congestion_t *cg; | |
3990 ngx_quic_connection_t *qc; | |
3991 | |
3992 if (f->plen == 0) { | |
3993 return; | |
3994 } | |
3995 | |
3996 qc = ngx_quic_get_connection(c); | |
3997 cg = &qc->congestion; | |
3998 | |
3999 cg->in_flight -= f->plen; | |
4000 | |
4001 timer = f->last - cg->recovery_start; | |
4002 | |
4003 if ((ngx_msec_int_t) timer <= 0) { | |
4004 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
4005 "quic congestion ack recovery win:%uz ss:%z if:%uz", | |
4006 cg->window, cg->ssthresh, cg->in_flight); | |
4007 | |
4008 return; | |
4009 } | |
4010 | |
4011 if (cg->window < cg->ssthresh) { | |
4012 cg->window += f->plen; | |
4013 | |
4014 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
4015 "quic congestion slow start win:%uz ss:%z if:%uz", | |
4016 cg->window, cg->ssthresh, cg->in_flight); | |
4017 | |
4018 } else { | |
4019 cg->window += qc->tp.max_udp_payload_size * f->plen / cg->window; | |
4020 | |
4021 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
4022 "quic congestion avoidance win:%uz ss:%z if:%uz", | |
4023 cg->window, cg->ssthresh, cg->in_flight); | |
4024 } | |
4025 | |
4026 /* prevent recovery_start from wrapping */ | |
4027 | |
4028 timer = cg->recovery_start - ngx_current_msec + qc->tp.max_idle_timeout * 2; | |
4029 | |
4030 if ((ngx_msec_int_t) timer < 0) { | |
4031 cg->recovery_start = ngx_current_msec - qc->tp.max_idle_timeout * 2; | |
4032 } | |
4033 } | |
4034 | |
4035 | |
4036 static void | |
4037 ngx_quic_congestion_lost(ngx_connection_t *c, ngx_quic_frame_t *f) | |
4038 { | |
4039 ngx_msec_t timer; | |
4040 ngx_quic_congestion_t *cg; | |
4041 ngx_quic_connection_t *qc; | |
4042 | |
4043 if (f->plen == 0) { | |
4044 return; | |
4045 } | |
4046 | |
4047 qc = ngx_quic_get_connection(c); | |
4048 cg = &qc->congestion; | |
4049 | |
4050 cg->in_flight -= f->plen; | |
4051 f->plen = 0; | |
4052 | |
4053 timer = f->last - cg->recovery_start; | |
4054 | |
4055 if ((ngx_msec_int_t) timer <= 0) { | |
4056 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
4057 "quic congestion lost recovery win:%uz ss:%z if:%uz", | |
4058 cg->window, cg->ssthresh, cg->in_flight); | |
4059 | |
4060 return; | |
4061 } | |
4062 | |
4063 cg->recovery_start = ngx_current_msec; | |
4064 cg->window /= 2; | |
4065 | |
4066 if (cg->window < qc->tp.max_udp_payload_size * 2) { | |
4067 cg->window = qc->tp.max_udp_payload_size * 2; | |
4068 } | |
4069 | |
4070 cg->ssthresh = cg->window; | |
4071 | |
4072 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
4073 "quic congestion lost win:%uz ss:%z if:%uz", | |
4074 cg->window, cg->ssthresh, cg->in_flight); | |
4075 } | |
4076 | |
4077 | |
4078 uint32_t | 2154 uint32_t |
4079 ngx_quic_version(ngx_connection_t *c) | 2155 ngx_quic_version(ngx_connection_t *c) |
4080 { | 2156 { |
4081 uint32_t version; | 2157 uint32_t version; |
4082 ngx_quic_connection_t *qc; | 2158 ngx_quic_connection_t *qc; |