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