Mercurial > hg > nginx
annotate src/event/quic/ngx_event_quic_socket.c @ 8962:47f45a98f892 quic
QUIC: fixed handling STREAM FIN.
Previously, when a STREAM FIN frame with no data bytes was received after all
prior stream data were already read by the application layer, the frame was
ignored and eof was not reported to the application.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Tue, 11 Jan 2022 18:57:02 +0300 |
parents | 32daba3aabb2 |
children | 1e2f4e9c8195 |
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 { | |
17 ngx_quic_path_t *path; | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
18 ngx_quic_socket_t *qsock, *tmp; |
8763 | 19 ngx_quic_client_id_t *cid; |
20 | |
21 /* | |
22 * qc->nclient_ids = 0 | |
23 * qc->nsockets = 0 | |
24 * qc->max_retired_seqnum = 0 | |
25 * qc->client_seqnum = 0 | |
26 */ | |
27 | |
28 ngx_queue_init(&qc->sockets); | |
29 ngx_queue_init(&qc->free_sockets); | |
30 | |
31 ngx_queue_init(&qc->paths); | |
32 ngx_queue_init(&qc->free_paths); | |
33 | |
34 ngx_queue_init(&qc->client_ids); | |
35 ngx_queue_init(&qc->free_client_ids); | |
36 | |
37 qc->tp.original_dcid.len = pkt->odcid.len; | |
38 qc->tp.original_dcid.data = ngx_pstrdup(c->pool, &pkt->odcid); | |
39 if (qc->tp.original_dcid.data == NULL) { | |
40 return NGX_ERROR; | |
41 } | |
42 | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
43 /* 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
|
44 qsock = ngx_quic_create_socket(c, qc); |
8763 | 45 if (qsock == NULL) { |
46 return NGX_ERROR; | |
47 } | |
48 | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
49 /* socket is listening at new server id */ |
8763 | 50 if (ngx_quic_listen(c, qc, qsock) != NGX_OK) { |
51 return NGX_ERROR; | |
52 } | |
53 | |
54 qc->tp.initial_scid.len = qsock->sid.len; | |
55 qc->tp.initial_scid.data = ngx_pnalloc(c->pool, qsock->sid.len); | |
56 if (qc->tp.initial_scid.data == NULL) { | |
57 goto failed; | |
58 } | |
59 ngx_memcpy(qc->tp.initial_scid.data, qsock->sid.id, qsock->sid.len); | |
60 | |
61 /* for all packets except first, this is set at udp layer */ | |
62 c->udp = &qsock->udp; | |
63 | |
64 /* ngx_quic_get_connection(c) macro is now usable */ | |
65 | |
66 /* we have a client identified by scid */ | |
67 cid = ngx_quic_create_client_id(c, &pkt->scid, 0, NULL); | |
68 if (cid == NULL) { | |
69 goto failed; | |
70 } | |
71 | |
72 /* the client arrived from this path */ | |
73 path = ngx_quic_add_path(c, c->sockaddr, c->socklen); | |
74 if (path == NULL) { | |
75 goto failed; | |
76 } | |
77 | |
78 if (pkt->validated) { | |
79 path->state = NGX_QUIC_PATH_VALIDATED; | |
8940
fb41e37ddeb0
QUIC: decoupled path state and limitation status.
Vladimir Homutov <vl@nginx.com>
parents:
8939
diff
changeset
|
80 path->limited = 0; |
8763 | 81 } |
82 | |
83 /* now bind socket to client and path */ | |
84 ngx_quic_connect(c, qsock, path, cid); | |
85 | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
86 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
|
87 if (tmp == NULL) { |
8763 | 88 goto failed; |
89 } | |
90 | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
91 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
|
92 |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
93 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
|
94 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
|
95 |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
96 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
|
97 goto failed; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
98 } |
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 ngx_quic_connect(c, tmp, path, cid); |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
101 |
8763 | 102 /* use this socket as default destination */ |
103 qc->socket = qsock; | |
104 | |
105 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
106 "quic active socket is #%uL:%uL:%uL (%s)", | |
107 qsock->sid.seqnum, qsock->cid->seqnum, qsock->path->seqnum, | |
108 ngx_quic_path_state_str(qsock->path)); | |
109 | |
110 return NGX_OK; | |
111 | |
112 failed: | |
113 | |
114 ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); | |
115 c->udp = NULL; | |
116 | |
117 return NGX_ERROR; | |
118 } | |
119 | |
120 | |
121 ngx_quic_socket_t * | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
122 ngx_quic_create_socket(ngx_connection_t *c, ngx_quic_connection_t *qc) |
8763 | 123 { |
124 ngx_queue_t *q; | |
125 ngx_quic_socket_t *sock; | |
126 | |
127 if (!ngx_queue_empty(&qc->free_sockets)) { | |
128 | |
129 q = ngx_queue_head(&qc->free_sockets); | |
130 sock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
131 | |
132 ngx_queue_remove(&sock->queue); | |
133 | |
134 ngx_memzero(sock, sizeof(ngx_quic_socket_t)); | |
135 | |
136 } else { | |
137 | |
138 sock = ngx_pcalloc(c->pool, sizeof(ngx_quic_socket_t)); | |
139 if (sock == NULL) { | |
140 return NULL; | |
141 } | |
142 } | |
143 | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
144 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
|
145 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
|
146 return NULL; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
147 } |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
148 |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
149 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
|
150 |
8763 | 151 return sock; |
152 } | |
153 | |
154 | |
155 void | |
156 ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock) | |
157 { | |
158 ngx_quic_connection_t *qc; | |
159 | |
160 qc = ngx_quic_get_connection(c); | |
161 | |
162 ngx_queue_remove(&qsock->queue); | |
163 ngx_queue_insert_head(&qc->free_sockets, &qsock->queue); | |
164 | |
165 ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); | |
166 qc->nsockets--; | |
167 | |
168 if (qsock->path) { | |
169 ngx_quic_unref_path(c, qsock->path); | |
170 } | |
171 | |
172 if (qsock->cid) { | |
173 ngx_quic_unref_client_id(c, qsock->cid); | |
174 } | |
175 | |
176 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
177 "quic socket #%L closed nsock:%ui", | |
178 (int64_t) qsock->sid.seqnum, qc->nsockets); | |
179 } | |
180 | |
181 | |
8911
b09f055daa4e
QUIC: fixed handling of RETIRE_CONNECTION_ID frame.
Vladimir Homutov <vl@nginx.com>
parents:
8888
diff
changeset
|
182 void |
8763 | 183 ngx_quic_unref_path(ngx_connection_t *c, ngx_quic_path_t *path) |
184 { | |
185 ngx_quic_connection_t *qc; | |
186 | |
187 path->refcnt--; | |
188 | |
189 if (path->refcnt) { | |
190 return; | |
191 } | |
192 | |
193 qc = ngx_quic_get_connection(c); | |
194 | |
195 ngx_queue_remove(&path->queue); | |
196 ngx_queue_insert_head(&qc->free_paths, &path->queue); | |
197 | |
198 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
199 "quic path #%uL addr:%V removed", | |
200 path->seqnum, &path->addr_text); | |
201 } | |
202 | |
203 | |
204 ngx_int_t | |
205 ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc, | |
206 ngx_quic_socket_t *qsock) | |
207 { | |
208 ngx_str_t id; | |
209 ngx_quic_server_id_t *sid; | |
210 | |
211 sid = &qsock->sid; | |
212 | |
213 id.data = sid->id; | |
214 id.len = sid->len; | |
215 | |
216 ngx_insert_udp_connection(c, &qsock->udp, &id); | |
217 | |
218 ngx_queue_insert_tail(&qc->sockets, &qsock->queue); | |
219 | |
220 qc->nsockets++; | |
221 qsock->quic = qc; | |
222 | |
223 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
8955
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
224 "quic socket #%L listening at sid:%xV nsock:%ui", |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8940
diff
changeset
|
225 (int64_t) sid->seqnum, &id, qc->nsockets); |
8763 | 226 |
227 return NGX_OK; | |
228 } | |
229 | |
230 | |
231 void | |
232 ngx_quic_connect(ngx_connection_t *c, ngx_quic_socket_t *sock, | |
233 ngx_quic_path_t *path, ngx_quic_client_id_t *cid) | |
234 { | |
235 sock->path = path; | |
236 path->refcnt++; | |
237 | |
238 sock->cid = cid; | |
239 cid->refcnt++; | |
240 | |
241 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
242 "quic socket #%L connected to cid #%uL path:%uL", | |
243 (int64_t) sock->sid.seqnum, | |
244 sock->cid->seqnum, path->seqnum); | |
245 } | |
246 | |
247 | |
248 void | |
249 ngx_quic_close_sockets(ngx_connection_t *c) | |
250 { | |
251 ngx_queue_t *q; | |
252 ngx_quic_socket_t *qsock; | |
253 ngx_quic_connection_t *qc; | |
254 | |
255 qc = ngx_quic_get_connection(c); | |
256 | |
257 while (!ngx_queue_empty(&qc->sockets)) { | |
258 q = ngx_queue_head(&qc->sockets); | |
259 qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
260 | |
261 ngx_quic_close_socket(c, qsock); | |
262 } | |
263 } | |
264 | |
265 | |
266 ngx_quic_socket_t * | |
267 ngx_quic_find_socket(ngx_connection_t *c, uint64_t seqnum) | |
268 { | |
269 ngx_queue_t *q; | |
270 ngx_quic_socket_t *qsock; | |
271 ngx_quic_connection_t *qc; | |
272 | |
273 qc = ngx_quic_get_connection(c); | |
274 | |
275 for (q = ngx_queue_head(&qc->sockets); | |
276 q != ngx_queue_sentinel(&qc->sockets); | |
277 q = ngx_queue_next(q)) | |
278 { | |
279 qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
280 | |
281 if (qsock->sid.seqnum == seqnum) { | |
282 return qsock; | |
283 } | |
284 } | |
285 | |
286 return NULL; | |
287 } | |
288 | |
289 | |
290 ngx_quic_socket_t * | |
291 ngx_quic_get_unconnected_socket(ngx_connection_t *c) | |
292 { | |
293 ngx_queue_t *q; | |
294 ngx_quic_socket_t *sock; | |
295 ngx_quic_connection_t *qc; | |
296 | |
297 qc = ngx_quic_get_connection(c); | |
298 | |
299 for (q = ngx_queue_head(&qc->sockets); | |
300 q != ngx_queue_sentinel(&qc->sockets); | |
301 q = ngx_queue_next(q)) | |
302 { | |
303 sock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
304 | |
305 if (sock->cid == NULL) { | |
306 return sock; | |
307 } | |
308 } | |
309 | |
310 return NULL; | |
8888 | 311 } |