uint64_t bytes; /* number of bytes sent */
uint64_t ack_offset; /* last acked ordered byte offset */
struct eb_root acked_frms; /* acked frames ordered by their offsets */
- struct buffer buf; /* transmit buffer, always valid (buf_empty or real buffer) */
- struct buffer mbuf[QCC_MBUF_CNT];
- uint64_t left; /* data currently stored in mbuf waiting for send */
+ struct buffer buf; /* transmit buffer before sending via xprt */
+ struct buffer xprt_buf; /* buffer for xprt sending, cleared on ACK. */
} tx;
struct wait_event *subs; /* recv wait_event the conn_stream associated is waiting on (via qc_subscribe) */
struct list list; /* To be used when adding in qcc->send_list or qcc->fctl_lsit */
return ret;
}
-/* Return next empty buffer of mux.
- * TODO to optimize memory consumption, a non-full buffer should be used before
- * allocating a new one.
- * TODO put this in mux ??
+/* Returns buffer for data sending.
+ * May be NULL if the allocation failed.
*/
-static struct buffer *get_mux_next_tx_buf(struct qcs *qcs)
+static struct buffer *mux_get_buf(struct qcs *qcs)
{
- struct buffer *buf = br_tail(qcs->tx.mbuf);
+ if (!b_size(&qcs->tx.buf))
+ b_alloc(&qcs->tx.buf);
- if (b_data(buf))
- buf = br_tail_add(qcs->tx.mbuf);
-
- if (!b_size(buf))
- qc_get_buf(qcs->qcc, buf);
-
- if (!buf)
- ABORT_NOW();
-
- return buf;
+ return &qcs->tx.buf;
}
static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx)
list[hdr].n = ist("");
- res = get_mux_next_tx_buf(qcs);
+ res = mux_get_buf(qcs);
/* At least 5 bytes to store frame type + length as a varint max size */
if (b_room(res) < 5)
if (!b_quic_enc_int(res, b_data(&headers_buf)))
ABORT_NOW();
b_add(res, b_data(&headers_buf));
- qcs->tx.left += 1 + frame_length_size + b_data(&headers_buf);
ret = 0;
blk = htx_get_head_blk(htx);
if (type != HTX_BLK_DATA)
goto end;
- res = get_mux_next_tx_buf(qcs);
+ res = mux_get_buf(qcs);
if (fsize > count)
fsize = count;
htx_cut_data_blk(htx, blk, fsize);
b_add(res, b_data(&outbuf));
- qcs->tx.left += b_data(&outbuf);
goto new_frame;
end:
offer_buffers(NULL, 1);
}
+ b_free(&qcs->tx.buf);
+ b_free(&qcs->tx.xprt_buf);
+
if (qcs->subs)
qcs->subs->events = 0;
qcs->tx.acked_frms = EB_ROOT_UNIQUE;
qcs->tx.max_data = qcc->strms[qcs_type].tx.max_data;
qcs->tx.buf = BUF_NULL;
- br_init(qcs->tx.mbuf, sizeof(qcs->tx.mbuf) / sizeof(qcs->tx.mbuf[0]));
- qcs->tx.left = 0;
+ qcs->tx.xprt_buf = BUF_NULL;
eb64_insert(&qcc->streams_by_id, &qcs->by_id);
qcc->strms[qcs_type].nb_streams++;
qcs->tx.offset = qcs->tx.bytes = qcs->tx.ack_offset = 0;
qcs->tx.acked_frms = EB_ROOT_UNIQUE;
qcs->tx.buf = BUF_NULL;
- br_init(qcs->tx.mbuf, sizeof(qcs->tx.mbuf) / sizeof(qcs->tx.mbuf[0]));
- qcs->tx.left = 0;
+ qcs->tx.xprt_buf = BUF_NULL;
qcs->subs = NULL;
LIST_INIT(&qcs->list);
qcs->rx.offset = qcs->rx.bytes = 0;
qcs->rx.buf = BUF_NULL;
qcs->rx.frms = EB_ROOT_UNIQUE;
- br_init(qcs->tx.mbuf, sizeof(qcs->tx.mbuf) / sizeof(qcs->tx.mbuf[0]));
- qcs->tx.left = 0;
+ qcs->tx.buf = BUF_NULL;
+ qcs->tx.xprt_buf = BUF_NULL;
qcs->subs = NULL;
LIST_INIT(&qcs->list);
static int qcs_push_frame(struct qcs *qcs, struct buffer *payload, int fin, uint64_t offset)
{
struct quic_frame *frm;
- struct buffer *buf = &qcs->tx.buf;
+ struct buffer *buf = &qcs->tx.xprt_buf;
struct quic_enc_level *qel = &qcs->qcc->conn->qc->els[QUIC_TLS_ENC_LEVEL_APP];
int total = 0, to_xfer;
*/
static int qc_send(struct qcc *qcc)
{
- struct qcs *qcs;
struct eb64_node *node;
int ret, done;
*/
node = eb64_first(&qcc->streams_by_id);
while (node) {
- struct buffer *buf;
- qcs = container_of(node, struct qcs, by_id);
- for (buf = br_head(qcs->tx.mbuf); b_size(buf); buf = br_del_head(qcs->tx.mbuf)) {
+ struct qcs *qcs = container_of(node, struct qcs, by_id);
+ struct buffer *buf = &qcs->tx.buf;
+ if (b_data(buf)) {
+ char fin = 0;
+
+ /* if FIN is activated, ensure the buffer to
+ * send is the last
+ */
+ if (qcs->flags & QC_SF_FIN_STREAM) {
+ BUG_ON(b_data(&qcs->tx.buf) < b_data(buf));
+ fin = (b_data(&qcs->tx.buf) - b_data(buf) == 0);
+ }
+
+ ret = qcs_push_frame(qcs, buf, fin, qcs->tx.offset);
+ if (ret < 0)
+ ABORT_NOW();
+
+ qcs->tx.offset += ret;
if (b_data(buf)) {
- char fin = 0;
-
- /* if FIN is activated, ensure the buffer to
- * send is the last
- */
- if (qcs->flags & QC_SF_FIN_STREAM) {
- BUG_ON(qcs->tx.left < b_data(buf));
- fin = !(qcs->tx.left - b_data(buf));
- }
-
- ret = qcs_push_frame(qcs, buf, fin, qcs->tx.offset);
- if (ret < 0)
- ABORT_NOW();
-
- qcs->tx.left -= ret;
- qcs->tx.offset += ret;
- if (b_data(buf)) {
- qcc->conn->xprt->subscribe(qcc->conn, qcc->conn->xprt_ctx,
- SUB_RETRY_SEND, &qcc->wait_event);
- break;
- }
+ qcc->conn->xprt->subscribe(qcc->conn, qcc->conn->xprt_ctx,
+ SUB_RETRY_SEND, &qcc->wait_event);
+ break;
}
- b_free(buf);
}
node = eb64_next(node);
}