REORG: quic: use a dedicated module for qc_stream_desc

Regroup all type definitions and functions related to qc_stream_desc in
the source file src/quic_stream.c.

qc_stream_desc complexity will be increased with the development of Tx
multi-buffers. Having a dedicated module is useful to mix it with
pure transport/quic-conn code.
This commit is contained in:
Amaury Denoyelle 2022-04-19 17:21:11 +02:00
parent da6ad2092a
commit 0cc02a345b
9 changed files with 152 additions and 112 deletions

View File

@ -636,7 +636,8 @@ ifneq ($(USE_QUIC),)
OPTIONS_OBJS += src/quic_sock.o src/proto_quic.o src/xprt_quic.o src/quic_tls.o \
src/quic_frame.o src/quic_cc.o src/quic_cc_newreno.o src/mux_quic.o \
src/cbuf.o src/qpack-dec.o src/qpack-tbl.o src/h3.o src/qpack-enc.o \
src/hq_interop.o src/cfgparse-quic.o src/quic_loss.o
src/hq_interop.o src/cfgparse-quic.o src/quic_loss.o \
src/quic_stream.o
endif
ifneq ($(USE_LUA),)

View File

@ -10,6 +10,7 @@
#include <haproxy/buf-t.h>
#include <haproxy/connection-t.h>
#include <haproxy/quic_stream-t.h>
#include <haproxy/xprt_quic-t.h>
#include <haproxy/conn_stream-t.h>

View File

@ -0,0 +1,32 @@
#ifndef _HAPROXY_QUIC_STREAM_T_H_
#define _HAPROXY_QUIC_STREAM_T_H_
#ifdef USE_QUIC
#include <import/ebtree-t.h>
#include <haproxy/buf-t.h>
/* QUIC STREAM descriptor.
*
* This structure is the low-level counterpart of the QUIC STREAM at the MUX
* layer. It provides a node for tree-storage and buffering for Tx.
*
* Once the MUX has finished to transfer data on a STREAM, it must release its
* QUIC STREAM descriptor. The descriptor will be kept by the quic_conn until
* all acknowledgement has been received.
*/
struct qc_stream_desc {
struct eb64_node by_id; /* id of the stream used for <streams_by_id> tree */
struct buffer buf; /* buffer for STREAM data on Tx, emptied on acknowledge */
uint64_t ack_offset; /* last acknowledged offset */
struct eb_root acked_frms; /* ACK frames tree for non-contiguous ACK ranges */
int release; /* set to 1 when the MUX has finished to use this stream */
void *ctx; /* MUX specific context */
};
#endif /* USE_QUIC */
#endif /* _HAPROXY_QUIC_STREAM_T_H_ */

View File

@ -0,0 +1,16 @@
#ifndef _HAPROXY_QUIC_STREAM_H_
#define _HAPROXY_QUIC_STREAM_H_
#ifdef USE_QUIC
#include <haproxy/quic_stream-t.h>
struct quic_conn;
struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx);
void qc_stream_desc_release(struct qc_stream_desc *stream,
struct quic_conn *qc);
int qc_stream_desc_free(struct qc_stream_desc *stream);
#endif /* USE_QUIC */
#endif /* _HAPROXY_QUIC_STREAM_H_ */

View File

@ -767,26 +767,5 @@ struct quic_conn {
const struct qcc_app_ops *app_ops;
};
/* QUIC STREAM descriptor.
*
* This structure is the low-level counterpart of the QUIC STREAM at the MUX
* layer. It provides a node for tree-storage and buffering for Tx.
*
* Once the MUX has finished to transfer data on a STREAM, it must release its
* QUIC STREAM descriptor. The descriptor will be kept by the quic_conn until
* all acknowledgement has been received.
*/
struct qc_stream_desc {
struct eb64_node by_id; /* id of the stream used for <streams_by_id> tree */
struct buffer buf; /* buffer for STREAM data on Tx, emptied on acknowledge */
uint64_t ack_offset; /* last acknowledged offset */
struct eb_root acked_frms; /* ACK frames tree for non-contiguous ACK ranges */
int release; /* set to 1 when the MUX has finished to use this stream */
void *ctx; /* MUX specific context */
};
#endif /* USE_QUIC */
#endif /* _HAPROXY_XPRT_QUIC_T_H */

