blob: 692f4d5837121f645fd2cf1e3689a34006ec54fb [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
20/* Allocate a new stream descriptor with id <id>. The caller is responsible to
Frédéric Lécaille7e3f7c42022-09-09 18:05:45 +020021 * store the stream in the appropriate tree. -1 special value must be used for
22 * a CRYPTO data stream, the type being ignored.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020023 *
24 * Returns the newly allocated instance on success or else NULL.
25 */
Frédéric Lécaille664741e2022-05-02 18:46:58 +020026struct qc_stream_desc *qc_stream_desc_new(uint64_t id, enum qcs_type type, void *ctx,
Amaury Denoyellee4301da2022-04-19 17:59:50 +020027 struct quic_conn *qc)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020028{
29 struct qc_stream_desc *stream;
30
Willy Tarreaua4482272022-05-27 09:11:02 +020031 stream = pool_alloc(pool_head_quic_stream_desc);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020032 if (!stream)
33 return NULL;
34
Frédéric Lécaille7e3f7c42022-09-09 18:05:45 +020035 if (id == (uint64_t)-1) {
36 stream->by_id.key = (uint64_t)-1;
37 }
38 else {
39 stream->by_id.key = id;
40 eb64_insert(&qc->streams_by_id, &stream->by_id);
41 qc->rx.strms[type].nb_streams++;
42 }
Amaury Denoyelleb22c0462022-04-21 11:00:41 +020043 stream->qc = qc;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020044
Amaury Denoyellea4569202022-04-15 17:29:25 +020045 stream->buf = NULL;
46 LIST_INIT(&stream->buf_list);
47 stream->buf_offset = 0;
48
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020049 stream->acked_frms = EB_ROOT;
50 stream->ack_offset = 0;
51 stream->release = 0;
52 stream->ctx = ctx;
53
54 return stream;
55}
56
Amaury Denoyellee4301da2022-04-19 17:59:50 +020057/* Mark the stream descriptor <stream> as released. It will be freed as soon as
Amaury Denoyelle93fba322022-05-24 16:53:14 +020058 * all its buffered data are acknowledged. Does nothing if <stream> is already
59 * NULL.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020060 */
Amaury Denoyellee4301da2022-04-19 17:59:50 +020061void qc_stream_desc_release(struct qc_stream_desc *stream)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020062{
Amaury Denoyelle93fba322022-05-24 16:53:14 +020063 if (!stream)
64 return;
65
Amaury Denoyellee4301da2022-04-19 17:59:50 +020066 /* A stream can be released only one time. */
67 BUG_ON(stream->release);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020068
69 stream->release = 1;
70 stream->ctx = NULL;
71
Amaury Denoyellea4569202022-04-15 17:29:25 +020072 if (LIST_ISEMPTY(&stream->buf_list)) {
73 /* if no buffer left we can free the stream. */
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +020074 qc_stream_desc_free(stream, 0);
Amaury Denoyellea4569202022-04-15 17:29:25 +020075 }
76 else {
77 /* A released stream does not use <stream.buf>. */
78 stream->buf = NULL;
79 }
80}
81
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +020082/* Acknowledge data at <offset> of length <len> for <stream>. It is handled
83 * only if it covers a range corresponding to stream.ack_offset. After data
84 * removal, if the stream does not contains data any more and is already
85 * released, the instance stream is freed. <stream> is set to NULL to indicate
86 * this.
87 *
88 * Returns the count of byte removed from stream. Do not forget to check if
89 * <stream> is NULL after invocation.
90 */
Amaury Denoyelled2f80a22022-04-15 17:30:49 +020091int qc_stream_desc_ack(struct qc_stream_desc **stream, size_t offset, size_t len)
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +020092{
93 struct qc_stream_desc *s = *stream;
94 struct qc_stream_buf *stream_buf;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +020095 struct quic_conn *qc = s->qc;
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +020096 struct buffer *buf;
97 size_t diff;
98
99 if (offset + len <= s->ack_offset || offset > s->ack_offset)
100 return 0;
101
102 /* There must be at least a buffer or we must not report an ACK. */
103 BUG_ON(LIST_ISEMPTY(&s->buf_list));
104
105 /* get oldest buffer from buf_list */
106 stream_buf = LIST_NEXT(&s->buf_list, struct qc_stream_buf *, list);
107 buf = &stream_buf->buf;
108
109 diff = offset + len - s->ack_offset;
110 s->ack_offset += diff;
111 b_del(buf, diff);
112
113 /* nothing more to do if buf still not empty. */
114 if (b_data(buf))
115 return diff;
116
117 /* buf is empty and can now be freed. Do not forget to reset current
118 * buf ptr if we were working on it.
119 */
120 LIST_DELETE(&stream_buf->list);
121 if (stream_buf == s->buf) {
122 /* current buf must always be last entry in buflist */
123 BUG_ON(!LIST_ISEMPTY(&s->buf_list));
124 s->buf = NULL;
125 }
126
127 b_free(buf);
Willy Tarreaua4482272022-05-27 09:11:02 +0200128 pool_free(pool_head_quic_stream_buf, stream_buf);
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200129 offer_buffers(NULL, 1);
130
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200131 /* notify MUX about available buffers. */
132 --qc->stream_buf_count;
133 if (qc->mux_state == QC_MUX_READY) {
134 if (qc->qcc->flags & QC_CF_CONN_FULL) {
135 qc->qcc->flags &= ~QC_CF_CONN_FULL;
136 tasklet_wakeup(qc->qcc->wait_event.tasklet);
137 }
138 }
139
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200140 /* Free stream instance if already released and no buffers left. */
141 if (s->release && LIST_ISEMPTY(&s->buf_list)) {
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200142 qc_stream_desc_free(s, 0);
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200143 *stream = NULL;
144 }
145
146 return diff;
147}
148
Amaury Denoyellea4569202022-04-15 17:29:25 +0200149/* Free the stream descriptor <stream> content. This function should be used
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200150 * when all its data have been acknowledged or on full connection closing if <closing>
151 * boolean is set to 1. It must only be called after the stream is released.
Amaury Denoyellea4569202022-04-15 17:29:25 +0200152 */
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200153void qc_stream_desc_free(struct qc_stream_desc *stream, int closing)
Amaury Denoyellea4569202022-04-15 17:29:25 +0200154{
155 struct qc_stream_buf *buf, *buf_back;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200156 struct quic_conn *qc = stream->qc;
Amaury Denoyellea4569202022-04-15 17:29:25 +0200157 struct eb64_node *frm_node;
158 unsigned int free_count = 0;
159
160 /* This function only deals with released streams. */
161 BUG_ON(!stream->release);
162
163 /* free remaining stream buffers */
164 list_for_each_entry_safe(buf, buf_back, &stream->buf_list, list) {
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200165 if (!(b_data(&buf->buf)) || closing) {
Amaury Denoyellea4569202022-04-15 17:29:25 +0200166 b_free(&buf->buf);
167 LIST_DELETE(&buf->list);
Willy Tarreaua4482272022-05-27 09:11:02 +0200168 pool_free(pool_head_quic_stream_buf, buf);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200169
170 ++free_count;
171 }
172 }
173
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200174 if (free_count) {
Amaury Denoyellea4569202022-04-15 17:29:25 +0200175 offer_buffers(NULL, free_count);
176
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200177 qc->stream_buf_count -= free_count;
178 if (qc->mux_state == QC_MUX_READY) {
179 /* notify MUX about available buffers. */
180 if (qc->qcc->flags & QC_CF_CONN_FULL) {
181 qc->qcc->flags &= ~QC_CF_CONN_FULL;
182 tasklet_wakeup(qc->qcc->wait_event.tasklet);
183 }
184 }
185 }
186
Amaury Denoyellea4569202022-04-15 17:29:25 +0200187 /* qc_stream_desc might be freed before having received all its ACKs.
188 * This is the case if some frames were retransmitted.
189 */
190 frm_node = eb64_first(&stream->acked_frms);
191 while (frm_node) {
192 struct quic_stream *strm;
193 struct quic_frame *frm;
194
Frédéric Lécaillea54e49d2022-05-10 15:15:24 +0200195 strm = eb64_entry(frm_node, struct quic_stream, offset);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200196
197 frm_node = eb64_next(frm_node);
198 eb64_delete(&strm->offset);
199
200 frm = container_of(strm, struct quic_frame, stream);
Frédéric Lécailleda342552022-04-25 10:28:49 +0200201 qc_release_frm(qc, frm);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200202 }
203
Frédéric Lécaille7e3f7c42022-09-09 18:05:45 +0200204 if (stream->by_id.key != (uint64_t)-1)
205 eb64_delete(&stream->by_id);
Willy Tarreaua4482272022-05-27 09:11:02 +0200206 pool_free(pool_head_quic_stream_desc, stream);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200207}
208
209/* Return the current buffer of <stream>. May be NULL if not allocated. */
210struct buffer *qc_stream_buf_get(struct qc_stream_desc *stream)
211{
212 if (!stream->buf)
213 return NULL;
214
215 return &stream->buf->buf;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200216}
217
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200218/* Check if a new stream buffer can be allocated for the connection <qc>.
219 * Returns a boolean.
220 */
Amaury Denoyelle1b2dba52022-04-15 17:32:04 +0200221static int qc_stream_buf_avail(struct quic_conn *qc)
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200222{
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200223 return qc->stream_buf_count < global.tune.quic_streams_buf;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200224}
225
226/* Allocate a new current buffer for <stream>. The buffer limit count for the
227 * connection is checked first. This function is not allowed if current buffer
228 * is not NULL prior to this call. The new buffer represents stream payload at
229 * offset <offset>.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200230 *
Amaury Denoyellea4569202022-04-15 17:29:25 +0200231 * Returns the buffer or NULL.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200232 */
Amaury Denoyellea4569202022-04-15 17:29:25 +0200233struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream,
234 uint64_t offset)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200235{
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200236 struct quic_conn *qc = stream->qc;
237
Amaury Denoyellea4569202022-04-15 17:29:25 +0200238 /* current buffer must be released first before allocate a new one. */
239 BUG_ON(stream->buf);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200240
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200241 if (!qc_stream_buf_avail(qc))
242 return NULL;
243
244 ++qc->stream_buf_count;
245
Amaury Denoyellea4569202022-04-15 17:29:25 +0200246 stream->buf_offset = offset;
Willy Tarreaua4482272022-05-27 09:11:02 +0200247 stream->buf = pool_alloc(pool_head_quic_stream_buf);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200248 if (!stream->buf)
249 return NULL;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200250
Amaury Denoyellea4569202022-04-15 17:29:25 +0200251 stream->buf->buf = BUF_NULL;
252 LIST_APPEND(&stream->buf_list, &stream->buf->list);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200253
Amaury Denoyellea4569202022-04-15 17:29:25 +0200254 return &stream->buf->buf;
255}
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200256
Amaury Denoyellea4569202022-04-15 17:29:25 +0200257/* Release the current buffer of <stream>. It will be kept internally by
258 * the <stream>. The current buffer cannot be NULL.
259 */
260void qc_stream_buf_release(struct qc_stream_desc *stream)
261{
262 /* current buffer already released */
263 BUG_ON(!stream->buf);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200264
Amaury Denoyellea4569202022-04-15 17:29:25 +0200265 stream->buf = NULL;
266 stream->buf_offset = 0;
267}