Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_streams.c @ 9051:37d5dddabaea quic
QUIC: reusable mode for main connection.
The connection is automatically switched to this mode by transport layer when
there are no non-cancelable streams. Currently, cancelable streams are
HTTP/3 encoder/decoder/control streams.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Tue, 29 Nov 2022 17:46:46 +0400 |
parents | aaca8e111959 |
children | 2e51cf3ffd90 |
comparison
equal
deleted
inserted
replaced
9050:aaca8e111959 | 9051:37d5dddabaea |
---|---|
31 static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c, | 31 static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c, |
32 ngx_chain_t *in, off_t limit); | 32 ngx_chain_t *in, off_t limit); |
33 static ngx_int_t ngx_quic_stream_flush(ngx_quic_stream_t *qs); | 33 static ngx_int_t ngx_quic_stream_flush(ngx_quic_stream_t *qs); |
34 static void ngx_quic_stream_cleanup_handler(void *data); | 34 static void ngx_quic_stream_cleanup_handler(void *data); |
35 static ngx_int_t ngx_quic_close_stream(ngx_quic_stream_t *qs); | 35 static ngx_int_t ngx_quic_close_stream(ngx_quic_stream_t *qs); |
36 static ngx_int_t ngx_quic_can_shutdown(ngx_connection_t *c); | |
36 static ngx_int_t ngx_quic_control_flow(ngx_quic_stream_t *qs, uint64_t last); | 37 static ngx_int_t ngx_quic_control_flow(ngx_quic_stream_t *qs, uint64_t last); |
37 static ngx_int_t ngx_quic_update_flow(ngx_quic_stream_t *qs, uint64_t last); | 38 static ngx_int_t ngx_quic_update_flow(ngx_quic_stream_t *qs, uint64_t last); |
38 static ngx_int_t ngx_quic_update_max_stream_data(ngx_quic_stream_t *qs); | 39 static ngx_int_t ngx_quic_update_max_stream_data(ngx_quic_stream_t *qs); |
39 static ngx_int_t ngx_quic_update_max_data(ngx_connection_t *c); | 40 static ngx_int_t ngx_quic_update_max_data(ngx_connection_t *c); |
40 static void ngx_quic_set_event(ngx_event_t *ev); | 41 static void ngx_quic_set_event(ngx_event_t *ev); |
48 ngx_quic_stream_t *nqs; | 49 ngx_quic_stream_t *nqs; |
49 ngx_quic_connection_t *qc; | 50 ngx_quic_connection_t *qc; |
50 | 51 |
51 pc = c->quic ? c->quic->parent : c; | 52 pc = c->quic ? c->quic->parent : c; |
52 qc = ngx_quic_get_connection(pc); | 53 qc = ngx_quic_get_connection(pc); |
54 | |
55 if (qc->closing) { | |
56 return NULL; | |
57 } | |
53 | 58 |
54 if (bidi) { | 59 if (bidi) { |
55 if (qc->streams.server_streams_bidi | 60 if (qc->streams.server_streams_bidi |
56 >= qc->streams.server_max_streams_bidi) | 61 >= qc->streams.server_max_streams_bidi) |
57 { | 62 { |
159 ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) | 164 ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) |
160 { | 165 { |
161 ngx_pool_t *pool; | 166 ngx_pool_t *pool; |
162 ngx_queue_t *q; | 167 ngx_queue_t *q; |
163 ngx_rbtree_t *tree; | 168 ngx_rbtree_t *tree; |
169 ngx_connection_t *sc; | |
164 ngx_rbtree_node_t *node; | 170 ngx_rbtree_node_t *node; |
165 ngx_quic_stream_t *qs; | 171 ngx_quic_stream_t *qs; |
166 | |
167 #if (NGX_DEBUG) | |
168 ngx_uint_t ns; | |
169 #endif | |
170 | 172 |
171 while (!ngx_queue_empty(&qc->streams.uninitialized)) { | 173 while (!ngx_queue_empty(&qc->streams.uninitialized)) { |
172 q = ngx_queue_head(&qc->streams.uninitialized); | 174 q = ngx_queue_head(&qc->streams.uninitialized); |
173 ngx_queue_remove(q); | 175 ngx_queue_remove(q); |
174 | 176 |
183 | 185 |
184 if (tree->root == tree->sentinel) { | 186 if (tree->root == tree->sentinel) { |
185 return NGX_OK; | 187 return NGX_OK; |
186 } | 188 } |
187 | 189 |
188 #if (NGX_DEBUG) | |
189 ns = 0; | |
190 #endif | |
191 | |
192 node = ngx_rbtree_min(tree->root, tree->sentinel); | 190 node = ngx_rbtree_min(tree->root, tree->sentinel); |
193 | 191 |
194 while (node) { | 192 while (node) { |
195 qs = (ngx_quic_stream_t *) node; | 193 qs = (ngx_quic_stream_t *) node; |
196 node = ngx_rbtree_next(tree, node); | 194 node = ngx_rbtree_next(tree, node); |
195 sc = qs->connection; | |
197 | 196 |
198 qs->recv_state = NGX_QUIC_STREAM_RECV_RESET_RECVD; | 197 qs->recv_state = NGX_QUIC_STREAM_RECV_RESET_RECVD; |
199 qs->send_state = NGX_QUIC_STREAM_SEND_RESET_SENT; | 198 qs->send_state = NGX_QUIC_STREAM_SEND_RESET_SENT; |
200 | 199 |
201 if (qs->connection == NULL) { | 200 if (sc == NULL) { |
202 ngx_quic_close_stream(qs); | 201 ngx_quic_close_stream(qs); |
203 continue; | 202 continue; |
204 } | 203 } |
205 | 204 |
206 ngx_quic_set_event(qs->connection->read); | 205 ngx_quic_set_event(sc->read); |
207 ngx_quic_set_event(qs->connection->write); | 206 ngx_quic_set_event(sc->write); |
208 | 207 |
209 #if (NGX_DEBUG) | 208 sc->close = 1; |
210 ns++; | 209 sc->read->handler(sc->read); |
211 #endif | 210 } |
212 } | 211 |
213 | 212 if (tree->root == tree->sentinel) { |
214 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 213 return NGX_OK; |
215 "quic connection has %ui active streams", ns); | 214 } |
215 | |
216 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
217 "quic connection has active streams"); | |
216 | 218 |
217 return NGX_AGAIN; | 219 return NGX_AGAIN; |
218 } | 220 } |
219 | 221 |
220 | 222 |
585 static ngx_quic_stream_t * | 587 static ngx_quic_stream_t * |
586 ngx_quic_create_stream(ngx_connection_t *c, uint64_t id) | 588 ngx_quic_create_stream(ngx_connection_t *c, uint64_t id) |
587 { | 589 { |
588 ngx_log_t *log; | 590 ngx_log_t *log; |
589 ngx_pool_t *pool; | 591 ngx_pool_t *pool; |
592 ngx_uint_t reusable; | |
590 ngx_queue_t *q; | 593 ngx_queue_t *q; |
591 ngx_connection_t *sc; | 594 ngx_connection_t *sc; |
592 ngx_quic_stream_t *qs; | 595 ngx_quic_stream_t *qs; |
593 ngx_pool_cleanup_t *cln; | 596 ngx_pool_cleanup_t *cln; |
594 ngx_quic_connection_t *qc; | 597 ngx_quic_connection_t *qc; |
637 } | 640 } |
638 | 641 |
639 *log = *c->log; | 642 *log = *c->log; |
640 pool->log = log; | 643 pool->log = log; |
641 | 644 |
645 reusable = c->reusable; | |
646 ngx_reusable_connection(c, 0); | |
647 | |
642 sc = ngx_get_connection(c->fd, log); | 648 sc = ngx_get_connection(c->fd, log); |
643 if (sc == NULL) { | 649 if (sc == NULL) { |
644 ngx_destroy_pool(pool); | 650 ngx_destroy_pool(pool); |
645 ngx_queue_insert_tail(&qc->streams.free, &qs->queue); | 651 ngx_queue_insert_tail(&qc->streams.free, &qs->queue); |
652 ngx_reusable_connection(c, reusable); | |
646 return NULL; | 653 return NULL; |
647 } | 654 } |
648 | 655 |
649 qs->connection = sc; | 656 qs->connection = sc; |
650 | 657 |
710 cln = ngx_pool_cleanup_add(pool, 0); | 717 cln = ngx_pool_cleanup_add(pool, 0); |
711 if (cln == NULL) { | 718 if (cln == NULL) { |
712 ngx_close_connection(sc); | 719 ngx_close_connection(sc); |
713 ngx_destroy_pool(pool); | 720 ngx_destroy_pool(pool); |
714 ngx_queue_insert_tail(&qc->streams.free, &qs->queue); | 721 ngx_queue_insert_tail(&qc->streams.free, &qs->queue); |
722 ngx_reusable_connection(c, reusable); | |
715 return NULL; | 723 return NULL; |
716 } | 724 } |
717 | 725 |
718 cln->handler = ngx_quic_stream_cleanup_handler; | 726 cln->handler = ngx_quic_stream_cleanup_handler; |
719 cln->data = sc; | 727 cln->data = sc; |
720 | 728 |
721 ngx_rbtree_insert(&qc->streams.tree, &qs->node); | 729 ngx_rbtree_insert(&qc->streams.tree, &qs->node); |
722 | 730 |
723 return qs; | 731 return qs; |
732 } | |
733 | |
734 | |
735 void | |
736 ngx_quic_cancelable_stream(ngx_connection_t *c) | |
737 { | |
738 ngx_connection_t *pc; | |
739 ngx_quic_stream_t *qs; | |
740 ngx_quic_connection_t *qc; | |
741 | |
742 qs = c->quic; | |
743 pc = qs->parent; | |
744 qc = ngx_quic_get_connection(pc); | |
745 | |
746 if (!qs->cancelable) { | |
747 qs->cancelable = 1; | |
748 | |
749 if (ngx_quic_can_shutdown(pc) == NGX_OK) { | |
750 ngx_reusable_connection(pc, 1); | |
751 | |
752 if (qc->shutdown) { | |
753 ngx_quic_shutdown_quic(pc); | |
754 } | |
755 } | |
756 } | |
724 } | 757 } |
725 | 758 |
726 | 759 |
727 static void | 760 static void |
728 ngx_quic_empty_handler(ngx_event_t *ev) | 761 ngx_quic_empty_handler(ngx_event_t *ev) |
1054 } | 1087 } |
1055 | 1088 |
1056 ngx_quic_queue_frame(qc, frame); | 1089 ngx_quic_queue_frame(qc, frame); |
1057 } | 1090 } |
1058 | 1091 |
1092 if (!pc->reusable && ngx_quic_can_shutdown(pc) == NGX_OK) { | |
1093 ngx_reusable_connection(pc, 1); | |
1094 } | |
1095 | |
1059 if (qc->shutdown) { | 1096 if (qc->shutdown) { |
1060 ngx_post_event(&qc->close, &ngx_posted_events); | 1097 ngx_quic_shutdown_quic(pc); |
1061 } | 1098 } |
1099 | |
1100 return NGX_OK; | |
1101 } | |
1102 | |
1103 | |
1104 static ngx_int_t | |
1105 ngx_quic_can_shutdown(ngx_connection_t *c) | |
1106 { | |
1107 ngx_rbtree_t *tree; | |
1108 ngx_rbtree_node_t *node; | |
1109 ngx_quic_stream_t *qs; | |
1110 ngx_quic_connection_t *qc; | |
1111 | |
1112 qc = ngx_quic_get_connection(c); | |
1113 | |
1114 tree = &qc->streams.tree; | |
1115 | |
1116 if (tree->root != tree->sentinel) { | |
1117 for (node = ngx_rbtree_min(tree->root, tree->sentinel); | |
1118 node; | |
1119 node = ngx_rbtree_next(tree, node)) | |
1120 { | |
1121 qs = (ngx_quic_stream_t *) node; | |
1122 | |
1123 if (!qs->cancelable) { | |
1124 return NGX_DECLINED; | |
1125 } | |
1126 } | |
1127 } | |
1062 | 1128 |
1063 return NGX_OK; | 1129 return NGX_OK; |
1064 } | 1130 } |
1065 | 1131 |
1066 | 1132 |