View File

@ -1248,9 +1248,6 @@ int quic_lstnr_dgram_dispatch(unsigned char *buf, size_t len, void *owner,
struct quic_dgram *new_dgram, struct list *dgrams);
int qc_send_app_pkts(struct quic_conn *qc, struct list *frms);
struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx);
void qc_stream_desc_release(struct qc_stream_desc *stream, struct quic_conn *qc);
void qc_notify_close(struct quic_conn *qc);
#endif /* USE_QUIC */

View File

@ -8,6 +8,7 @@
#include <haproxy/dynbuf.h>
#include <haproxy/htx.h>
#include <haproxy/pool.h>
#include <haproxy/quic_stream.h>
#include <haproxy/sink.h>
#include <haproxy/ssl_sock-t.h>
#include <haproxy/trace.h>

99
src/quic_stream.c Normal file
View File

@ -0,0 +1,99 @@
#include <haproxy/quic_stream.h>
#include <import/eb64tree.h>
#include <haproxy/api.h>
#include <haproxy/buf.h>
#include <haproxy/list.h>
#include <haproxy/dynbuf.h>
#include <haproxy/pool.h>
#include <haproxy/xprt_quic.h>
DECLARE_STATIC_POOL(pool_head_quic_conn_stream, "qc_stream_desc",
sizeof(struct qc_stream_desc));
/* Allocate a new stream descriptor with id <id>. The caller is responsible to
* store the stream in the appropriate tree.
*
* Returns the newly allocated instance on success or else NULL.
*/
struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx)
{
struct qc_stream_desc *stream;
stream = pool_alloc(pool_head_quic_conn_stream);
if (!stream)
return NULL;
stream->by_id.key = id;
stream->by_id.node.leaf_p = NULL;
stream->buf = BUF_NULL;
stream->acked_frms = EB_ROOT;
stream->ack_offset = 0;
stream->release = 0;
stream->ctx = ctx;
return stream;
}
/* Mark the stream descriptor <stream> as released by the upper layer. It will
* be freed as soon as all its buffered data are acknowledged. In the meantime,
* the stream is stored in the <qc> tree : thus it must have been removed from
* any other tree before calling this function.
*/
void qc_stream_desc_release(struct qc_stream_desc *stream,
struct quic_conn *qc)
{
BUG_ON(stream->by_id.node.leaf_p);
stream->release = 1;
stream->ctx = NULL;
if (!b_data(&stream->buf))
qc_stream_desc_free(stream);
else
eb64_insert(&qc->streams_by_id, &stream->by_id);
}
/* Free the stream descriptor <stream> buffer. This function should be used
* when all its data have been acknowledged. If the stream was released by the
* upper layer, the stream descriptor will be freed.
*
* Returns 0 if the stream was not freed else non-zero.
*/
int qc_stream_desc_free(struct qc_stream_desc *stream)
{
b_free(&stream->buf);
offer_buffers(NULL, 1);
if (stream->release) {
/* Free frames still waiting for an ACK. Even if the stream buf
* is NULL, some frames could still be not acknowledged. This
* is notably the case for retransmission where multiple frames
* points to the same buffer content.
*/
struct eb64_node *frm_node = eb64_first(&stream->acked_frms);
while (frm_node) {
struct quic_stream *strm;
struct quic_frame *frm;
strm = eb64_entry(&frm_node->node, struct quic_stream, offset);
frm_node = eb64_next(frm_node);
eb64_delete(&strm->offset);
frm = container_of(strm, struct quic_frame, stream);
LIST_DELETE(&frm->list);
quic_tx_packet_refdec(frm->pkt);
pool_free(pool_head_quic_frame, frm);
}
eb64_delete(&stream->by_id);
pool_free(pool_head_quic_conn_stream, stream);
return 1;
}
return 0;
}

View File

