Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_connid.c @ 8763:4117aa7fa38e quic
QUIC: connection migration.
The patch adds proper transitions between multiple networking addresses that
can be used by a single quic connection. New networking paths are validated
using PATH_CHALLENGE/PATH_RESPONSE frames.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Thu, 29 Apr 2021 15:35:02 +0300 |
parents | e0cb1e58ca13 |
children | d5f93733c17d |
comparison
equal
deleted
inserted
replaced
8762:12f18e0bca09 | 8763:4117aa7fa38e |
---|---|
7 #include <ngx_config.h> | 7 #include <ngx_config.h> |
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 #include <ngx_event.h> | 9 #include <ngx_event.h> |
10 #include <ngx_event_quic_connection.h> | 10 #include <ngx_event_quic_connection.h> |
11 | 11 |
12 | |
13 #define NGX_QUIC_MAX_SERVER_IDS 8 | 12 #define NGX_QUIC_MAX_SERVER_IDS 8 |
14 | 13 |
15 | 14 |
16 static ngx_int_t ngx_quic_create_server_id(ngx_connection_t *c, u_char *id); | |
17 #if (NGX_QUIC_BPF) | 15 #if (NGX_QUIC_BPF) |
18 static ngx_int_t ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id); | 16 static ngx_int_t ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id); |
19 #endif | 17 #endif |
20 static ngx_int_t ngx_quic_retire_connection_id(ngx_connection_t *c, | 18 static ngx_int_t ngx_quic_send_retire_connection_id(ngx_connection_t *c, |
21 enum ssl_encryption_level_t level, uint64_t seqnum); | 19 enum ssl_encryption_level_t level, uint64_t seqnum); |
22 static ngx_quic_server_id_t *ngx_quic_insert_server_id(ngx_connection_t *c, | 20 |
23 ngx_quic_connection_t *qc, ngx_str_t *id); | |
24 static ngx_quic_client_id_t *ngx_quic_alloc_client_id(ngx_connection_t *c, | 21 static ngx_quic_client_id_t *ngx_quic_alloc_client_id(ngx_connection_t *c, |
25 ngx_quic_connection_t *qc); | 22 ngx_quic_connection_t *qc); |
26 static ngx_quic_server_id_t *ngx_quic_alloc_server_id(ngx_connection_t *c, | 23 static ngx_int_t ngx_quic_replace_retired_client_id(ngx_connection_t *c, |
27 ngx_quic_connection_t *qc); | 24 ngx_quic_client_id_t *retired_cid); |
25 static ngx_int_t ngx_quic_send_server_id(ngx_connection_t *c, | |
26 ngx_quic_server_id_t *sid); | |
28 | 27 |
29 | 28 |
30 ngx_int_t | 29 ngx_int_t |
31 ngx_quic_setup_connection_ids(ngx_connection_t *c, ngx_quic_connection_t *qc, | |
32 ngx_quic_header_t *pkt) | |
33 { | |
34 ngx_quic_server_id_t *sid, *osid; | |
35 ngx_quic_client_id_t *cid; | |
36 | |
37 /* | |
38 * qc->nclient_ids = 0 | |
39 * qc->nserver_ids = 0 | |
40 * qc->max_retired_seqnum = 0 | |
41 */ | |
42 | |
43 ngx_queue_init(&qc->client_ids); | |
44 ngx_queue_init(&qc->server_ids); | |
45 ngx_queue_init(&qc->free_client_ids); | |
46 ngx_queue_init(&qc->free_server_ids); | |
47 | |
48 qc->odcid.len = pkt->odcid.len; | |
49 qc->odcid.data = ngx_pstrdup(c->pool, &pkt->odcid); | |
50 if (qc->odcid.data == NULL) { | |
51 return NGX_ERROR; | |
52 } | |
53 | |
54 qc->tp.original_dcid = qc->odcid; | |
55 | |
56 qc->scid.len = pkt->scid.len; | |
57 qc->scid.data = ngx_pstrdup(c->pool, &pkt->scid); | |
58 if (qc->scid.data == NULL) { | |
59 return NGX_ERROR; | |
60 } | |
61 | |
62 qc->dcid.len = NGX_QUIC_SERVER_CID_LEN; | |
63 qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len); | |
64 if (qc->dcid.data == NULL) { | |
65 return NGX_ERROR; | |
66 } | |
67 | |
68 if (ngx_quic_create_server_id(c, qc->dcid.data) != NGX_OK) { | |
69 return NGX_ERROR; | |
70 } | |
71 | |
72 qc->tp.initial_scid = qc->dcid; | |
73 | |
74 cid = ngx_quic_alloc_client_id(c, qc); | |
75 if (cid == NULL) { | |
76 return NGX_ERROR; | |
77 } | |
78 | |
79 cid->seqnum = 0; | |
80 cid->len = pkt->scid.len; | |
81 ngx_memcpy(cid->id, pkt->scid.data, pkt->scid.len); | |
82 | |
83 ngx_queue_insert_tail(&qc->client_ids, &cid->queue); | |
84 qc->nclient_ids++; | |
85 qc->client_seqnum = 0; | |
86 | |
87 qc->server_seqnum = NGX_QUIC_UNSET_PN; | |
88 | |
89 osid = ngx_quic_insert_server_id(c, qc, &qc->odcid); | |
90 if (osid == NULL) { | |
91 return NGX_ERROR; | |
92 } | |
93 | |
94 qc->server_seqnum = 0; | |
95 | |
96 sid = ngx_quic_insert_server_id(c, qc, &qc->dcid); | |
97 if (sid == NULL) { | |
98 ngx_rbtree_delete(&c->listening->rbtree, &osid->udp.node); | |
99 return NGX_ERROR; | |
100 } | |
101 | |
102 c->udp = &sid->udp; | |
103 | |
104 return NGX_OK; | |
105 } | |
106 | |
107 | |
108 static ngx_int_t | |
109 ngx_quic_create_server_id(ngx_connection_t *c, u_char *id) | 30 ngx_quic_create_server_id(ngx_connection_t *c, u_char *id) |
110 { | 31 { |
111 if (RAND_bytes(id, NGX_QUIC_SERVER_CID_LEN) != 1) { | 32 if (RAND_bytes(id, NGX_QUIC_SERVER_CID_LEN) != 1) { |
112 return NGX_ERROR; | 33 return NGX_ERROR; |
113 } | 34 } |
118 "quic bpf failed to generate socket key"); | 39 "quic bpf failed to generate socket key"); |
119 /* ignore error, things still may work */ | 40 /* ignore error, things still may work */ |
120 } | 41 } |
121 #endif | 42 #endif |
122 | 43 |
123 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
124 "quic create server id %*xs", | |
125 (size_t) NGX_QUIC_SERVER_CID_LEN, id); | |
126 return NGX_OK; | 44 return NGX_OK; |
127 } | 45 } |
128 | 46 |
129 | 47 |
130 #if (NGX_QUIC_BPF) | 48 #if (NGX_QUIC_BPF) |
153 } | 71 } |
154 | 72 |
155 #endif | 73 #endif |
156 | 74 |
157 | 75 |
158 | |
159 | |
160 ngx_int_t | 76 ngx_int_t |
161 ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c, | 77 ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c, |
162 ngx_quic_header_t *pkt, ngx_quic_new_conn_id_frame_t *f) | 78 ngx_quic_header_t *pkt, ngx_quic_new_conn_id_frame_t *f) |
163 { | 79 { |
80 ngx_str_t id; | |
164 ngx_queue_t *q; | 81 ngx_queue_t *q; |
165 ngx_quic_client_id_t *cid, *item; | 82 ngx_quic_client_id_t *cid, *item; |
166 ngx_quic_connection_t *qc; | 83 ngx_quic_connection_t *qc; |
167 | 84 |
168 qc = ngx_quic_get_connection(c); | 85 qc = ngx_quic_get_connection(c); |
175 * a corresponding RETIRE_CONNECTION_ID frame that retires | 92 * a corresponding RETIRE_CONNECTION_ID frame that retires |
176 * the newly received connection ID, unless it has already | 93 * the newly received connection ID, unless it has already |
177 * done so for that sequence number. | 94 * done so for that sequence number. |
178 */ | 95 */ |
179 | 96 |
180 if (ngx_quic_retire_connection_id(c, pkt->level, f->seqnum) != NGX_OK) { | 97 if (ngx_quic_send_retire_connection_id(c, pkt->level, f->seqnum) |
98 != NGX_OK) | |
99 { | |
181 return NGX_ERROR; | 100 return NGX_ERROR; |
182 } | 101 } |
183 | 102 |
184 goto retire; | 103 goto retire; |
185 } | 104 } |
218 return NGX_ERROR; | 137 return NGX_ERROR; |
219 } | 138 } |
220 | 139 |
221 } else { | 140 } else { |
222 | 141 |
223 cid = ngx_quic_alloc_client_id(c, qc); | 142 id.data = f->cid; |
224 if (cid == NULL) { | 143 id.len = f->len; |
225 return NGX_ERROR; | 144 |
226 } | 145 if (ngx_quic_create_client_id(c, &id, f->seqnum, f->srt) == NULL) { |
227 | 146 return NGX_ERROR; |
228 cid->seqnum = f->seqnum; | |
229 cid->len = f->len; | |
230 ngx_memcpy(cid->id, f->cid, f->len); | |
231 | |
232 ngx_memcpy(cid->sr_token, f->srt, NGX_QUIC_SR_TOKEN_LEN); | |
233 | |
234 ngx_queue_insert_tail(&qc->client_ids, &cid->queue); | |
235 qc->nclient_ids++; | |
236 | |
237 /* always use latest available connection id */ | |
238 if (f->seqnum > qc->client_seqnum) { | |
239 qc->scid.len = cid->len; | |
240 qc->scid.data = cid->id; | |
241 qc->client_seqnum = f->seqnum; | |
242 } | 147 } |
243 } | 148 } |
244 | 149 |
245 retire: | 150 retire: |
246 | 151 |
267 continue; | 172 continue; |
268 } | 173 } |
269 | 174 |
270 /* this connection id must be retired */ | 175 /* this connection id must be retired */ |
271 | 176 |
272 if (ngx_quic_retire_connection_id(c, pkt->level, cid->seqnum) | 177 if (ngx_quic_send_retire_connection_id(c, pkt->level, cid->seqnum) |
273 != NGX_OK) | 178 != NGX_OK) |
274 { | 179 { |
275 return NGX_ERROR; | 180 return NGX_ERROR; |
276 } | 181 } |
277 | 182 |
278 ngx_queue_remove(&cid->queue); | 183 if (cid->refcnt) { |
279 ngx_queue_insert_head(&qc->free_client_ids, &cid->queue); | 184 /* we are going to retire client id which is in use */ |
280 qc->nclient_ids--; | 185 if (ngx_quic_replace_retired_client_id(c, cid) != NGX_OK) { |
186 return NGX_ERROR; | |
187 } | |
188 } | |
189 | |
190 ngx_quic_unref_client_id(c, cid); | |
281 } | 191 } |
282 | 192 |
283 done: | 193 done: |
284 | 194 |
285 if (qc->nclient_ids > qc->tp.active_connection_id_limit) { | 195 if (qc->nclient_ids > qc->tp.active_connection_id_limit) { |
298 return NGX_OK; | 208 return NGX_OK; |
299 } | 209 } |
300 | 210 |
301 | 211 |
302 static ngx_int_t | 212 static ngx_int_t |
303 ngx_quic_retire_connection_id(ngx_connection_t *c, | 213 ngx_quic_send_retire_connection_id(ngx_connection_t *c, |
304 enum ssl_encryption_level_t level, uint64_t seqnum) | 214 enum ssl_encryption_level_t level, uint64_t seqnum) |
305 { | 215 { |
306 ngx_quic_frame_t *frame; | 216 ngx_quic_frame_t *frame; |
307 ngx_quic_connection_t *qc; | 217 ngx_quic_connection_t *qc; |
308 | 218 |
317 frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID; | 227 frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID; |
318 frame->u.retire_cid.sequence_number = seqnum; | 228 frame->u.retire_cid.sequence_number = seqnum; |
319 | 229 |
320 ngx_quic_queue_frame(qc, frame); | 230 ngx_quic_queue_frame(qc, frame); |
321 | 231 |
322 return NGX_OK; | 232 /* we are no longer going to use this client id */ |
233 | |
234 return NGX_OK; | |
235 } | |
236 | |
237 | |
238 static ngx_quic_client_id_t * | |
239 ngx_quic_alloc_client_id(ngx_connection_t *c, ngx_quic_connection_t *qc) | |
240 { | |
241 ngx_queue_t *q; | |
242 ngx_quic_client_id_t *cid; | |
243 | |
244 if (!ngx_queue_empty(&qc->free_client_ids)) { | |
245 | |
246 q = ngx_queue_head(&qc->free_client_ids); | |
247 cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); | |
248 | |
249 ngx_queue_remove(&cid->queue); | |
250 | |
251 ngx_memzero(cid, sizeof(ngx_quic_client_id_t)); | |
252 | |
253 } else { | |
254 | |
255 cid = ngx_pcalloc(c->pool, sizeof(ngx_quic_client_id_t)); | |
256 if (cid == NULL) { | |
257 return NULL; | |
258 } | |
259 } | |
260 | |
261 return cid; | |
262 } | |
263 | |
264 | |
265 ngx_quic_client_id_t * | |
266 ngx_quic_create_client_id(ngx_connection_t *c, ngx_str_t *id, | |
267 uint64_t seqnum, u_char *token) | |
268 { | |
269 ngx_quic_client_id_t *cid; | |
270 ngx_quic_connection_t *qc; | |
271 | |
272 qc = ngx_quic_get_connection(c); | |
273 | |
274 cid = ngx_quic_alloc_client_id(c, qc); | |
275 if (cid == NULL) { | |
276 return NULL; | |
277 } | |
278 | |
279 cid->seqnum = seqnum; | |
280 | |
281 cid->len = id->len; | |
282 ngx_memcpy(cid->id, id->data, id->len); | |
283 | |
284 if (token) { | |
285 ngx_memcpy(cid->sr_token, token, NGX_QUIC_SR_TOKEN_LEN); | |
286 } | |
287 | |
288 ngx_queue_insert_tail(&qc->client_ids, &cid->queue); | |
289 qc->nclient_ids++; | |
290 | |
291 if (seqnum > qc->client_seqnum) { | |
292 qc->client_seqnum = seqnum; | |
293 } | |
294 | |
295 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
296 "quic cid #%uL received id:%uz:%xV:%*xs", | |
297 cid->seqnum, id->len, id, | |
298 (size_t) NGX_QUIC_SR_TOKEN_LEN, cid->sr_token); | |
299 | |
300 return cid; | |
301 } | |
302 | |
303 | |
304 ngx_quic_client_id_t * | |
305 ngx_quic_next_client_id(ngx_connection_t *c) | |
306 { | |
307 ngx_queue_t *q; | |
308 ngx_quic_client_id_t *cid; | |
309 ngx_quic_connection_t *qc; | |
310 | |
311 qc = ngx_quic_get_connection(c); | |
312 | |
313 for (q = ngx_queue_head(&qc->client_ids); | |
314 q != ngx_queue_sentinel(&qc->client_ids); | |
315 q = ngx_queue_next(q)) | |
316 { | |
317 cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); | |
318 | |
319 if (cid->refcnt == 0) { | |
320 return cid; | |
321 } | |
322 } | |
323 | |
324 return NULL; | |
323 } | 325 } |
324 | 326 |
325 | 327 |
326 ngx_int_t | 328 ngx_int_t |
327 ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c, | 329 ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c, |
328 ngx_quic_header_t *pkt, ngx_quic_retire_cid_frame_t *f) | 330 ngx_quic_header_t *pkt, ngx_quic_retire_cid_frame_t *f) |
329 { | 331 { |
332 ngx_quic_path_t *path; | |
333 ngx_quic_socket_t *qsock, **tmp; | |
334 ngx_quic_client_id_t *cid; | |
335 ngx_quic_connection_t *qc; | |
336 | |
337 qc = ngx_quic_get_connection(c); | |
338 | |
339 qsock = ngx_quic_find_socket(c, f->sequence_number); | |
340 if (qsock == NULL) { | |
341 return NGX_OK; | |
342 } | |
343 | |
344 if (qsock->sid.seqnum == qc->socket->sid.seqnum) { | |
345 tmp = &qc->socket; | |
346 | |
347 } else if (qc->backup && qsock->sid.seqnum == qc->backup->sid.seqnum) { | |
348 tmp = &qc->backup; | |
349 | |
350 } else { | |
351 tmp = NULL; | |
352 } | |
353 | |
354 if (ngx_quic_create_sockets(c) != NGX_OK) { | |
355 return NGX_ERROR; | |
356 } | |
357 | |
358 if (tmp) { | |
359 /* replace socket in use (active or backup) */ | |
360 | |
361 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
362 "quic %s socket #%uL:%uL:%uL retired", | |
363 (*tmp) == qc->socket ? "active" : "backup", | |
364 (*tmp)->sid.seqnum, (*tmp)->cid->seqnum, | |
365 (*tmp)->path->seqnum); | |
366 | |
367 qsock = ngx_quic_get_unconnected_socket(c); | |
368 if (qsock == NULL) { | |
369 return NGX_ERROR; | |
370 } | |
371 | |
372 path = (*tmp)->path; | |
373 cid = (*tmp)->cid; | |
374 | |
375 ngx_quic_connect(c, qsock, path, cid); | |
376 | |
377 | |
378 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
379 "quic %s socket is now #%uL:%uL:%uL (%s)", | |
380 (*tmp) == qc->socket ? "active" : "backup", | |
381 qsock->sid.seqnum, qsock->cid->seqnum, | |
382 qsock->path->seqnum, | |
383 ngx_quic_path_state_str(qsock->path)); | |
384 | |
385 ngx_quic_close_socket(c, *tmp); /* no longer used */ | |
386 | |
387 *tmp = qsock; | |
388 } | |
389 | |
390 return NGX_OK; | |
391 } | |
392 | |
393 | |
394 ngx_int_t | |
395 ngx_quic_create_sockets(ngx_connection_t *c) | |
396 { | |
397 ngx_uint_t n; | |
398 ngx_quic_socket_t *qsock; | |
399 ngx_quic_connection_t *qc; | |
400 | |
401 qc = ngx_quic_get_connection(c); | |
402 | |
403 n = ngx_min(NGX_QUIC_MAX_SERVER_IDS, qc->ctp.active_connection_id_limit); | |
404 | |
405 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
406 "quic create sockets has:%ui max:%ui", qc->nsockets, n); | |
407 | |
408 while (qc->nsockets < n) { | |
409 | |
410 qsock = ngx_quic_alloc_socket(c, qc); | |
411 if (qsock == NULL) { | |
412 return NGX_ERROR; | |
413 } | |
414 | |
415 if (ngx_quic_listen(c, qc, qsock) != NGX_OK) { | |
416 return NGX_ERROR; | |
417 } | |
418 | |
419 if (ngx_quic_send_server_id(c, &qsock->sid) != NGX_OK) { | |
420 return NGX_ERROR; | |
421 } | |
422 } | |
423 | |
424 return NGX_OK; | |
425 } | |
426 | |
427 | |
428 static ngx_int_t | |
429 ngx_quic_send_server_id(ngx_connection_t *c, ngx_quic_server_id_t *sid) | |
430 { | |
431 ngx_str_t dcid; | |
432 ngx_quic_frame_t *frame; | |
433 ngx_quic_connection_t *qc; | |
434 | |
435 qc = ngx_quic_get_connection(c); | |
436 | |
437 dcid.len = sid->len; | |
438 dcid.data = sid->id; | |
439 | |
440 frame = ngx_quic_alloc_frame(c); | |
441 if (frame == NULL) { | |
442 return NGX_ERROR; | |
443 } | |
444 | |
445 frame->level = ssl_encryption_application; | |
446 frame->type = NGX_QUIC_FT_NEW_CONNECTION_ID; | |
447 frame->u.ncid.seqnum = sid->seqnum; | |
448 frame->u.ncid.retire = 0; | |
449 frame->u.ncid.len = NGX_QUIC_SERVER_CID_LEN; | |
450 ngx_memcpy(frame->u.ncid.cid, sid->id, NGX_QUIC_SERVER_CID_LEN); | |
451 | |
452 if (ngx_quic_new_sr_token(c, &dcid, qc->conf->sr_token_key, | |
453 frame->u.ncid.srt) | |
454 != NGX_OK) | |
455 { | |
456 return NGX_ERROR; | |
457 } | |
458 | |
459 ngx_quic_queue_frame(qc, frame); | |
460 | |
461 return NGX_OK; | |
462 } | |
463 | |
464 | |
465 static ngx_int_t | |
466 ngx_quic_replace_retired_client_id(ngx_connection_t *c, | |
467 ngx_quic_client_id_t *retired_cid) | |
468 { | |
330 ngx_queue_t *q; | 469 ngx_queue_t *q; |
331 ngx_quic_server_id_t *sid; | 470 ngx_quic_socket_t *qsock; |
332 ngx_quic_connection_t *qc; | 471 ngx_quic_client_id_t *cid; |
333 | 472 ngx_quic_connection_t *qc; |
334 qc = ngx_quic_get_connection(c); | 473 |
335 | 474 qc = ngx_quic_get_connection(c); |
336 for (q = ngx_queue_head(&qc->server_ids); | 475 |
337 q != ngx_queue_sentinel(&qc->server_ids); | 476 for (q = ngx_queue_head(&qc->sockets); |
477 q != ngx_queue_sentinel(&qc->sockets); | |
338 q = ngx_queue_next(q)) | 478 q = ngx_queue_next(q)) |
339 { | 479 { |
340 sid = ngx_queue_data(q, ngx_quic_server_id_t, queue); | 480 qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); |
341 | 481 |
342 if (sid->seqnum == f->sequence_number) { | 482 if (qsock->cid == retired_cid) { |
343 ngx_queue_remove(q); | 483 |
344 ngx_queue_insert_tail(&qc->free_server_ids, &sid->queue); | 484 cid = ngx_quic_next_client_id(c); |
345 ngx_rbtree_delete(&c->listening->rbtree, &sid->udp.node); | 485 if (cid == NULL) { |
346 qc->nserver_ids--; | 486 return NGX_ERROR; |
347 break; | 487 } |
348 } | 488 |
349 } | 489 qsock->cid = cid; |
350 | 490 cid->refcnt++; |
351 return ngx_quic_issue_server_ids(c); | 491 |
352 } | 492 ngx_quic_unref_client_id(c, retired_cid); |
353 | 493 |
354 | 494 if (retired_cid->refcnt == 0) { |
355 ngx_int_t | 495 return NGX_OK; |
356 ngx_quic_issue_server_ids(ngx_connection_t *c) | 496 } |
357 { | 497 } |
358 ngx_str_t dcid; | |
359 ngx_uint_t n; | |
360 ngx_quic_frame_t *frame; | |
361 ngx_quic_server_id_t *sid; | |
362 ngx_quic_connection_t *qc; | |
363 u_char id[NGX_QUIC_SERVER_CID_LEN]; | |
364 | |
365 qc = ngx_quic_get_connection(c); | |
366 | |
367 n = ngx_min(NGX_QUIC_MAX_SERVER_IDS, qc->ctp.active_connection_id_limit); | |
368 | |
369 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
370 "quic issue server ids has:%ui max:%ui", qc->nserver_ids, n); | |
371 | |
372 while (qc->nserver_ids < n) { | |
373 if (ngx_quic_create_server_id(c, id) != NGX_OK) { | |
374 return NGX_ERROR; | |
375 } | |
376 | |
377 dcid.len = NGX_QUIC_SERVER_CID_LEN; | |
378 dcid.data = id; | |
379 | |
380 sid = ngx_quic_insert_server_id(c, qc, &dcid); | |
381 if (sid == NULL) { | |
382 return NGX_ERROR; | |
383 } | |
384 | |
385 frame = ngx_quic_alloc_frame(c); | |
386 if (frame == NULL) { | |
387 return NGX_ERROR; | |
388 } | |
389 | |
390 frame->level = ssl_encryption_application; | |
391 frame->type = NGX_QUIC_FT_NEW_CONNECTION_ID; | |
392 frame->u.ncid.seqnum = sid->seqnum; | |
393 frame->u.ncid.retire = 0; | |
394 frame->u.ncid.len = NGX_QUIC_SERVER_CID_LEN; | |
395 ngx_memcpy(frame->u.ncid.cid, id, NGX_QUIC_SERVER_CID_LEN); | |
396 | |
397 if (ngx_quic_new_sr_token(c, &dcid, qc->conf->sr_token_key, | |
398 frame->u.ncid.srt) | |
399 != NGX_OK) | |
400 { | |
401 return NGX_ERROR; | |
402 } | |
403 | |
404 ngx_quic_queue_frame(qc, frame); | |
405 } | 498 } |
406 | 499 |
407 return NGX_OK; | 500 return NGX_OK; |
408 } | 501 } |
409 | 502 |
410 | 503 |
411 void | 504 void |
412 ngx_quic_clear_temp_server_ids(ngx_connection_t *c) | 505 ngx_quic_unref_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid) |
413 { | 506 { |
414 ngx_queue_t *q, *next; | 507 ngx_quic_connection_t *qc; |
415 ngx_quic_server_id_t *sid; | 508 |
416 ngx_quic_connection_t *qc; | 509 cid->refcnt--; |
417 | 510 |
418 qc = ngx_quic_get_connection(c); | 511 if (cid->refcnt) { |
419 | 512 return; |
420 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | 513 } |
421 "quic clear temp server ids"); | 514 |
422 | 515 qc = ngx_quic_get_connection(c); |
423 for (q = ngx_queue_head(&qc->server_ids); | 516 |
424 q != ngx_queue_sentinel(&qc->server_ids); | 517 ngx_queue_remove(&cid->queue); |
425 q = next) | 518 ngx_queue_insert_head(&qc->free_client_ids, &cid->queue); |
426 { | 519 |
427 next = ngx_queue_next(q); | 520 qc->nclient_ids--; |
428 sid = ngx_queue_data(q, ngx_quic_server_id_t, queue); | 521 } |
429 | |
430 if (sid->seqnum != NGX_QUIC_UNSET_PN) { | |
431 continue; | |
432 } | |
433 | |
434 ngx_queue_remove(q); | |
435 ngx_queue_insert_tail(&qc->free_server_ids, &sid->queue); | |
436 ngx_rbtree_delete(&c->listening->rbtree, &sid->udp.node); | |
437 qc->nserver_ids--; | |
438 } | |
439 } | |
440 | |
441 | |
442 static ngx_quic_server_id_t * | |
443 ngx_quic_insert_server_id(ngx_connection_t *c, ngx_quic_connection_t *qc, | |
444 ngx_str_t *id) | |
445 { | |
446 ngx_str_t dcid; | |
447 ngx_quic_server_id_t *sid; | |
448 | |
449 sid = ngx_quic_alloc_server_id(c, qc); | |
450 if (sid == NULL) { | |
451 return NULL; | |
452 } | |
453 | |
454 sid->quic = qc; | |
455 | |
456 sid->seqnum = qc->server_seqnum; | |
457 | |
458 if (qc->server_seqnum != NGX_QUIC_UNSET_PN) { | |
459 qc->server_seqnum++; | |
460 } | |
461 | |
462 sid->len = id->len; | |
463 ngx_memcpy(sid->id, id->data, id->len); | |
464 | |
465 ngx_queue_insert_tail(&qc->server_ids, &sid->queue); | |
466 qc->nserver_ids++; | |
467 | |
468 dcid.data = sid->id; | |
469 dcid.len = sid->len; | |
470 | |
471 ngx_insert_udp_connection(c, &sid->udp, &dcid); | |
472 | |
473 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
474 "quic insert server id seqnum:%uL id len:%uz %xV", | |
475 sid->seqnum, id->len, id); | |
476 | |
477 return sid; | |
478 } | |
479 | |
480 | |
481 static ngx_quic_client_id_t * | |
482 ngx_quic_alloc_client_id(ngx_connection_t *c, ngx_quic_connection_t *qc) | |
483 { | |
484 ngx_queue_t *q; | |
485 ngx_quic_client_id_t *cid; | |
486 | |
487 if (!ngx_queue_empty(&qc->free_client_ids)) { | |
488 | |
489 q = ngx_queue_head(&qc->free_client_ids); | |
490 cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); | |
491 | |
492 ngx_queue_remove(&cid->queue); | |
493 | |
494 ngx_memzero(cid, sizeof(ngx_quic_client_id_t)); | |
495 | |
496 } else { | |
497 | |
498 cid = ngx_pcalloc(c->pool, sizeof(ngx_quic_client_id_t)); | |
499 if (cid == NULL) { | |
500 return NULL; | |
501 } | |
502 } | |
503 | |
504 return cid; | |
505 } | |
506 | |
507 | |
508 static ngx_quic_server_id_t * | |
509 ngx_quic_alloc_server_id(ngx_connection_t *c, ngx_quic_connection_t *qc) | |
510 { | |
511 ngx_queue_t *q; | |
512 ngx_quic_server_id_t *sid; | |
513 | |
514 if (!ngx_queue_empty(&qc->free_server_ids)) { | |
515 | |
516 q = ngx_queue_head(&qc->free_server_ids); | |
517 sid = ngx_queue_data(q, ngx_quic_server_id_t, queue); | |
518 | |
519 ngx_queue_remove(&sid->queue); | |
520 | |
521 ngx_memzero(sid, sizeof(ngx_quic_server_id_t)); | |
522 | |
523 } else { | |
524 | |
525 sid = ngx_pcalloc(c->pool, sizeof(ngx_quic_server_id_t)); | |
526 if (sid == NULL) { | |
527 return NULL; | |
528 } | |
529 } | |
530 | |
531 return sid; | |
532 } |