Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic.c @ 8724:fc64ab301bad quic
QUIC: connection shutdown.
The function ngx_quic_shutdown_connection() waits until all non-cancelable
streams are closed, and then closes the connection. In HTTP/3 cancelable
streams are all unidirectional streams except push streams.
The function is called from HTTP/3 when client reaches keepalive_requests.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 15 Mar 2021 16:39:33 +0300 |
parents | 0a0b1de9ccab |
children | 90ae21799f67 |
comparison
equal
deleted
inserted
replaced
8723:265062a99043 | 8724:fc64ab301bad |
---|---|
172 ngx_uint_t error; | 172 ngx_uint_t error; |
173 enum ssl_encryption_level_t error_level; | 173 enum ssl_encryption_level_t error_level; |
174 ngx_uint_t error_ftype; | 174 ngx_uint_t error_ftype; |
175 const char *error_reason; | 175 const char *error_reason; |
176 | 176 |
177 ngx_uint_t shutdown_code; | |
178 const char *shutdown_reason; | |
179 | |
177 unsigned error_app:1; | 180 unsigned error_app:1; |
178 unsigned send_timer_set:1; | 181 unsigned send_timer_set:1; |
179 unsigned closing:1; | 182 unsigned closing:1; |
183 unsigned shutdown:1; | |
180 unsigned draining:1; | 184 unsigned draining:1; |
181 unsigned key_phase:1; | 185 unsigned key_phase:1; |
182 unsigned validated:1; | 186 unsigned validated:1; |
183 } ngx_quic_connection_t; | 187 } ngx_quic_connection_t; |
184 | 188 |
382 size_t size); | 386 size_t size); |
383 static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c, | 387 static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c, |
384 ngx_chain_t *in, off_t limit); | 388 ngx_chain_t *in, off_t limit); |
385 static size_t ngx_quic_max_stream_flow(ngx_connection_t *c); | 389 static size_t ngx_quic_max_stream_flow(ngx_connection_t *c); |
386 static void ngx_quic_stream_cleanup_handler(void *data); | 390 static void ngx_quic_stream_cleanup_handler(void *data); |
391 static void ngx_quic_shutdown_quic(ngx_connection_t *c); | |
387 static ngx_quic_frame_t *ngx_quic_alloc_frame(ngx_connection_t *c); | 392 static ngx_quic_frame_t *ngx_quic_alloc_frame(ngx_connection_t *c); |
388 static void ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame); | 393 static void ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame); |
389 | 394 |
390 static void ngx_quic_congestion_ack(ngx_connection_t *c, | 395 static void ngx_quic_congestion_ack(ngx_connection_t *c, |
391 ngx_quic_frame_t *frame); | 396 ngx_quic_frame_t *frame); |
682 if (qc->error_reason) { | 687 if (qc->error_reason) { |
683 p = ngx_slprintf(p, last, " \"%s\"", qc->error_reason); | 688 p = ngx_slprintf(p, last, " \"%s\"", qc->error_reason); |
684 } | 689 } |
685 } | 690 } |
686 | 691 |
692 p = ngx_slprintf(p, last, "%s", qc->shutdown ? " shutdown" : ""); | |
687 p = ngx_slprintf(p, last, "%s", qc->closing ? " closing" : ""); | 693 p = ngx_slprintf(p, last, "%s", qc->closing ? " closing" : ""); |
688 p = ngx_slprintf(p, last, "%s", qc->draining ? " draining" : ""); | 694 p = ngx_slprintf(p, last, "%s", qc->draining ? " draining" : ""); |
689 p = ngx_slprintf(p, last, "%s", qc->key_phase ? " kp" : ""); | 695 p = ngx_slprintf(p, last, "%s", qc->key_phase ? " kp" : ""); |
690 p = ngx_slprintf(p, last, "%s", qc->validated? " valid" : ""); | 696 p = ngx_slprintf(p, last, "%s", qc->validated? " valid" : ""); |
691 | 697 |
2133 qc->error_reason = reason; | 2139 qc->error_reason = reason; |
2134 qc->error_app = 1; | 2140 qc->error_app = 1; |
2135 qc->error_ftype = 0; | 2141 qc->error_ftype = 0; |
2136 | 2142 |
2137 ngx_quic_close_connection(c, NGX_ERROR); | 2143 ngx_quic_close_connection(c, NGX_ERROR); |
2144 } | |
2145 | |
2146 | |
2147 void | |
2148 ngx_quic_shutdown_connection(ngx_connection_t *c, ngx_uint_t err, | |
2149 const char *reason) | |
2150 { | |
2151 ngx_quic_connection_t *qc; | |
2152 | |
2153 qc = ngx_quic_get_connection(c); | |
2154 qc->shutdown = 1; | |
2155 qc->shutdown_code = err; | |
2156 qc->shutdown_reason = reason; | |
2157 | |
2158 ngx_quic_shutdown_quic(c); | |
2138 } | 2159 } |
2139 | 2160 |
2140 | 2161 |
2141 static void | 2162 static void |
2142 ngx_quic_close_timer_handler(ngx_event_t *ev) | 2163 ngx_quic_close_timer_handler(ngx_event_t *ev) |
5943 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 5964 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
5944 "quic stream id:0x%xL is new", id); | 5965 "quic stream id:0x%xL is new", id); |
5945 | 5966 |
5946 qc = ngx_quic_get_connection(c); | 5967 qc = ngx_quic_get_connection(c); |
5947 | 5968 |
5969 if (qc->shutdown) { | |
5970 return NGX_QUIC_STREAM_GONE; | |
5971 } | |
5972 | |
5948 if (id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { | 5973 if (id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { |
5949 | 5974 |
5950 if (id & NGX_QUIC_STREAM_SERVER_INITIATED) { | 5975 if (id & NGX_QUIC_STREAM_SERVER_INITIATED) { |
5951 if ((id >> 2) < qc->streams.server_streams_uni) { | 5976 if ((id >> 2) < qc->streams.server_streams_uni) { |
5952 return NGX_QUIC_STREAM_GONE; | 5977 return NGX_QUIC_STREAM_GONE; |
6014 if (sn == NULL) { | 6039 if (sn == NULL) { |
6015 return NULL; | 6040 return NULL; |
6016 } | 6041 } |
6017 | 6042 |
6018 sn->c->listening->handler(sn->c); | 6043 sn->c->listening->handler(sn->c); |
6044 | |
6045 if (qc->shutdown) { | |
6046 return NGX_QUIC_STREAM_GONE; | |
6047 } | |
6019 } | 6048 } |
6020 | 6049 |
6021 return ngx_quic_create_stream(c, id, n); | 6050 return ngx_quic_create_stream(c, id, n); |
6022 } | 6051 } |
6023 | 6052 |
6408 || (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) | 6437 || (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) |
6409 { | 6438 { |
6410 if (!c->read->pending_eof && !c->read->error) { | 6439 if (!c->read->pending_eof && !c->read->error) { |
6411 frame = ngx_quic_alloc_frame(pc); | 6440 frame = ngx_quic_alloc_frame(pc); |
6412 if (frame == NULL) { | 6441 if (frame == NULL) { |
6413 return; | 6442 goto done; |
6414 } | 6443 } |
6415 | 6444 |
6416 frame->level = ssl_encryption_application; | 6445 frame->level = ssl_encryption_application; |
6417 frame->type = NGX_QUIC_FT_STOP_SENDING; | 6446 frame->type = NGX_QUIC_FT_STOP_SENDING; |
6418 frame->u.stop_sending.id = qs->id; | 6447 frame->u.stop_sending.id = qs->id; |
6423 } | 6452 } |
6424 | 6453 |
6425 if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) { | 6454 if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) { |
6426 frame = ngx_quic_alloc_frame(pc); | 6455 frame = ngx_quic_alloc_frame(pc); |
6427 if (frame == NULL) { | 6456 if (frame == NULL) { |
6428 return; | 6457 goto done; |
6429 } | 6458 } |
6430 | 6459 |
6431 frame->level = ssl_encryption_application; | 6460 frame->level = ssl_encryption_application; |
6432 frame->type = NGX_QUIC_FT_MAX_STREAMS; | 6461 frame->type = NGX_QUIC_FT_MAX_STREAMS; |
6433 | 6462 |
6442 | 6471 |
6443 ngx_quic_queue_frame(qc, frame); | 6472 ngx_quic_queue_frame(qc, frame); |
6444 | 6473 |
6445 if (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { | 6474 if (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { |
6446 /* do not send fin for client unidirectional streams */ | 6475 /* do not send fin for client unidirectional streams */ |
6447 return; | 6476 goto done; |
6448 } | 6477 } |
6449 } | 6478 } |
6450 | 6479 |
6451 if (c->write->error) { | 6480 if (c->write->error) { |
6452 goto error; | 6481 goto done; |
6453 } | 6482 } |
6454 | 6483 |
6455 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 6484 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
6456 "quic stream id:0x%xL send fin", qs->id); | 6485 "quic stream id:0x%xL send fin", qs->id); |
6457 | 6486 |
6458 frame = ngx_quic_alloc_frame(pc); | 6487 frame = ngx_quic_alloc_frame(pc); |
6459 if (frame == NULL) { | 6488 if (frame == NULL) { |
6460 return; | 6489 goto done; |
6461 } | 6490 } |
6462 | 6491 |
6463 frame->level = ssl_encryption_application; | 6492 frame->level = ssl_encryption_application; |
6464 frame->type = NGX_QUIC_FT_STREAM7; /* OFF=1 LEN=1 FIN=1 */ | 6493 frame->type = NGX_QUIC_FT_STREAM7; /* OFF=1 LEN=1 FIN=1 */ |
6465 frame->u.stream.off = 1; | 6494 frame->u.stream.off = 1; |
6471 frame->u.stream.offset = c->sent; | 6500 frame->u.stream.offset = c->sent; |
6472 frame->u.stream.length = 0; | 6501 frame->u.stream.length = 0; |
6473 | 6502 |
6474 ngx_quic_queue_frame(qc, frame); | 6503 ngx_quic_queue_frame(qc, frame); |
6475 | 6504 |
6476 error: | 6505 done: |
6477 | 6506 |
6478 (void) ngx_quic_output(pc); | 6507 (void) ngx_quic_output(pc); |
6508 | |
6509 if (qc->shutdown) { | |
6510 ngx_quic_shutdown_quic(pc); | |
6511 } | |
6512 } | |
6513 | |
6514 | |
6515 static void | |
6516 ngx_quic_shutdown_quic(ngx_connection_t *c) | |
6517 { | |
6518 ngx_rbtree_t *tree; | |
6519 ngx_rbtree_node_t *node; | |
6520 ngx_quic_stream_t *qs; | |
6521 ngx_quic_connection_t *qc; | |
6522 | |
6523 qc = ngx_quic_get_connection(c); | |
6524 | |
6525 if (qc->closing) { | |
6526 return; | |
6527 } | |
6528 | |
6529 tree = &qc->streams.tree; | |
6530 | |
6531 if (tree->root != tree->sentinel) { | |
6532 for (node = ngx_rbtree_min(tree->root, tree->sentinel); | |
6533 node; | |
6534 node = ngx_rbtree_next(tree, node)) | |
6535 { | |
6536 qs = (ngx_quic_stream_t *) node; | |
6537 | |
6538 if (!qs->cancelable) { | |
6539 return; | |
6540 } | |
6541 } | |
6542 } | |
6543 | |
6544 ngx_quic_finalize_connection(c, qc->shutdown_code, qc->shutdown_reason); | |
6479 } | 6545 } |
6480 | 6546 |
6481 | 6547 |
6482 static ngx_quic_frame_t * | 6548 static ngx_quic_frame_t * |
6483 ngx_quic_alloc_frame(ngx_connection_t *c) | 6549 ngx_quic_alloc_frame(ngx_connection_t *c) |