# HG changeset patch # User Roman Arutyunyan # Date 1593696839 -10800 # Node ID e0f92f68e0188d5ec3c939e1a0688136d8ce118a # Parent a7f64438aa3c7a7dddf546e602ff87621bd7e458 QUIC: Introduced ngx_quic_finalize_connection(). The function finalizes QUIC connection with an application protocol error code and sends a CONNECTION_CLOSE frame with type=0x1d. Also, renamed NGX_QUIC_FT_CONNECTION_CLOSE2 to NGX_QUIC_FT_CONNECTION_CLOSE_APP. 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,9 +110,11 @@ struct ngx_quic_connection_s { uint64_t max_streams; ngx_uint_t error; + enum ssl_encryption_level_t error_level; ngx_uint_t error_ftype; const char *error_reason; + unsigned error_app:1; unsigned send_timer_set:1; unsigned closing:1; unsigned draining:1; @@ -181,9 +183,7 @@ static ngx_int_t ngx_quic_app_input(ngx_ static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt); static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt); -static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c, - enum ssl_encryption_level_t level, ngx_uint_t err, ngx_uint_t frame_type, - const char *reason); +static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c); static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c); static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c, @@ -540,7 +540,8 @@ static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, uint8_t alert) { - ngx_connection_t *c; + ngx_connection_t *c; + ngx_quic_connection_t *qc; c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); @@ -548,13 +549,18 @@ ngx_quic_send_alert(ngx_ssl_conn_t *ssl_ "quic ngx_quic_send_alert(), lvl=%d, alert=%d", (int) level, (int) alert); - if (c->quic == NULL) { + qc = c->quic; + if (qc == NULL) { return 1; } - if (ngx_quic_send_cc(c, level, NGX_QUIC_ERR_CRYPTO(alert), 0, "TLS alert") - != NGX_OK) - { + qc->error_level = level; + qc->error = NGX_QUIC_ERR_CRYPTO(alert); + qc->error_reason = "TLS alert"; + qc->error_app = 0; + qc->error_ftype = 0; + + if (ngx_quic_send_cc(c) != NGX_OK) { return 0; } @@ -1262,10 +1268,9 @@ ngx_quic_close_connection(ngx_connection static ngx_int_t ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc) { - ngx_uint_t i, err; - ngx_quic_send_ctx_t *ctx; - ngx_quic_connection_t *qc; - enum ssl_encryption_level_t level; + ngx_uint_t i; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; qc = c->quic; @@ -1311,27 +1316,28 @@ ngx_quic_close_quic(ngx_connection_t *c, ngx_add_timer(&qc->close, 3 * NGX_QUIC_HARDCODED_PTO); - err = NGX_QUIC_ERR_NO_ERROR; + qc->error = NGX_QUIC_ERR_NO_ERROR; } else { - err = qc->error ? qc->error : NGX_QUIC_ERR_INTERNAL_ERROR; - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic immediate close due to error: %ui %s", - qc->error, + if (qc->error == 0 && !qc->error_app) { + qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic immediate close due to %serror: %ui %s", + qc->error_app ? "app " : "", qc->error, qc->error_reason ? qc->error_reason : ""); } - level = c->ssl ? SSL_quic_read_level(c->ssl->connection) - : ssl_encryption_initial; - - (void) ngx_quic_send_cc(c, level, err, qc->error_ftype, - qc->error_reason); - - if (level == ssl_encryption_handshake) { + qc->error_level = c->ssl ? SSL_quic_read_level(c->ssl->connection) + : ssl_encryption_initial; + + (void) ngx_quic_send_cc(c); + + if (qc->error_level == ssl_encryption_handshake) { /* for clients that might not have handshake keys */ - (void) ngx_quic_send_cc(c, ssl_encryption_initial, err, - qc->error_ftype, qc->error_reason); + qc->error_level = ssl_encryption_initial; + (void) ngx_quic_send_cc(c); } } @@ -1382,6 +1388,22 @@ ngx_quic_close_quic(ngx_connection_t *c, } +void +ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err, + const char *reason) +{ + ngx_quic_connection_t *qc; + + qc = c->quic; + qc->error = err; + qc->error_reason = reason; + qc->error_app = 1; + qc->error_ftype = 0; + + ngx_quic_close_connection(c, NGX_ERROR); +} + + static void ngx_quic_close_timer_handler(ngx_event_t *ev) { @@ -1887,8 +1909,14 @@ ngx_quic_payload_handler(ngx_connection_ * a packet containing a CONNECTION_CLOSE frame and to identify * packets as belonging to the connection. */ - return ngx_quic_send_cc(c, pkt->level, NGX_QUIC_ERR_NO_ERROR, 0, - "connection is closing, packet discarded"); + + qc->error_level = pkt->level; + qc->error = NGX_QUIC_ERR_NO_ERROR; + qc->error_reason = "connection is closing, packet discarded"; + qc->error_ftype = 0; + qc->error_app = 0; + + return ngx_quic_send_cc(c); } p = pkt->payload.data; @@ -1926,7 +1954,7 @@ ngx_quic_payload_handler(ngx_connection_ continue; case NGX_QUIC_FT_CONNECTION_CLOSE: - case NGX_QUIC_FT_CONNECTION_CLOSE2: + case NGX_QUIC_FT_CONNECTION_CLOSE_APP: do_close = 1; continue; } @@ -2098,8 +2126,7 @@ ngx_quic_send_ack(ngx_connection_t *c, n static ngx_int_t -ngx_quic_send_cc(ngx_connection_t *c, enum ssl_encryption_level_t level, - ngx_uint_t err, ngx_uint_t frame_type, const char *reason) +ngx_quic_send_cc(ngx_connection_t *c) { ngx_quic_frame_t *frame; ngx_quic_connection_t *qc; @@ -2122,19 +2149,21 @@ ngx_quic_send_cc(ngx_connection_t *c, en return NGX_ERROR; } - frame->level = level; + frame->level = qc->error_level; frame->type = NGX_QUIC_FT_CONNECTION_CLOSE; - frame->u.close.error_code = err; - frame->u.close.frame_type = frame_type; - - if (reason) { - frame->u.close.reason.len = ngx_strlen(reason); - frame->u.close.reason.data = (u_char *) reason; + frame->u.close.error_code = qc->error; + frame->u.close.frame_type = qc->error_ftype; + frame->u.close.app = qc->error_app; + + if (qc->error_reason) { + frame->u.close.reason.len = ngx_strlen(qc->error_reason); + frame->u.close.reason.data = (u_char *) qc->error_reason; } ngx_snprintf(frame->info, sizeof(frame->info) - 1, - "cc from send_cc err=%ui level=%d ft=%ui reason \"%s\"", - err, level, frame_type, reason ? reason : "-"); + "CONNECTION_CLOSE%s err:%ui level:%d ft:%ui reason:\"%s\"", + qc->error_app ? "_APP" : "", qc->error, qc->error_level, + qc->error_ftype, qc->error_reason ? qc->error_reason : "-"); ngx_quic_queue_frame(c->quic, frame); diff --git a/src/event/ngx_event_quic.h b/src/event/ngx_event_quic.h --- a/src/event/ngx_event_quic.h +++ b/src/event/ngx_event_quic.h @@ -103,6 +103,8 @@ struct ngx_quic_stream_s { void ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp, ngx_connection_handler_pt handler); ngx_connection_t *ngx_quic_create_uni_stream(ngx_connection_t *c); +void ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err, + const char *reason); /********************************* DEBUG *************************************/ diff --git a/src/event/ngx_event_quic_transport.c b/src/event/ngx_event_quic_transport.c --- a/src/event/ngx_event_quic_transport.c +++ b/src/event/ngx_event_quic_transport.c @@ -726,10 +726,8 @@ ngx_quic_parse_frame(ngx_quic_header_t * f->u.ncid.seqnum, f->u.ncid.retire, f->u.ncid.len); break; - case NGX_QUIC_FT_CONNECTION_CLOSE2: - /* fall through */ - case NGX_QUIC_FT_CONNECTION_CLOSE: + case NGX_QUIC_FT_CONNECTION_CLOSE_APP: p = ngx_quic_parse_int(p, end, &f->u.close.error_code); if (p == NULL) { @@ -767,7 +765,7 @@ ngx_quic_parse_frame(ngx_quic_header_t * } else { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, - "quic frame in: CONNECTION_CLOSE2:" + "quic frame in: CONNECTION_CLOSE_APP:" " code:0x%xi reason:'%V'", f->u.close.error_code, &f->u.close.reason); } @@ -1174,6 +1172,7 @@ ngx_quic_create_frame(u_char *p, ngx_qui return ngx_quic_create_stream(p, &f->u.stream); case NGX_QUIC_FT_CONNECTION_CLOSE: + case NGX_QUIC_FT_CONNECTION_CLOSE_APP: f->need_ack = 0; return ngx_quic_create_close(p, &f->u.close); @@ -1742,13 +1741,21 @@ ngx_quic_create_transport_params(u_char static size_t ngx_quic_create_close(u_char *p, ngx_quic_close_frame_t *cl) { - size_t len; - u_char *start; + size_t len; + u_char *start; + ngx_uint_t type; + + type = cl->app ? NGX_QUIC_FT_CONNECTION_CLOSE_APP + : NGX_QUIC_FT_CONNECTION_CLOSE; if (p == NULL) { - len = ngx_quic_varint_len(NGX_QUIC_FT_CONNECTION_CLOSE); + len = ngx_quic_varint_len(type); len += ngx_quic_varint_len(cl->error_code); - len += ngx_quic_varint_len(cl->frame_type); + + if (!cl->app) { + len += ngx_quic_varint_len(cl->frame_type); + } + len += ngx_quic_varint_len(cl->reason.len); len += cl->reason.len; @@ -1757,9 +1764,13 @@ ngx_quic_create_close(u_char *p, ngx_qui start = p; - ngx_quic_build_int(&p, NGX_QUIC_FT_CONNECTION_CLOSE); + ngx_quic_build_int(&p, type); ngx_quic_build_int(&p, cl->error_code); - ngx_quic_build_int(&p, cl->frame_type); + + if (!cl->app) { + ngx_quic_build_int(&p, cl->frame_type); + } + ngx_quic_build_int(&p, cl->reason.len); p = ngx_cpymem(p, cl->reason.data, cl->reason.len); diff --git a/src/event/ngx_event_quic_transport.h b/src/event/ngx_event_quic_transport.h --- a/src/event/ngx_event_quic_transport.h +++ b/src/event/ngx_event_quic_transport.h @@ -71,7 +71,7 @@ #define NGX_QUIC_FT_PATH_CHALLENGE 0x1A #define NGX_QUIC_FT_PATH_RESPONSE 0x1B #define NGX_QUIC_FT_CONNECTION_CLOSE 0x1C -#define NGX_QUIC_FT_CONNECTION_CLOSE2 0x1D +#define NGX_QUIC_FT_CONNECTION_CLOSE_APP 0x1D #define NGX_QUIC_FT_HANDSHAKE_DONE 0x1E /* 22.4. QUIC Transport Error Codes Registry */ @@ -185,6 +185,7 @@ typedef struct { uint64_t error_code; uint64_t frame_type; ngx_str_t reason; + ngx_uint_t app; /* unsigned app:1; */ } ngx_quic_close_frame_t;