]> git.kaiwu.me - nginx.git/commitdiff
Added sending of extra CONNECTION_CLOSE frames.
authorVladimir Homutov <vl@nginx.com>
Fri, 22 May 2020 15:14:35 +0000 (18:14 +0300)
committerVladimir Homutov <vl@nginx.com>
Fri, 22 May 2020 15:14:35 +0000 (18:14 +0300)
According to quic-transport draft 28 section 10.3.1:

   When sending CONNECTION_CLOSE, the goal is to ensure that the peer
   will process the frame.  Generally, this means sending the frame in a
   packet with the highest level of packet protection to avoid the
   packet being discarded.  After the handshake is confirmed (see
   Section 4.1.2 of [QUIC-TLS]), an endpoint MUST send any
   CONNECTION_CLOSE frames in a 1-RTT packet.  However, prior to
   confirming the handshake, it is possible that more advanced packet
   protection keys are not available to the peer, so another
   CONNECTION_CLOSE frame MAY be sent in a packet that uses a lower
   packet protection level.

src/event/ngx_event_quic.c

index 32c9faff32c1f097c43318aa04c7b70b70ec260a..e2ccf5e43b22c833b068e7e755447a14be4de426 100644 (file)
@@ -1189,24 +1189,32 @@ ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc)
             ngx_quic_free_frames(c, &ctx->sent);
         }
 
-        level = (qc->state == ssl_encryption_early_data)
-                ? ssl_encryption_application
-                : qc->state;
+        if (rc == NGX_DONE) {
 
-        if (rc == NGX_OK) {
+            /*
+             *  10.2.  Idle Timeout
+             *
+             *  If the idle timeout is enabled by either peer, a connection is
+             *  silently closed and its state is discarded when it remains idle
+             */
+
+            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                           "quic closing %s connection",
+                           qc->draining ? "drained" : "idle");
+
+        } else {
 
             /*
              * 10.3.  Immediate Close
              *
-             *  An endpoint sends a CONNECTION_CLOSE frame (Section 19.19) to
-             *  terminate the connection immediately.
+             *  An endpoint sends a CONNECTION_CLOSE frame (Section 19.19)
+             *  to terminate the connection immediately.
              */
-             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                            "quic immediate close, drain = %d", qc->draining);
 
-            if (ngx_quic_send_cc(c, level, NGX_QUIC_ERR_NO_ERROR, 0, NULL)
-                == NGX_OK)
-            {
+            if (rc == NGX_OK) {
+                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                                "quic immediate close, drain = %d",
+                                qc->draining);
 
                 qc->close.log = c->log;
                 qc->close.data = c;
@@ -1214,29 +1222,30 @@ ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc)
                 qc->close.cancelable = 1;
 
                 ngx_add_timer(&qc->close, 3 * NGX_QUIC_HARDCODED_PTO);
-            }
 
-        } else if (rc == NGX_DONE) {
+                err = NGX_QUIC_ERR_NO_ERROR;
 
-            /*
-             *  10.2.  Idle Timeout
-             *
-             *  If the idle timeout is enabled by either peer, a connection is
-             *  silently closed and its state is discarded when it remains idle
-             */
+            } else {
+                err = qc->error ? qc->error : NGX_QUIC_ERR_INTERNAL_ERROR;
 
-            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                           "quic closing %s connection",
-                           qc->draining ? "drained" : "idle");
+                ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                               "quic immediate close due to error: %ui %s",
+                               qc->error,
+                               qc->error_reason ? qc->error_reason : "");
+            }
 
-        } else {
-            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                           "quic immediate close due to fatal error: %ui",
-                           qc->error);
+            level = (qc->state == ssl_encryption_early_data)
+                    ? ssl_encryption_handshake
+                    : qc->state;
 
-            err = qc->error ? qc->error : NGX_QUIC_ERR_INTERNAL_ERROR;
             (void) ngx_quic_send_cc(c, level, err, qc->error_ftype,
                                     qc->error_reason);
+
+            if (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->closing = 1;