Mercurial > hg > nginx
annotate src/event/quic/ngx_event_quic_socket.c @ 9143:48691bab4474
QUIC: fixed probe-congestion deadlock.
When probe timeout expired while congestion window was exhausted, probe PINGs
could not be sent. As a result, lost packets could not be declared lost and
congestion window could not be freed for new packets. This deadlock
continued until connection idle timeout expiration.
Now PINGs are sent separately from the frame queue without congestion control,
as specified by RFC 9002, Section 7:
An endpoint MUST NOT send a packet if it would cause bytes_in_flight
(see Appendix B.2) to be larger than the congestion window, unless the
packet is sent on a PTO timer expiration (see Section 6.2) or when entering
recovery (see Section 7.3.2).
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 14 Aug 2023 08:28:30 +0400 |
parents | adcc6d8acfd4 |
children | bba136612fe4 |
rev | line source |
---|---|
8763 | 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 ngx_int_t | |
14 ngx_quic_open_sockets(ngx_connection_t *c, ngx_quic_connection_t *qc, | |
15 ngx_quic_header_t *pkt) | |
16 { | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
17 ngx_quic_socket_t *qsock, *tmp; |
8763 | 18 ngx_quic_client_id_t *cid; |
19 | |
20 /* | |
8971
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
21 * qc->path = NULL |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
22 * |
8763 | 23 * qc->nclient_ids = 0 |
24 * qc->nsockets = 0 | |
25 * qc->max_retired_seqnum = 0 | |
26 * qc->client_seqnum = 0 | |
27 */ | |
28 | |
29 ngx_queue_init(&qc->sockets); | |
30 ngx_queue_init(&qc->free_sockets); | |
31 | |
32 ngx_queue_init(&qc->paths); | |
33 ngx_queue_init(&qc->free_paths); | |
34 | |
35 ngx_queue_init(&qc->client_ids); | |
36 ngx_queue_init(&qc->free_client_ids); | |
37 | |
38 qc->tp.original_dcid.len = pkt->odcid.len; | |
39 qc->tp.original_dcid.data = ngx_pstrdup(c->pool, &pkt->odcid); | |
40 if (qc->tp.original_dcid.data == NULL) { | |
9015
a2fbae359828
QUIC: fixed indentation.
Sergey Kandaurov <pluknet@nginx.com>
parents:
8997
diff
changeset
|
41 return NGX_ERROR; |
8763 | 42 } |
43 | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
44 /* socket to use for further processing (id auto-generated) */ |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
45 qsock = ngx_quic_create_socket(c, qc); |
8763 | 46 if (qsock == NULL) { |
47 return NGX_ERROR; | |
48 } | |
49 | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
50 /* socket is listening at new server id */ |
8763 | 51 if (ngx_quic_listen(c, qc, qsock) != NGX_OK) { |
52 return NGX_ERROR; | |
53 } | |
54 | |
8971
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
55 qsock->used = 1; |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
56 |
8763 | 57 qc->tp.initial_scid.len = qsock->sid.len; |
58 qc->tp.initial_scid.data = ngx_pnalloc(c->pool, qsock->sid.len); | |
59 if (qc->tp.initial_scid.data == NULL) { | |
60 goto failed; | |
61 } | |
62 ngx_memcpy(qc->tp.initial_scid.data, qsock->sid.id, qsock->sid.len); | |
63 | |
64 /* for all packets except first, this is set at udp layer */ | |
65 c->udp = &qsock->udp; | |
66 | |
67 /* ngx_quic_get_connection(c) macro is now usable */ | |
68 | |
69 /* we have a client identified by scid */ | |
70 cid = ngx_quic_create_client_id(c, &pkt->scid, 0, NULL); | |
71 if (cid == NULL) { | |
72 goto failed; | |
73 } | |
74 | |
8971
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
75 /* path of the first packet is our initial active path */ |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
76 qc->path = ngx_quic_new_path(c, c->sockaddr, c->socklen, cid); |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
77 if (qc->path == NULL) { |
8763 | 78 goto failed; |
79 } | |
80 | |
8971
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
81 qc->path->tag = NGX_QUIC_PATH_ACTIVE; |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
82 |
8763 | 83 if (pkt->validated) { |
8971
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
84 qc->path->validated = 1; |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
85 qc->path->limited = 0; |
8763 | 86 } |
87 | |
8971
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8955
diff
changeset
|
88 ngx_quic_path_dbg(c, "set active", qc->path); |
8763 | 89 |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
90 tmp = ngx_pcalloc(c->pool, sizeof(ngx_quic_socket_t)); |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
91 if (tmp == NULL) { |
8763 | 92 goto failed; |
93 } | |
94 | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
95 tmp->sid.seqnum = NGX_QUIC_UNSET_PN; /* temporary socket */ |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
96 |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
97 ngx_memcpy(tmp->sid.id, pkt->odcid.data, pkt->odcid.len); |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
98 tmp->sid.len = pkt->odcid.len; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
99 |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
100 if (ngx_quic_listen(c, qc, tmp) != NGX_OK) { |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
101 goto failed; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
102 } |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
103 |
8763 | 104 return NGX_OK; |
105 | |
106 failed: | |
107 | |
108 ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); | |
109 c->udp = NULL; | |
110 | |
111 return NGX_ERROR; | |
112 } | |
113 | |
114 | |
115 ngx_quic_socket_t * | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
116 ngx_quic_create_socket(ngx_connection_t *c, ngx_quic_connection_t *qc) |
8763 | 117 { |
118 ngx_queue_t *q; | |
119 ngx_quic_socket_t *sock; | |
120 | |
121 if (!ngx_queue_empty(&qc->free_sockets)) { | |
122 | |
123 q = ngx_queue_head(&qc->free_sockets); | |
124 sock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
125 | |
126 ngx_queue_remove(&sock->queue); | |
127 | |
128 ngx_memzero(sock, sizeof(ngx_quic_socket_t)); | |
129 | |
130 } else { | |
131 | |
132 sock = ngx_pcalloc(c->pool, sizeof(ngx_quic_socket_t)); | |
133 if (sock == NULL) { | |
134 return NULL; | |
135 } | |
136 } | |
137 | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
138 sock->sid.len = NGX_QUIC_SERVER_CID_LEN; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
139 if (ngx_quic_create_server_id(c, sock->sid.id) != NGX_OK) { |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
140 return NULL; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
141 } |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
142 |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
143 sock->sid.seqnum = qc->server_seqnum++; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
144 |
8763 | 145 return sock; |
146 } | |
147 | |
148 | |
149 void | |
150 ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock) | |
151 { | |
152 ngx_quic_connection_t *qc; | |
153 | |
154 qc = ngx_quic_get_connection(c); | |
155 | |
156 ngx_queue_remove(&qsock->queue); | |
157 ngx_queue_insert_head(&qc->free_sockets, &qsock->queue); | |
158 | |
159 ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); | |
160 qc->nsockets--; | |
161 | |
162 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
8997
fab36e4abf83
QUIC: got rid of hash symbol in backup and logging.
Vladimir Homutov <vl@nginx.com>
parents:
8971
diff
changeset
|
163 "quic socket seq:%L closed nsock:%ui", |
8763 | 164 (int64_t) qsock->sid.seqnum, qc->nsockets); |
165 } | |
166 | |
167 | |
168 ngx_int_t | |
169 ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc, | |
170 ngx_quic_socket_t *qsock) | |
171 { | |
172 ngx_str_t id; | |
173 ngx_quic_server_id_t *sid; | |
174 | |
175 sid = &qsock->sid; | |
176 | |
177 id.data = sid->id; | |
178 id.len = sid->len; | |
179 | |
9017
c2f5d79cde64
QUIC: separate UDP framework for QUIC.
Roman Arutyunyan <arut@nginx.com>
parents:
9015
diff
changeset
|
180 qsock->udp.connection = c; |
c2f5d79cde64
QUIC: separate UDP framework for QUIC.
Roman Arutyunyan <arut@nginx.com>
parents:
9015
diff
changeset
|
181 qsock->udp.node.key = ngx_crc32_long(id.data, id.len); |
9107
adcc6d8acfd4
Common tree insert function for QUIC and UDP connections.
Roman Arutyunyan <arut@nginx.com>
parents:
9017
diff
changeset
|
182 qsock->udp.key = id; |
9017
c2f5d79cde64
QUIC: separate UDP framework for QUIC.
Roman Arutyunyan <arut@nginx.com>
parents:
9015
diff
changeset
|
183 |
c2f5d79cde64
QUIC: separate UDP framework for QUIC.
Roman Arutyunyan <arut@nginx.com>
parents:
9015
diff
changeset
|
184 ngx_rbtree_insert(&c->listening->rbtree, &qsock->udp.node); |
8763 | 185 |
186 ngx_queue_insert_tail(&qc->sockets, &qsock->queue); | |
187 | |
188 qc->nsockets++; | |
189 qsock->quic = qc; | |
190 | |
191 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
8997
fab36e4abf83
QUIC: got rid of hash symbol in backup and logging.
Vladimir Homutov <vl@nginx.com>
parents:
8971
diff
changeset
|
192 "quic socket seq:%L listening at sid:%xV nsock:%ui", |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
193 (int64_t) sid->seqnum, &id, qc->nsockets); |
8763 | 194 |
195 return NGX_OK; | |
196 } | |
197 | |
198 | |
199 void | |
200 ngx_quic_close_sockets(ngx_connection_t *c) | |
201 { | |
202 ngx_queue_t *q; | |
203 ngx_quic_socket_t *qsock; | |
204 ngx_quic_connection_t *qc; | |
205 | |
206 qc = ngx_quic_get_connection(c); | |
207 | |
208 while (!ngx_queue_empty(&qc->sockets)) { | |
209 q = ngx_queue_head(&qc->sockets); | |
210 qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
211 | |
212 ngx_quic_close_socket(c, qsock); | |
213 } | |
214 } | |
215 | |
216 | |
217 ngx_quic_socket_t * | |
218 ngx_quic_find_socket(ngx_connection_t *c, uint64_t seqnum) | |
219 { | |
220 ngx_queue_t *q; | |
221 ngx_quic_socket_t *qsock; | |
222 ngx_quic_connection_t *qc; | |
223 | |
224 qc = ngx_quic_get_connection(c); | |
225 | |
226 for (q = ngx_queue_head(&qc->sockets); | |
227 q != ngx_queue_sentinel(&qc->sockets); | |
228 q = ngx_queue_next(q)) | |
229 { | |
230 qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
231 | |
232 if (qsock->sid.seqnum == seqnum) { | |
233 return qsock; | |
234 } | |
235 } | |
236 | |
237 return NULL; | |
238 } |