MINOR: mux-quic/h3: emit SETTINGS via MUX tasklet handler
Previously, QUIC MUX application layer was installed and initialized via MUX init. However, the latter stage involve I/O operations, for example when using HTTP/3 with the emission of a SETTINGS frame. Change this to prevent any I/O operations during MUX init. As such, finalize app_ops callback is now called during the first invokation of qcc_io_send(), in the context of MUX tasklet. To implement this, a new application state value is added, to detect the transition from NULL to INIT stage.
This commit is contained in:
parent
188fc45b95
commit
06e7674399
@ -33,6 +33,7 @@ enum qcs_type {
|
||||
};
|
||||
|
||||
enum qcc_app_st {
|
||||
QCC_APP_ST_NULL,
|
||||
QCC_APP_ST_INIT,
|
||||
QCC_APP_ST_SHUT,
|
||||
} __attribute__((packed));
|
||||
|
12
src/h3.c
12
src/h3.c
@ -1488,7 +1488,7 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Function used to emit stream data from <qcs> control uni-stream.
|
||||
/* Emit SETTINGS frame on <qcs> control uni-stream.
|
||||
*
|
||||
* On success return the number of sent bytes. A negative code is used on
|
||||
* error.
|
||||
@ -2406,7 +2406,8 @@ static int h3_init(struct qcc *qcc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize H3 control stream and prepare SETTINGS emission.
|
||||
/* Open control stream for <ctx> HTTP/3 connection and schedule a SETTINGS
|
||||
* frame emission on it.
|
||||
*
|
||||
* Returns 0 on success else non-zero.
|
||||
*/
|
||||
@ -2429,6 +2430,13 @@ static int h3_finalize(void *ctx)
|
||||
qcs_send_metadata(qcs);
|
||||
h3c->ctrl_strm = qcs;
|
||||
|
||||
/* 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 (h3_control_send(qcs, h3c) < 0) {
|
||||
qcc_set_error(qcc, H3_ERR_INTERNAL_ERROR, 1);
|
||||
goto err;
|
||||
|
@ -1474,28 +1474,13 @@ int qcc_install_app_ops(struct qcc *qcc, const struct qcc_app_ops *app_ops)
|
||||
TRACE_ENTER(QMUX_EV_QCC_NEW, qcc->conn);
|
||||
|
||||
if (app_ops->init && !app_ops->init(qcc)) {
|
||||
TRACE_ERROR("app ops init error", QMUX_EV_QCC_NEW, qcc->conn);
|
||||
TRACE_ERROR("application layer install error", QMUX_EV_QCC_NEW, qcc->conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
TRACE_PROTO("application layer initialized", QMUX_EV_QCC_NEW, qcc->conn);
|
||||
TRACE_PROTO("application layer installed", QMUX_EV_QCC_NEW, qcc->conn);
|
||||
qcc->app_ops = app_ops;
|
||||
|
||||
/* 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;
|
||||
|
||||
@ -2480,6 +2465,29 @@ static void qcc_wakeup_pacing(struct qcc *qcc)
|
||||
++qcc->tx.paced_sent_ctr;
|
||||
}
|
||||
|
||||
/* Finalize <qcc> app layer initialization with I/O operations.
|
||||
*
|
||||
* Returns 0 on success else non-zero.
|
||||
*/
|
||||
static int qcc_app_init(struct qcc *qcc)
|
||||
{
|
||||
TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn);
|
||||
|
||||
if (qcc->app_ops->finalize && qcc->app_ops->finalize(qcc->ctx)) {
|
||||
TRACE_ERROR("app ops finalize error", QMUX_EV_QCC_NEW, qcc->conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
qcc->app_st = QCC_APP_ST_INIT;
|
||||
|
||||
TRACE_LEAVE(QMUX_EV_QCC_SEND, qcc->conn);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
TRACE_DEVEL("leaving on error", QMUX_EV_QCC_SEND, qcc->conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Proceed to sending. Loop through all available streams for the <qcc>
|
||||
* instance and try to send as much as possible.
|
||||
*
|
||||
@ -2530,6 +2538,11 @@ static int qcc_io_send(struct qcc *qcc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (qcc->app_st < QCC_APP_ST_INIT) {
|
||||
if (qcc_app_init(qcc))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!LIST_ISEMPTY(&qcc->lfctl.frms)) {
|
||||
if (qcc_send_frames(qcc, &qcc->lfctl.frms, 0)) {
|
||||
TRACE_DEVEL("flow-control frames rejected by transport, aborting send", QMUX_EV_QCC_SEND, qcc->conn);
|
||||
@ -3042,7 +3055,7 @@ static int qmux_init(struct connection *conn, struct proxy *prx,
|
||||
conn->ctx = qcc;
|
||||
qcc->nb_hreq = qcc->nb_sc = 0;
|
||||
qcc->flags = 0;
|
||||
qcc->app_st = QCC_APP_ST_INIT;
|
||||
qcc->app_st = QCC_APP_ST_NULL;
|
||||
qcc->glitches = 0;
|
||||
qcc->err = quic_err_transport(QC_ERR_NO_ERROR);
|
||||
|
||||
|
@ -133,6 +133,7 @@ INITCALL1(STG_REGISTER, trace_register_source, TRACE_SOURCE);
|
||||
static char *qcc_app_st_to_str(const enum qcc_app_st st)
|
||||
{
|
||||
switch (st) {
|
||||
case QCC_APP_ST_NULL: return "NULL";
|
||||
case QCC_APP_ST_INIT: return "INIT";
|
||||
case QCC_APP_ST_SHUT: return "SHUT";
|
||||
default: return "";
|
||||
|
Loading…
x
Reference in New Issue
Block a user