diff options
Diffstat (limited to 'src/hq_interop.c')
-rw-r--r-- | src/hq_interop.c | 117 |
1 files changed, 91 insertions, 26 deletions
diff --git a/src/hq_interop.c b/src/hq_interop.c index 31c2101..c88f888 100644 --- a/src/hq_interop.c +++ b/src/hq_interop.c @@ -8,8 +8,10 @@ #include <haproxy/http.h> #include <haproxy/mux_quic.h> #include <haproxy/qmux_http.h> +#include <haproxy/qmux_trace.h> +#include <haproxy/trace.h> -static ssize_t hq_interop_decode_qcs(struct qcs *qcs, struct buffer *b, int fin) +static ssize_t hq_interop_rcv_buf(struct qcs *qcs, struct buffer *b, int fin) { struct htx *htx; struct htx_sl *sl; @@ -25,7 +27,7 @@ static ssize_t hq_interop_decode_qcs(struct qcs *qcs, struct buffer *b, int fin) if (!fin) return 0; - b_alloc(&htx_buf); + b_alloc(&htx_buf, DB_MUX_RX); htx = htx_from_buf(&htx_buf); /* skip method */ @@ -83,34 +85,21 @@ static ssize_t hq_interop_decode_qcs(struct qcs *qcs, struct buffer *b, int fin) return b_data(b); } -static struct buffer *mux_get_buf(struct qcs *qcs) -{ - if (!b_size(&qcs->tx.buf)) - b_alloc(&qcs->tx.buf); - - return &qcs->tx.buf; -} - static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count) { enum htx_blk_type btype; - struct htx *htx; + struct htx *htx = NULL; struct htx_blk *blk; int32_t idx; uint32_t bsize, fsize; - struct buffer *res, outbuf; + struct buffer *res = NULL; size_t total = 0; - - res = mux_get_buf(qcs); - outbuf = b_make(b_tail(res), b_contig_space(res), 0, 0); + int err; htx = htx_from_buf(buf); - if (htx->extra && htx->extra == HTX_UNKOWN_PAYLOAD_LENGTH) - qcs->flags |= QC_SF_UNKNOWN_PL_LENGTH; - - while (count && !htx_is_empty(htx) && !(qcs->flags & QC_SF_BLK_MROOM)) { + while (count && !htx_is_empty(htx) && qcc_stream_can_send(qcs)) { /* Not implemented : QUIC on backend side */ idx = htx_get_head(htx); blk = htx_get_blk(htx, idx); @@ -121,18 +110,48 @@ static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf, switch (btype) { case HTX_BLK_DATA: + res = qcc_get_stream_txbuf(qcs, &err); + if (!res) { + if (err) + ABORT_NOW(); + goto end; + } + + if (unlikely(fsize == count && + !b_data(res) && + htx_nbblks(htx) == 1 && btype == HTX_BLK_DATA)) { + void *old_area = res->area; + + TRACE_DATA("perform zero-copy DATA transfer", QMUX_EV_STRM_SEND, + qcs->qcc->conn, qcs); + + /* remap MUX buffer to HTX area */ + *res = b_make(buf->area, buf->size, + sizeof(struct htx) + blk->addr, fsize); + + /* assign old MUX area to HTX buffer. */ + buf->area = old_area; + buf->data = buf->head = 0; + total += fsize; + + /* reload HTX with empty buffer. */ + *htx = *htx_from_buf(buf); + goto end; + } + if (fsize > count) fsize = count; - if (b_room(&outbuf) < fsize) - fsize = b_room(&outbuf); + if (b_contig_space(res) < fsize) + fsize = b_contig_space(res); if (!fsize) { - qcs->flags |= QC_SF_BLK_MROOM; - goto end; + /* Release buf and restart parsing if sending still possible. */ + qcc_release_stream_txbuf(qcs); + continue; } - b_putblk(&outbuf, htx_get_blk_ptr(htx, blk), fsize); + b_putblk(res, htx_get_blk_ptr(htx, blk), fsize); total += fsize; count -= fsize; @@ -155,12 +174,56 @@ static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf, } end: - b_add(res, b_data(&outbuf)); htx_to_buf(htx, buf); return total; } +static size_t hq_interop_nego_ff(struct qcs *qcs, size_t count) +{ + int err, ret = 0; + struct buffer *res; + + start: + res = qcc_get_stream_txbuf(qcs, &err); + if (!res) { + if (err) + ABORT_NOW(); + qcs->sd->iobuf.flags |= IOBUF_FL_FF_BLOCKED; + goto end; + } + + if (!b_room(res)) { + if (qcc_release_stream_txbuf(qcs)) { + qcs->sd->iobuf.flags |= IOBUF_FL_FF_BLOCKED; + goto end; + } + + goto start; + } + + /* No header required for HTTP/0.9, no need to reserve an offset. */ + qcs->sd->iobuf.buf = res; + qcs->sd->iobuf.offset = 0; + qcs->sd->iobuf.data = 0; + + ret = MIN(count, b_contig_space(res)); + end: + return ret; +} + +static size_t hq_interop_done_ff(struct qcs *qcs) +{ + const size_t ret = qcs->sd->iobuf.data; + + /* No header required for HTTP/0.9, simply mark ff as done. */ + qcs->sd->iobuf.buf = NULL; + qcs->sd->iobuf.offset = 0; + qcs->sd->iobuf.data = 0; + + return ret; +} + static int hq_interop_attach(struct qcs *qcs, void *conn_ctx) { qcs_wait_http_req(qcs); @@ -168,7 +231,9 @@ static int hq_interop_attach(struct qcs *qcs, void *conn_ctx) } const struct qcc_app_ops hq_interop_ops = { - .decode_qcs = hq_interop_decode_qcs, + .rcv_buf = hq_interop_rcv_buf, .snd_buf = hq_interop_snd_buf, + .nego_ff = hq_interop_nego_ff, + .done_ff = hq_interop_done_ff, .attach = hq_interop_attach, }; |