]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-quic: support app graceful shutdown
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 13 Jul 2022 13:15:58 +0000 (15:15 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 15 Jul 2022 13:06:59 +0000 (15:06 +0200)
Adjust qcc_emit_cc_app() to allow the delay of emission of a
CONNECTION_CLOSE. This will only set the error code but the quic-conn
layer is not flagged for immediate close. The quic-conn will be
responsible to shut the connection when deemed suitable.

This change will allow to implement application graceful shutdown, such
as HTTP/3 with GOAWAY emission. This will allow to emit closing frames
on MUX release. Once all work is done at the lower layer, the quic-conn
should emit a CONNECTION_CLOSE with the registered error code.

include/haproxy/mux_quic.h
src/h3.c
src/mux_quic.c

index dbb6fe6faa36116a45bef1531f618f1d3446daa9..0ad94cf32f577ce2aabc288173e0b1f59a1d08b7 100644 (file)
@@ -21,7 +21,7 @@ int qcs_subscribe(struct qcs *qcs, int event_type, struct wait_event *es);
 void qcs_notify_recv(struct qcs *qcs);
 void qcs_notify_send(struct qcs *qcs);
 
-void qcc_emit_cc_app(struct qcc *qcc, int err);
+void qcc_emit_cc_app(struct qcc *qcc, int err, int immediate);
 void qcc_reset_stream(struct qcs *qcs, int err);
 int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
              char fin, char *data);
index 074016699df0240f41a22adad4ee9f4569a4d3ca..7fb5f9489c11347cbb36e885c784b379b6e3b077 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -168,7 +168,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
        switch (type) {
        case H3_UNI_S_T_CTRL:
                if (h3c->flags & H3_CF_UNI_CTRL_SET) {
-                       qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR);
+                       qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
                        return -1;
                }
                h3c->flags |= H3_CF_UNI_CTRL_SET;
@@ -182,7 +182,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
 
        case H3_UNI_S_T_QPACK_DEC:
                if (h3c->flags & H3_CF_UNI_QPACK_DEC_SET) {
-                       qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR);
+                       qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
                        return -1;
                }
                h3c->flags |= H3_CF_UNI_QPACK_DEC_SET;
@@ -192,7 +192,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
 
        case H3_UNI_S_T_QPACK_ENC:
                if (h3c->flags & H3_CF_UNI_QPACK_ENC_SET) {
-                       qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR);
+                       qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
                        return -1;
                }
                h3c->flags |= H3_CF_UNI_QPACK_ENC_SET;
@@ -621,7 +621,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
                        total += hlen;
 
                        if (!h3_is_frame_valid(h3c, qcs, ftype)) {
-                               qcc_emit_cc_app(qcs->qcc, H3_FRAME_UNEXPECTED);
+                               qcc_emit_cc_app(qcs->qcc, H3_FRAME_UNEXPECTED, 1);
                                return -1;
                        }
 
@@ -643,7 +643,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
                         * excessive decompressed size.
                         */
                        if (flen > QC_S_RX_BUF_SZ) {
-                               qcc_emit_cc_app(qcs->qcc, H3_EXCESSIVE_LOAD);
+                               qcc_emit_cc_app(qcs->qcc, H3_EXCESSIVE_LOAD, 1);
                                return -1;
                        }
                        break;
@@ -665,7 +665,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
                                 * only close the stream once RESET_STREAM is
                                 * supported.
                                 */
-                               qcc_emit_cc_app(qcs->qcc, h3c->err);
+                               qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
                                return -1;
                        }
                        break;
@@ -679,7 +679,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
                case H3_FT_SETTINGS:
                        ret = h3_parse_settings_frm(qcs->qcc->ctx, b, flen);
                        if (ret < 0) {
-                               qcc_emit_cc_app(qcs->qcc, h3c->err);
+                               qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
                                return -1;
                        }
                        h3c->flags |= H3_CF_SETTINGS_RECV;
index 065ffa57fe3d2199b5e6ce57cc8467113e585c46..658a97437d48eeaddbc84990390dd6d094a86eec 100644 (file)
@@ -667,13 +667,24 @@ static int qcc_decode_qcs(struct qcc *qcc, struct qcs *qcs)
 }
 
 /* Emit a CONNECTION_CLOSE_APP with error <err>. Reserved for application error
- * code. This will interrupt all future send/receive operations.
+ * code. To close the connection right away, set <immediate> : this is useful
+ * when dealing with a connection fatal error. Else a graceful shutdown will be
+ * conducted : the error-code is only registered. The lower layer is
+ * responsible to close the connection when deemed suitable. Note that in this
+ * case the error code might be overwritten if an immediate close is requested
+ * in the interval.
  */
-void qcc_emit_cc_app(struct qcc *qcc, int err)
+void qcc_emit_cc_app(struct qcc *qcc, int err, int immediate)
 {
-       quic_set_connection_close(qcc->conn->handle.qc, quic_err_app(err));
-       qcc->flags |= QC_CF_CC_EMIT;
-       tasklet_wakeup(qcc->wait_event.tasklet);
+       if (immediate) {
+               quic_set_connection_close(qcc->conn->handle.qc, quic_err_app(err));
+               qcc->flags |= QC_CF_CC_EMIT;
+               tasklet_wakeup(qcc->wait_event.tasklet);
+       }
+       else {
+               /* Only register the error code for graceful shutdown. */
+               qcc->conn->handle.qc->err = quic_err_app(err);
+       }
 }
 
 /* Prepare for the emission of RESET_STREAM on <qcs> with error code <err>. */