blob: e5998ef1ff690ae6fdc52947ea9628c6563c2fc4 [file] [log] [blame]
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +02001#include <haproxy/quic_stream.h>
2
3#include <import/eb64tree.h>
4
5#include <haproxy/api.h>
6#include <haproxy/buf.h>
7#include <haproxy/list.h>
8#include <haproxy/dynbuf.h>
9#include <haproxy/pool.h>
10#include <haproxy/xprt_quic.h>
11
12DECLARE_STATIC_POOL(pool_head_quic_conn_stream, "qc_stream_desc",
13 sizeof(struct qc_stream_desc));
Amaury Denoyellea4569202022-04-15 17:29:25 +020014DECLARE_STATIC_POOL(pool_head_quic_conn_stream_buf, "qc_stream_buf",
15 sizeof(struct qc_stream_buf));
16
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020017
18/* Allocate a new stream descriptor with id <id>. The caller is responsible to
19 * store the stream in the appropriate tree.
20 *
21 * Returns the newly allocated instance on success or else NULL.
22 */
Amaury Denoyellee4301da2022-04-19 17:59:50 +020023struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx,
24 struct quic_conn *qc)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020025{
26 struct qc_stream_desc *stream;
27
28 stream = pool_alloc(pool_head_quic_conn_stream);
29 if (!stream)
30 return NULL;
31
32 stream->by_id.key = id;
Amaury Denoyellee4301da2022-04-19 17:59:50 +020033 eb64_insert(&qc->streams_by_id, &stream->by_id);
Amaury Denoyelleb22c0462022-04-21 11:00:41 +020034 stream->qc = qc;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020035
Amaury Denoyellea4569202022-04-15 17:29:25 +020036 stream->buf = NULL;
37 LIST_INIT(&stream->buf_list);
38 stream->buf_offset = 0;
39
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020040 stream->acked_frms = EB_ROOT;
41 stream->ack_offset = 0;
42 stream->release = 0;
43 stream->ctx = ctx;
44
45 return stream;
46}
47
Amaury Denoyellee4301da2022-04-19 17:59:50 +020048/* Mark the stream descriptor <stream> as released. It will be freed as soon as
49 * all its buffered data are acknowledged.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020050 */
Amaury Denoyellee4301da2022-04-19 17:59:50 +020051void qc_stream_desc_release(struct qc_stream_desc *stream)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020052{
Amaury Denoyellee4301da2022-04-19 17:59:50 +020053 /* A stream can be released only one time. */
54 BUG_ON(stream->release);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020055
56 stream->release = 1;
57 stream->ctx = NULL;
58
Amaury Denoyellea4569202022-04-15 17:29:25 +020059 if (LIST_ISEMPTY(&stream->buf_list)) {
60 /* if no buffer left we can free the stream. */
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020061 qc_stream_desc_free(stream);
Amaury Denoyellea4569202022-04-15 17:29:25 +020062 }
63 else {
64 /* A released stream does not use <stream.buf>. */
65 stream->buf = NULL;
66 }
67}
68
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +020069/* Acknowledge data at <offset> of length <len> for <stream>. It is handled
70 * only if it covers a range corresponding to stream.ack_offset. After data
71 * removal, if the stream does not contains data any more and is already
72 * released, the instance stream is freed. <stream> is set to NULL to indicate
73 * this.
74 *
75 * Returns the count of byte removed from stream. Do not forget to check if
76 * <stream> is NULL after invocation.
77 */
Amaury Denoyelled2f80a22022-04-15 17:30:49 +020078int qc_stream_desc_ack(struct qc_stream_desc **stream, size_t offset, size_t len)
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +020079{
80 struct qc_stream_desc *s = *stream;
81 struct qc_stream_buf *stream_buf;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +020082 struct quic_conn *qc = s->qc;
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +020083 struct buffer *buf;
84 size_t diff;
85
86 if (offset + len <= s->ack_offset || offset > s->ack_offset)
87 return 0;
88
89 /* There must be at least a buffer or we must not report an ACK. */
90 BUG_ON(LIST_ISEMPTY(&s->buf_list));
91
92 /* get oldest buffer from buf_list */
93 stream_buf = LIST_NEXT(&s->buf_list, struct qc_stream_buf *, list);
94 buf = &stream_buf->buf;
95
96 diff = offset + len - s->ack_offset;
97 s->ack_offset += diff;
98 b_del(buf, diff);
99
100 /* nothing more to do if buf still not empty. */
101 if (b_data(buf))
102 return diff;
103
104 /* buf is empty and can now be freed. Do not forget to reset current
105 * buf ptr if we were working on it.
106 */
107 LIST_DELETE(&stream_buf->list);
108 if (stream_buf == s->buf) {
109 /* current buf must always be last entry in buflist */
110 BUG_ON(!LIST_ISEMPTY(&s->buf_list));
111 s->buf = NULL;
112 }
113
114 b_free(buf);
115 pool_free(pool_head_quic_conn_stream_buf, stream_buf);
116 offer_buffers(NULL, 1);
117
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200118 /* notify MUX about available buffers. */
119 --qc->stream_buf_count;
120 if (qc->mux_state == QC_MUX_READY) {
121 if (qc->qcc->flags & QC_CF_CONN_FULL) {
122 qc->qcc->flags &= ~QC_CF_CONN_FULL;
123 tasklet_wakeup(qc->qcc->wait_event.tasklet);
124 }
125 }
126
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200127 /* Free stream instance if already released and no buffers left. */
128 if (s->release && LIST_ISEMPTY(&s->buf_list)) {
129 qc_stream_desc_free(s);
130 *stream = NULL;
131 }
132
133 return diff;
134}
135
Amaury Denoyellea4569202022-04-15 17:29:25 +0200136/* Free the stream descriptor <stream> content. This function should be used
137 * when all its data have been acknowledged or on full connection closing. It
138 * must only be called after the stream is released.
139 */
140void qc_stream_desc_free(struct qc_stream_desc *stream)
141{
142 struct qc_stream_buf *buf, *buf_back;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200143 struct quic_conn *qc = stream->qc;
Amaury Denoyellea4569202022-04-15 17:29:25 +0200144 struct eb64_node *frm_node;
145 unsigned int free_count = 0;
146
147 /* This function only deals with released streams. */
148 BUG_ON(!stream->release);
149
150 /* free remaining stream buffers */
151 list_for_each_entry_safe(buf, buf_back, &stream->buf_list, list) {
152 if (!(b_data(&buf->buf))) {
153 b_free(&buf->buf);
154 LIST_DELETE(&buf->list);
155 pool_free(pool_head_quic_conn_stream_buf, buf);
156
157 ++free_count;
158 }
159 }
160
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200161 if (free_count) {
Amaury Denoyellea4569202022-04-15 17:29:25 +0200162 offer_buffers(NULL, free_count);
163
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200164 qc->stream_buf_count -= free_count;
165 if (qc->mux_state == QC_MUX_READY) {
166 /* notify MUX about available buffers. */
167 if (qc->qcc->flags & QC_CF_CONN_FULL) {
168 qc->qcc->flags &= ~QC_CF_CONN_FULL;
169 tasklet_wakeup(qc->qcc->wait_event.tasklet);
170 }
171 }
172 }
173
Amaury Denoyellea4569202022-04-15 17:29:25 +0200174 /* qc_stream_desc might be freed before having received all its ACKs.
175 * This is the case if some frames were retransmitted.
176 */
177 frm_node = eb64_first(&stream->acked_frms);
178 while (frm_node) {
179 struct quic_stream *strm;
180 struct quic_frame *frm;
181
182 strm = eb64_entry(&frm_node->node, struct quic_stream, offset);
183
184 frm_node = eb64_next(frm_node);
185 eb64_delete(&strm->offset);
186
187 frm = container_of(strm, struct quic_frame, stream);
188 LIST_DELETE(&frm->list);
189 quic_tx_packet_refdec(frm->pkt);
190 pool_free(pool_head_quic_frame, frm);
191 }
192
193 eb64_delete(&stream->by_id);
194 pool_free(pool_head_quic_conn_stream, stream);
195}
196
197/* Return the current buffer of <stream>. May be NULL if not allocated. */
198struct buffer *qc_stream_buf_get(struct qc_stream_desc *stream)
199{
200 if (!stream->buf)
201 return NULL;
202
203 return &stream->buf->buf;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200204}
205
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200206/* Check if a new stream buffer can be allocated for the connection <qc>.
207 * Returns a boolean.
208 */
Amaury Denoyelle1b2dba52022-04-15 17:32:04 +0200209static int qc_stream_buf_avail(struct quic_conn *qc)
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200210{
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200211 return qc->stream_buf_count < global.tune.quic_streams_buf;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200212}
213
214/* Allocate a new current buffer for <stream>. The buffer limit count for the
215 * connection is checked first. This function is not allowed if current buffer
216 * is not NULL prior to this call. The new buffer represents stream payload at
217 * offset <offset>.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200218 *
Amaury Denoyellea4569202022-04-15 17:29:25 +0200219 * Returns the buffer or NULL.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200220 */
Amaury Denoyellea4569202022-04-15 17:29:25 +0200221struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream,
222 uint64_t offset)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200223{
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200224 struct quic_conn *qc = stream->qc;
225
Amaury Denoyellea4569202022-04-15 17:29:25 +0200226 /* current buffer must be released first before allocate a new one. */
227 BUG_ON(stream->buf);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200228
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200229 if (!qc_stream_buf_avail(qc))
230 return NULL;
231
232 ++qc->stream_buf_count;
233
Amaury Denoyellea4569202022-04-15 17:29:25 +0200234 stream->buf_offset = offset;
235 stream->buf = pool_alloc(pool_head_quic_conn_stream_buf);
236 if (!stream->buf)
237 return NULL;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200238
Amaury Denoyellea4569202022-04-15 17:29:25 +0200239 stream->buf->buf = BUF_NULL;
240 LIST_APPEND(&stream->buf_list, &stream->buf->list);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200241
Amaury Denoyellea4569202022-04-15 17:29:25 +0200242 return &stream->buf->buf;
243}
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200244
Amaury Denoyellea4569202022-04-15 17:29:25 +0200245/* Release the current buffer of <stream>. It will be kept internally by
246 * the <stream>. The current buffer cannot be NULL.
247 */
248void qc_stream_buf_release(struct qc_stream_desc *stream)
249{
250 /* current buffer already released */
251 BUG_ON(!stream->buf);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200252
Amaury Denoyellea4569202022-04-15 17:29:25 +0200253 stream->buf = NULL;
254 stream->buf_offset = 0;
255}