diff --git a/src/mux_quic.c b/src/mux_quic.c index f6e2ae5ef..15ce50cb1 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -2416,13 +2416,7 @@ static int qcc_subscribe_send(struct qcc *qcc) return 1; } -/* Wrapper for send on transport layer. Send a list of frames for the - * connection . - * - * Returns 0 if all data sent with success. On fatal error, a negative error - * code is returned. A positive 1 is used if emission should be paced. - */ -static int qcc_send_frames(struct qcc *qcc, struct list *frms, int stream) +static int _qcc_send_frames(struct qcc *qcc, struct list *frms, int stream) { enum quic_tx_err ret; struct quic_pacer *pacer = NULL; @@ -2461,6 +2455,104 @@ static int qcc_send_frames(struct qcc *qcc, struct list *frms, int stream) return -1; } +/* Wrapper for send on transport layer. Send a list of frames for the + * connection . + * + * Returns 0 if all data sent with success. On fatal error, a negative error + * code is returned. A positive 1 is used if emission should be paced. + */ +static int _qcc_qos_send_frames(struct qcc *qcc, struct list *frms, int stream) +{ + struct connection *conn = qcc->conn; + struct quic_frame *frm, *frm_old; + unsigned char *pos, *old, *end; + size_t ret; + + TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn); + list_for_each_entry_safe(frm, frm_old, frms, list) { + loop: + struct quic_frame *split_frm = NULL, *old_frm; + + b_reset(&trash); + old = pos = (unsigned char *)b_orig(&trash); + end = (unsigned char *)b_wrap(&trash); + + TRACE_PRINTF(TRACE_LEVEL_DEVELOPER, QMUX_EV_QCC_SEND, qcc->conn, 0, 0, 0, + "frm type %02llx", (ullong)frm->type); + + if (frm->type >= QUIC_FT_STREAM_8 && frm->type <= QUIC_FT_STREAM_F) { + size_t flen, split_size; + + flen = quic_strm_frm_fillbuf(end - pos, frm, &split_size); + if (!flen) + continue; + + if (split_size) { + split_frm = quic_strm_frm_split(frm, split_size); + if (!split_frm) { + ABORT_NOW(); + continue; + } + + old_frm = frm; + frm = split_frm; + } + + } + + qc_build_frm(&pos, end, frm, NULL, NULL); + BUG_ON(pos - old > global.tune.bufsize); + BUG_ON(pos == old); + b_add(&trash, pos - old); + + ret = conn->xprt->snd_buf(conn, conn->xprt_ctx, &trash, b_data(&trash), 0); + if (!ret) { + TRACE_DEVEL("snd_buf interrupted", QMUX_EV_QCC_SEND, qcc->conn); + if (split_frm) + LIST_INSERT(frms, &split_frm->list); + break; + } + + if (ret != b_data(&trash)) { + /* TODO */ + ABORT_NOW(); + } + + if (frm->type >= QUIC_FT_STREAM_8 && frm->type <= QUIC_FT_STREAM_E) { + /* TODO notify MUX */ + } + + LIST_DEL_INIT(&frm->list); + if (split_frm) { + frm = old_frm; + goto loop; + } + } + + if (conn->flags & CO_FL_ERROR) { + /* TODO */ + //ABORT_NOW(); + } + else if (!LIST_ISEMPTY(frms) && !(qcc->wait_event.events & SUB_RETRY_SEND)) { + conn->xprt->subscribe(conn, conn->xprt_ctx, SUB_RETRY_SEND, &qcc->wait_event); + } + + TRACE_LEAVE(QMUX_EV_QCC_SEND, qcc->conn); + return 0; +} + +/* Wrapper for send on transport layer. Send a list of frames for the + * connection . + * + * Returns 0 if all data sent with success. On fatal error, a negative error + * code is returned. A positive 1 is used if emission should be paced. + */ +static int qcc_send_frames(struct qcc *qcc, struct list *frms, int stream) +{ + return qmux_is_quic(qcc) ? _qcc_send_frames(qcc, frms, stream) : + _qcc_qos_send_frames(qcc, frms, stream); +} + /* Emit a RESET_STREAM on . * * Returns 0 if the frame has been successfully sent else non-zero.