aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/event/ngx_event_quic.c235
1 files changed, 144 insertions, 91 deletions
diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c
index 3584546b3..8650103b1 100644
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -34,6 +34,8 @@
*/
#define NGX_QUIC_MAX_BUFFERED 65535
+#define NGX_QUIC_STREAM_GONE (void *) -1
+
typedef struct {
ngx_rbtree_t tree;
@@ -270,6 +272,8 @@ static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
static ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree,
uint64_t id);
+static ngx_quic_stream_t *ngx_quic_create_client_stream(ngx_connection_t *c,
+ uint64_t id);
static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c,
uint64_t id, size_t rcvbuf_size);
static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf,
@@ -2893,10 +2897,8 @@ static ngx_int_t
ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_quic_frame_t *frame)
{
- size_t n;
- uint64_t id;
- ngx_buf_t *b;
- ngx_event_t *rev;
+ ngx_pool_t *pool;
+ ngx_connection_t *sc;
ngx_quic_stream_t *sn;
ngx_quic_connection_t *qc;
ngx_quic_stream_frame_t *f;
@@ -2915,92 +2917,34 @@ ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
sn = ngx_quic_find_stream(&qc->streams.tree, f->stream_id);
if (sn == NULL) {
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic stream id 0x%xL is new", f->stream_id);
+ sn = ngx_quic_create_client_stream(c, f->stream_id);
- if (f->stream_id & NGX_QUIC_STREAM_SERVER_INITIATED) {
- qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR;
+ if (sn == NULL) {
return NGX_ERROR;
}
- if (f->stream_id & NGX_QUIC_STREAM_UNIDIRECTIONAL) {
- if ((f->stream_id >> 2) < qc->streams.client_streams_uni) {
- return NGX_OK;
- }
-
- if ((f->stream_id >> 2) >= qc->streams.client_max_streams_uni) {
- qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR;
- return NGX_ERROR;
- }
-
- id = (qc->streams.client_streams_uni << 2)
- | NGX_QUIC_STREAM_UNIDIRECTIONAL;
- qc->streams.client_streams_uni = (f->stream_id >> 2) + 1;
- n = qc->tp.initial_max_stream_data_uni;
-
- } else {
- if ((f->stream_id >> 2) < qc->streams.client_streams_bidi) {
- return NGX_OK;
- }
-
- if ((f->stream_id >> 2) >= qc->streams.client_max_streams_bidi) {
- qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR;
- return NGX_ERROR;
- }
-
- id = (qc->streams.client_streams_bidi << 2);
- qc->streams.client_streams_bidi = (f->stream_id >> 2) + 1;
- n = qc->tp.initial_max_stream_data_bidi_remote;
- }
-
- if (n < NGX_QUIC_STREAM_BUFSIZE) {
- n = NGX_QUIC_STREAM_BUFSIZE;
- }
-
- if (n < f->length) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic no space in stream buffer");
- return NGX_ERROR;
+ if (sn == NGX_QUIC_STREAM_GONE) {
+ return NGX_OK;
}
- /*
- * 2.1. Stream Types and Identifiers
- *
- * Within each type, streams are created with numerically increasing
- * stream IDs. A stream ID that is used out of order results in all
- * streams of that type with lower-numbered stream IDs also being
- * opened.
- */
-
- for ( /* void */ ; id <= f->stream_id; id += 0x04) {
-
- sn = ngx_quic_create_stream(c, id, n);
- if (sn == NULL) {
- return NGX_ERROR;
- }
-
- if (id == f->stream_id && f->offset == 0) {
- b = sn->b;
- b->last = ngx_cpymem(b->last, f->data, f->length);
-
- sn->fs.received += f->length;
+ sc = sn->c;
+ fs = &sn->fs;
- rev = sn->c->read;
- rev->ready = 1;
+ if (ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_stream_input,
+ sn)
+ != NGX_OK)
+ {
+ pool = sc->pool;
- if (f->fin) {
- rev->pending_eof = 1;
- }
- }
+ ngx_close_connection(sc);
+ ngx_destroy_pool(pool);
- sn->c->listening->handler(sn->c);
+ return NGX_ERROR;
}
- if (f->offset == 0) {
- return NGX_OK;
- }
+ sc->listening->handler(sc);
- /* out-of-order stream: proceed to buffering */
+ return NGX_OK;
}
fs = &sn->fs;
@@ -3026,8 +2970,6 @@ ngx_quic_stream_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
f = &frame->u.stream;
id = f->stream_id;
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic existing stream");
-
b = sn->b;
if ((size_t) ((b->pos - b->start) + (b->end - b->last)) < f->length) {
@@ -3132,13 +3074,25 @@ ngx_quic_handle_stream_data_blocked_frame(ngx_connection_t *c,
sn = ngx_quic_find_stream(&qc->streams.tree, f->id);
if (sn == NULL) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic unknown stream id:0x%xL", f->id);
- return NGX_ERROR;
- }
+ sn = ngx_quic_create_client_stream(c, f->id);
- b = sn->b;
- n = sn->fs.received + (b->pos - b->start) + (b->end - b->last);
+ if (sn == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (sn == NGX_QUIC_STREAM_GONE) {
+ return NGX_OK;
+ }
+
+ b = sn->b;
+ n = b->end - b->last;
+
+ sn->c->listening->handler(sn->c);
+
+ } else {
+ b = sn->b;
+ n = sn->fs.received + (b->pos - b->start) + (b->end - b->last);
+ }
frame = ngx_quic_alloc_frame(c, 0);
if (frame == NULL) {
@@ -3182,14 +3136,23 @@ ngx_quic_handle_max_stream_data_frame(ngx_connection_t *c,
sn = ngx_quic_find_stream(&qc->streams.tree, f->id);
if (sn == NULL) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "unknown stream id:0x%xL", f->id);
+ sn = ngx_quic_create_client_stream(c, f->id);
- if (f->id & NGX_QUIC_STREAM_SERVER_INITIATED) {
- qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR;
+ if (sn == NULL) {
+ return NGX_ERROR;
}
- return NGX_ERROR;
+ if (sn == NGX_QUIC_STREAM_GONE) {
+ return NGX_OK;
+ }
+
+ if (f->limit > sn->send_max_data) {
+ sn->send_max_data = f->limit;
+ }
+
+ sn->c->listening->handler(sn->c);
+
+ return NGX_OK;
}
if (f->limit <= sn->send_max_data) {
@@ -3887,6 +3850,96 @@ ngx_quic_find_stream(ngx_rbtree_t *rbtree, uint64_t id)
static ngx_quic_stream_t *
+ngx_quic_create_client_stream(ngx_connection_t *c, uint64_t id)
+{
+ size_t n;
+ uint64_t min_id;
+ ngx_quic_stream_t *sn;
+ ngx_quic_connection_t *qc;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "quic stream id 0x%xL is new", id);
+
+ qc = c->quic;
+
+ if (id & NGX_QUIC_STREAM_UNIDIRECTIONAL) {
+
+ if (id & NGX_QUIC_STREAM_SERVER_INITIATED) {
+ if ((id >> 2) < qc->streams.server_streams_uni) {
+ return NGX_QUIC_STREAM_GONE;
+ }
+
+ qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR;
+ return NULL;
+ }
+
+ if ((id >> 2) < qc->streams.client_streams_uni) {
+ return NGX_QUIC_STREAM_GONE;
+ }
+
+ if ((id >> 2) >= qc->streams.client_max_streams_uni) {
+ qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR;
+ return NULL;
+ }
+
+ min_id = (qc->streams.client_streams_uni << 2)
+ | NGX_QUIC_STREAM_UNIDIRECTIONAL;
+ qc->streams.client_streams_uni = (id >> 2) + 1;
+ n = qc->tp.initial_max_stream_data_uni;
+
+ } else {
+
+ if (id & NGX_QUIC_STREAM_SERVER_INITIATED) {
+ if ((id >> 2) < qc->streams.server_streams_bidi) {
+ return NGX_QUIC_STREAM_GONE;
+ }
+
+ qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR;
+ return NULL;
+ }
+
+ if ((id >> 2) < qc->streams.client_streams_bidi) {
+ return NGX_QUIC_STREAM_GONE;
+ }
+
+ if ((id >> 2) >= qc->streams.client_max_streams_bidi) {
+ qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR;
+ return NULL;
+ }
+
+ min_id = (qc->streams.client_streams_bidi << 2);
+ qc->streams.client_streams_bidi = (id >> 2) + 1;
+ n = qc->tp.initial_max_stream_data_bidi_remote;
+ }
+
+ if (n < NGX_QUIC_STREAM_BUFSIZE) {
+ n = NGX_QUIC_STREAM_BUFSIZE;
+ }
+
+ /*
+ * 2.1. Stream Types and Identifiers
+ *
+ * Within each type, streams are created with numerically increasing
+ * stream IDs. A stream ID that is used out of order results in all
+ * streams of that type with lower-numbered stream IDs also being
+ * opened.
+ */
+
+ for ( /* void */ ; min_id < id; min_id += 0x04) {
+
+ sn = ngx_quic_create_stream(c, min_id, n);
+ if (sn == NULL) {
+ return NULL;
+ }
+
+ sn->c->listening->handler(sn->c);
+ }
+
+ return ngx_quic_create_stream(c, id, n);
+}
+
+
+static ngx_quic_stream_t *
ngx_quic_create_stream(ngx_connection_t *c, uint64_t id, size_t rcvbuf_size)
{
ngx_log_t *log;