@ -45,6 +45,7 @@
#include <haproxy/quic_frame.h>
#include <haproxy/quic_loss.h>
#include <haproxy/quic_sock.h>
#include <haproxy/quic_stream.h>
#include <haproxy/cbuf.h>
#include <haproxy/proto_quic.h>
#include <haproxy/quic_tls.h>
@ -169,7 +170,6 @@ DECLARE_POOL(pool_head_quic_rx_strm_frm, "quic_rx_strm_frm", sizeof(struct quic_
DECLARE_STATIC_POOL(pool_head_quic_crypto_buf, "quic_crypto_buf_pool", sizeof(struct quic_crypto_buf));
DECLARE_POOL(pool_head_quic_frame, "quic_frame_pool", sizeof(struct quic_frame));
DECLARE_STATIC_POOL(pool_head_quic_arng, "quic_arng_pool", sizeof(struct quic_arng_node));
DECLARE_STATIC_POOL(pool_head_quic_conn_stream, "qc_stream_desc", sizeof(struct qc_stream_desc));
static struct quic_tx_packet *qc_build_pkt(unsigned char **pos, const unsigned char *buf_end,
struct quic_enc_level *qel, struct list *frms,
@ -1429,48 +1429,6 @@ static int qc_pkt_decrypt(struct quic_rx_packet *pkt, struct quic_enc_level *qel
return 1;
}
/* Free the stream descriptor <stream> buffer. This function should be used
* when all its data have been acknowledged. If the stream was released by the
* upper layer, the stream descriptor will be freed.
*
* Returns 0 if the stream was not freed else non-zero.
*/
static int qc_stream_desc_free(struct qc_stream_desc *stream)
{
b_free(&stream->buf);
offer_buffers(NULL, 1);
if (stream->release) {
/* Free frames still waiting for an ACK. Even if the stream buf
* is NULL, some frames could still be not acknowledged. This
* is notably the case for retransmission where multiple frames
* points to the same buffer content.
*/
struct eb64_node *frm_node = eb64_first(&stream->acked_frms);
while (frm_node) {
struct quic_stream *strm;
struct quic_frame *frm;
strm = eb64_entry(&frm_node->node, struct quic_stream, offset);
frm_node = eb64_next(frm_node);
eb64_delete(&strm->offset);
frm = container_of(strm, struct quic_frame, stream);
LIST_DELETE(&frm->list);
quic_tx_packet_refdec(frm->pkt);
pool_free(pool_head_quic_frame, frm);
}
eb64_delete(&stream->by_id);
pool_free(pool_head_quic_conn_stream, stream);
return 1;
}
return 0;
}
/* Remove from <stream> the acknowledged frames.
*
* Returns 1 if at least one frame was removed else 0.
@ -5956,50 +5914,6 @@ int quic_lstnr_dgram_dispatch(unsigned char *buf, size_t len, void *owner,
return 0;
}
/* Allocate a new stream descriptor with id <id>. The caller is responsible to
* store the stream in the appropriate tree.
*
* Returns the newly allocated instance on success or else NULL.
*/
struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx)
{
struct qc_stream_desc *stream;
stream = pool_alloc(pool_head_quic_conn_stream);
if (!stream)
return NULL;
stream->by_id.key = id;
stream->by_id.node.leaf_p = NULL;
stream->buf = BUF_NULL;
stream->acked_frms = EB_ROOT;
stream->ack_offset = 0;
stream->release = 0;
stream->ctx = ctx;
return stream;
}
/* Mark the stream descriptor <stream> as released by the upper layer. It will
* be freed as soon as all its buffered data are acknowledged. In the meantime,
* the stream is stored in the <qc> tree : thus it must have been removed from
* any other tree before calling this function.
*/
void qc_stream_desc_release(struct qc_stream_desc *stream,
struct quic_conn *qc)
{
BUG_ON(stream->by_id.node.leaf_p);
stream->release = 1;
stream->ctx = NULL;
if (!b_data(&stream->buf))
qc_stream_desc_free(stream);
else
eb64_insert(&qc->streams_by_id, &stream->by_id);
}
/* Notify the MUX layer if alive about an imminent close of <qc>. */
void qc_notify_close(struct quic_conn *qc)
{