#define QC_CF_CC_EMIT 0x00000001 /* A CONNECTION_CLOSE is set by the MUX */
#define QC_CF_BLK_MFCTL 0x00000002 /* sending blocked due to connection flow-control */
#define QC_CF_CONN_FULL 0x00000004 /* no stream buffers available on connection */
-#define QC_CF_APP_FINAL 0x00000008 /* The application layer was finalized */
struct qcc {
struct connection *conn;
TRACE_LEAVE(H3_EV_H3S_END, qcs->qcc->conn, qcs);
}
+/* Initialize H3 control stream and prepare SETTINGS emission.
+ *
+ * Returns 0 on success else non-zero.
+ */
static int h3_finalize(void *ctx)
{
struct h3c *h3c = ctx;
qcs = qcc_init_stream_local(h3c->qcc, 0);
if (!qcs)
- return 0;
+ return 1;
h3_control_send(qcs, h3c);
h3c->ctrl_strm = qcs;
- return 1;
+ return 0;
}
/* Generate a GOAWAY frame for <h3c> connection on the control stream.
TRACE_PROTO("application layer initialized", QMUX_EV_QCC_NEW, qcc->conn);
+ /* RFC 9114 7.2.4.2. Initialization
+ *
+ * Endpoints MUST NOT require any data to be
+ * received from the peer prior to sending the SETTINGS frame;
+ * settings MUST be sent as soon as the transport is ready to
+ * send data.
+ */
+ if (qcc->app_ops->finalize) {
+ if (qcc->app_ops->finalize(qcc->ctx)) {
+ TRACE_ERROR("app ops finalize error", QMUX_EV_QCC_NEW, qcc->conn);
+ goto err;
+ }
+ tasklet_wakeup(qcc->wait_event.tasklet);
+ }
+
TRACE_LEAVE(QMUX_EV_QCC_NEW, qcc->conn);
return 0;
if (qcc->flags & QC_CF_BLK_MFCTL)
goto err;
- if (!(qcc->flags & QC_CF_APP_FINAL) && !eb_is_empty(&qcc->streams_by_id) &&
- qcc->app_ops->finalize) {
- /* Finalize the application layer before sending any stream.
- * For h3 this consists in preparing the control stream data (SETTINGS h3).
- */
- qcc->app_ops->finalize(qcc->ctx);
- qcc->flags |= QC_CF_APP_FINAL;
- }
-
/* Send STREAM/STOP_SENDING/RESET_STREAM data for registered streams. */
list_for_each_entry_safe(qcs, qcs_tmp, &qcc->send_list, el_send) {
/* Stream must not be present in send_list if it has nothing to send. */