# HG changeset patch # User Roman Arutyunyan # Date 1584621275 -10800 # Node ID 5ad7bffd38508334e83f044f45640e85fa722943 # Parent a3257a725b3d94bf79b38abe5837a7aefa512558 Send a FIN frame when QUIC stream is closed. diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c --- a/src/event/ngx_event_quic.c +++ b/src/event/ngx_event_quic.c @@ -110,6 +110,7 @@ static ssize_t ngx_quic_stream_recv(ngx_ size_t size); static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, size_t size); +static void ngx_quic_stream_cleanup_handler(void *data); static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); @@ -1286,6 +1287,7 @@ ngx_quic_create_stream(ngx_connection_t ngx_log_t *log; ngx_pool_t *pool; ngx_event_t *rev, *wev; + ngx_pool_cleanup_t *cln; ngx_quic_connection_t *qc; ngx_quic_stream_node_t *sn; @@ -1352,6 +1354,16 @@ ngx_quic_create_stream(ngx_connection_t sn->c->send = ngx_quic_stream_send; sn->c->send_chain = ngx_quic_stream_send_chain; + cln = ngx_pool_cleanup_add(pool, 0); + if (cln == NULL) { + ngx_close_connection(sn->c); + ngx_destroy_pool(pool); + return NULL; + } + + cln->handler = ngx_quic_stream_cleanup_handler; + cln->data = sn->c; + return sn; } @@ -1457,6 +1469,58 @@ ngx_quic_stream_send(ngx_connection_t *c } +static void +ngx_quic_stream_cleanup_handler(void *data) +{ + ngx_connection_t *c = data; + + ngx_connection_t *pc; + ngx_quic_frame_t *frame; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + ngx_quic_stream_node_t *sn; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic send fin"); + + qs = c->qs; + pc = qs->parent; + qc = pc->quic; + + if ((qs->id & 0x03) == 0x02) { + /* do not send fin for client unidirectional streams */ + return; + } + + // XXX: get direct pointer from stream structure? + sn = ngx_quic_find_stream(&qc->streams.tree, qs->id); + + if (sn == NULL) { + return; + } + + frame = ngx_pcalloc(pc->pool, sizeof(ngx_quic_frame_t)); + if (frame == NULL) { + return; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_STREAM7; /* OFF=1 LEN=1 FIN=1 */ + frame->u.stream.off = 1; + frame->u.stream.len = 1; + frame->u.stream.fin = 1; + + frame->u.stream.type = frame->type; + frame->u.stream.stream_id = qs->id; + frame->u.stream.offset = c->sent; + frame->u.stream.length = 0; + frame->u.stream.data = NULL; + + ngx_sprintf(frame->info, "stream %xi fin=1 level=%d", qs->id, frame->level); + + ngx_quic_queue_frame(qc, frame); +} + + static ngx_chain_t * ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)