blob: a4b984d04281cd04ac4d8a94bcfd0c85b0f97520 [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>
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +02007#include <haproxy/dynbuf.h>
Amaury Denoyelle5c25dc52022-09-30 17:44:15 +02008#include <haproxy/list.h>
9#include <haproxy/mux_quic-t.h>
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020010#include <haproxy/pool.h>
Amaury Denoyelle92fa63f2022-09-30 18:11:13 +020011#include <haproxy/quic_conn.h>
Amaury Denoyelle5c25dc52022-09-30 17:44:15 +020012#include <haproxy/task.h>
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020013
Willy Tarreaua4482272022-05-27 09:11:02 +020014DECLARE_STATIC_POOL(pool_head_quic_stream_desc, "qc_stream_desc",
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020015 sizeof(struct qc_stream_desc));
Willy Tarreaua4482272022-05-27 09:11:02 +020016DECLARE_STATIC_POOL(pool_head_quic_stream_buf, "qc_stream_buf",
Amaury Denoyellea4569202022-04-15 17:29:25 +020017 sizeof(struct qc_stream_buf));
18
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020019
Amaury Denoyelle574dae22024-01-26 14:30:16 +010020static void qc_stream_buf_free(struct qc_stream_desc *stream,
21 struct qc_stream_buf **stream_buf)
22{
23 struct quic_conn *qc = stream->qc;
24 struct buffer *buf = &(*stream_buf)->buf;
25
26 LIST_DEL_INIT(&(*stream_buf)->list);
Amaury Denoyelledc674c22024-01-29 09:18:08 +010027
28 /* Reset current buf ptr if deleted instance is the same one. */
29 if (*stream_buf == stream->buf)
Amaury Denoyelle574dae22024-01-26 14:30:16 +010030 stream->buf = NULL;
Amaury Denoyelle574dae22024-01-26 14:30:16 +010031
32 b_free(buf);
33 offer_buffers(NULL, 1);
34 pool_free(pool_head_quic_stream_buf, *stream_buf);
35 *stream_buf = NULL;
36
37 /* notify MUX about available buffers. */
38 --qc->stream_buf_count;
39 if (qc->mux_state == QC_MUX_READY) {
40 if (qc->qcc->flags & QC_CF_CONN_FULL) {
41 qc->qcc->flags &= ~QC_CF_CONN_FULL;
42 tasklet_wakeup(qc->qcc->wait_event.tasklet);
43 }
44 }
45}
46
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020047/* Allocate a new stream descriptor with id <id>. The caller is responsible to
Frédéric Lécaille7e3f7c42022-09-09 18:05:45 +020048 * store the stream in the appropriate tree. -1 special value must be used for
49 * a CRYPTO data stream, the type being ignored.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020050 *
51 * Returns the newly allocated instance on success or else NULL.
52 */
Frédéric Lécaille664741e2022-05-02 18:46:58 +020053struct qc_stream_desc *qc_stream_desc_new(uint64_t id, enum qcs_type type, void *ctx,
Amaury Denoyellee4301da2022-04-19 17:59:50 +020054 struct quic_conn *qc)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020055{
56 struct qc_stream_desc *stream;
57
Willy Tarreaua4482272022-05-27 09:11:02 +020058 stream = pool_alloc(pool_head_quic_stream_desc);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020059 if (!stream)
60 return NULL;
61
Frédéric Lécaille7e3f7c42022-09-09 18:05:45 +020062 if (id == (uint64_t)-1) {
63 stream->by_id.key = (uint64_t)-1;
64 }
65 else {
66 stream->by_id.key = id;
67 eb64_insert(&qc->streams_by_id, &stream->by_id);
68 qc->rx.strms[type].nb_streams++;
69 }
Amaury Denoyelleb22c0462022-04-21 11:00:41 +020070 stream->qc = qc;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020071
Amaury Denoyellea4569202022-04-15 17:29:25 +020072 stream->buf = NULL;
73 LIST_INIT(&stream->buf_list);
74 stream->buf_offset = 0;
75
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020076 stream->acked_frms = EB_ROOT;
77 stream->ack_offset = 0;
78 stream->release = 0;
79 stream->ctx = ctx;
80
81 return stream;
82}
83
Amaury Denoyellee4301da2022-04-19 17:59:50 +020084/* Mark the stream descriptor <stream> as released. It will be freed as soon as
Amaury Denoyelle93fba322022-05-24 16:53:14 +020085 * all its buffered data are acknowledged. Does nothing if <stream> is already
86 * NULL.
Amaury Denoyellebbb18202024-01-26 14:41:04 +010087 *
88 * <final_size> corresponds to the last offset sent for this stream. If there
89 * is unsent data present, they will be remove first to guarantee that buffer
90 * is freed after receiving all acknowledges.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020091 */
Amaury Denoyellebbb18202024-01-26 14:41:04 +010092void qc_stream_desc_release(struct qc_stream_desc *stream,
93 uint64_t final_size)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020094{
Amaury Denoyelle93fba322022-05-24 16:53:14 +020095 if (!stream)
96 return;
97
Amaury Denoyellee4301da2022-04-19 17:59:50 +020098 /* A stream can be released only one time. */
99 BUG_ON(stream->release);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200100
101 stream->release = 1;
102 stream->ctx = NULL;
103
Amaury Denoyellebbb18202024-01-26 14:41:04 +0100104 if (stream->buf) {
105 struct qc_stream_buf *stream_buf = stream->buf;
106 struct buffer *buf = &stream_buf->buf;
107 const uint64_t tail_offset =
108 MAX(stream->buf_offset, stream->ack_offset) + b_data(buf);
109
110 /* final_size cannot be greater than all currently stored data. */
111 BUG_ON(final_size > tail_offset);
112
113 /* Remove unsent data from current buffer. */
114 if (final_size < tail_offset) {
115 b_sub(buf, tail_offset - final_size);
116 /* Remove buffer is all ACK already received. */
117 if (!b_data(buf))
118 qc_stream_buf_free(stream, &stream_buf);
119 }
120
121 /* A released stream does not use <stream.buf>. */
122 stream->buf = NULL;
123 }
124
Amaury Denoyellea4569202022-04-15 17:29:25 +0200125 if (LIST_ISEMPTY(&stream->buf_list)) {
126 /* if no buffer left we can free the stream. */
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200127 qc_stream_desc_free(stream, 0);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200128 }
Amaury Denoyellea4569202022-04-15 17:29:25 +0200129}
130
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200131/* Acknowledge data at <offset> of length <len> for <stream>. It is handled
132 * only if it covers a range corresponding to stream.ack_offset. After data
133 * removal, if the stream does not contains data any more and is already
134 * released, the instance stream is freed. <stream> is set to NULL to indicate
135 * this.
136 *
137 * Returns the count of byte removed from stream. Do not forget to check if
138 * <stream> is NULL after invocation.
139 */
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200140int qc_stream_desc_ack(struct qc_stream_desc **stream, size_t offset, size_t len)
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200141{
142 struct qc_stream_desc *s = *stream;
143 struct qc_stream_buf *stream_buf;
144 struct buffer *buf;
145 size_t diff;
146
147 if (offset + len <= s->ack_offset || offset > s->ack_offset)
148 return 0;
149
150 /* There must be at least a buffer or we must not report an ACK. */
151 BUG_ON(LIST_ISEMPTY(&s->buf_list));
152
153 /* get oldest buffer from buf_list */
154 stream_buf = LIST_NEXT(&s->buf_list, struct qc_stream_buf *, list);
155 buf = &stream_buf->buf;
156
157 diff = offset + len - s->ack_offset;
158 s->ack_offset += diff;
159 b_del(buf, diff);
160
Amaury Denoyelle574dae22024-01-26 14:30:16 +0100161 /* Free oldest buffer if all data acknowledged. */
162 if (!b_data(buf)) {
163 qc_stream_buf_free(s, &stream_buf);
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200164
Amaury Denoyelle574dae22024-01-26 14:30:16 +0100165 /* Free stream instance if already released and no buffers left. */
166 if (s->release && LIST_ISEMPTY(&s->buf_list)) {
167 qc_stream_desc_free(s, 0);
168 *stream = NULL;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200169 }
170 }
171
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200172 return diff;
173}
174
Amaury Denoyellea4569202022-04-15 17:29:25 +0200175/* Free the stream descriptor <stream> content. This function should be used
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200176 * when all its data have been acknowledged or on full connection closing if <closing>
177 * boolean is set to 1. It must only be called after the stream is released.
Amaury Denoyellea4569202022-04-15 17:29:25 +0200178 */
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200179void qc_stream_desc_free(struct qc_stream_desc *stream, int closing)
Amaury Denoyellea4569202022-04-15 17:29:25 +0200180{
181 struct qc_stream_buf *buf, *buf_back;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200182 struct quic_conn *qc = stream->qc;
Amaury Denoyellea4569202022-04-15 17:29:25 +0200183 struct eb64_node *frm_node;
184 unsigned int free_count = 0;
185
186 /* This function only deals with released streams. */
187 BUG_ON(!stream->release);
188
189 /* free remaining stream buffers */
190 list_for_each_entry_safe(buf, buf_back, &stream->buf_list, list) {
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200191 if (!(b_data(&buf->buf)) || closing) {
Amaury Denoyellea4569202022-04-15 17:29:25 +0200192 b_free(&buf->buf);
193 LIST_DELETE(&buf->list);
Willy Tarreaua4482272022-05-27 09:11:02 +0200194 pool_free(pool_head_quic_stream_buf, buf);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200195
196 ++free_count;
197 }
198 }
199
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200200 if (free_count) {
Amaury Denoyellea4569202022-04-15 17:29:25 +0200201 offer_buffers(NULL, free_count);
202
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200203 qc->stream_buf_count -= free_count;
204 if (qc->mux_state == QC_MUX_READY) {
205 /* notify MUX about available buffers. */
206 if (qc->qcc->flags & QC_CF_CONN_FULL) {
207 qc->qcc->flags &= ~QC_CF_CONN_FULL;
208 tasklet_wakeup(qc->qcc->wait_event.tasklet);
209 }
210 }
211 }
212
Amaury Denoyellea4569202022-04-15 17:29:25 +0200213 /* qc_stream_desc might be freed before having received all its ACKs.
214 * This is the case if some frames were retransmitted.
215 */
216 frm_node = eb64_first(&stream->acked_frms);
217 while (frm_node) {
Amaury Denoyelled5f03cd2023-04-24 15:32:23 +0200218 struct qf_stream *strm_frm;
Amaury Denoyellea4569202022-04-15 17:29:25 +0200219 struct quic_frame *frm;
220
Amaury Denoyelled5f03cd2023-04-24 15:32:23 +0200221 strm_frm = eb64_entry(frm_node, struct qf_stream, offset);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200222
223 frm_node = eb64_next(frm_node);
Amaury Denoyelled5f03cd2023-04-24 15:32:23 +0200224 eb64_delete(&strm_frm->offset);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200225
Amaury Denoyelled5f03cd2023-04-24 15:32:23 +0200226 frm = container_of(strm_frm, struct quic_frame, stream);
Frédéric Lécailleda342552022-04-25 10:28:49 +0200227 qc_release_frm(qc, frm);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200228 }
229
Frédéric Lécaille7e3f7c42022-09-09 18:05:45 +0200230 if (stream->by_id.key != (uint64_t)-1)
231 eb64_delete(&stream->by_id);
Willy Tarreaua4482272022-05-27 09:11:02 +0200232 pool_free(pool_head_quic_stream_desc, stream);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200233}
234
235/* Return the current buffer of <stream>. May be NULL if not allocated. */
236struct buffer *qc_stream_buf_get(struct qc_stream_desc *stream)
237{
238 if (!stream->buf)
239 return NULL;
240
241 return &stream->buf->buf;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200242}
243
Amaury Denoyelle6c501ed2023-05-12 16:19:32 +0200244/* Returns the count of available buffer left for <qc>. */
Amaury Denoyelle1b2dba52022-04-15 17:32:04 +0200245static int qc_stream_buf_avail(struct quic_conn *qc)
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200246{
Amaury Denoyelle6c501ed2023-05-12 16:19:32 +0200247 BUG_ON(qc->stream_buf_count > global.tune.quic_streams_buf);
248 return global.tune.quic_streams_buf - qc->stream_buf_count;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200249}
250
251/* Allocate a new current buffer for <stream>. The buffer limit count for the
252 * connection is checked first. This function is not allowed if current buffer
253 * is not NULL prior to this call. The new buffer represents stream payload at
254 * offset <offset>.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200255 *
Amaury Denoyelle6c501ed2023-05-12 16:19:32 +0200256 * Returns the buffer or NULL on error. Caller may check <avail> to ensure if
257 * the connection buffer limit was reached or a fatal error was encountered.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200258 */
Amaury Denoyellea4569202022-04-15 17:29:25 +0200259struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream,
Amaury Denoyelle6c501ed2023-05-12 16:19:32 +0200260 uint64_t offset, int *avail)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200261{
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200262 struct quic_conn *qc = stream->qc;
263
Amaury Denoyellea4569202022-04-15 17:29:25 +0200264 /* current buffer must be released first before allocate a new one. */
265 BUG_ON(stream->buf);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200266
Amaury Denoyelle6c501ed2023-05-12 16:19:32 +0200267 *avail = qc_stream_buf_avail(qc);
268 if (!*avail)
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200269 return NULL;
270
Amaury Denoyellea4569202022-04-15 17:29:25 +0200271 stream->buf_offset = offset;
Willy Tarreaua4482272022-05-27 09:11:02 +0200272 stream->buf = pool_alloc(pool_head_quic_stream_buf);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200273 if (!stream->buf)
274 return NULL;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200275
Amaury Denoyelle50fe0062023-05-11 16:52:48 +0200276 ++qc->stream_buf_count;
277
Amaury Denoyellea4569202022-04-15 17:29:25 +0200278 stream->buf->buf = BUF_NULL;
279 LIST_APPEND(&stream->buf_list, &stream->buf->list);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200280
Amaury Denoyellea4569202022-04-15 17:29:25 +0200281 return &stream->buf->buf;
282}
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200283
Amaury Denoyellea4569202022-04-15 17:29:25 +0200284/* Release the current buffer of <stream>. It will be kept internally by
285 * the <stream>. The current buffer cannot be NULL.
286 */
287void qc_stream_buf_release(struct qc_stream_desc *stream)
288{
289 /* current buffer already released */
290 BUG_ON(!stream->buf);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200291
Amaury Denoyellea4569202022-04-15 17:29:25 +0200292 stream->buf = NULL;
293 stream->buf_offset = 0;
294}