blob: abd977c5bf67e39f709da79095e5f3df4f47bd1b [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
Willy Tarreaua4482272022-05-27 09:11:02 +020012DECLARE_STATIC_POOL(pool_head_quic_stream_desc, "qc_stream_desc",
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020013 sizeof(struct qc_stream_desc));
Willy Tarreaua4482272022-05-27 09:11:02 +020014DECLARE_STATIC_POOL(pool_head_quic_stream_buf, "qc_stream_buf",
Amaury Denoyellea4569202022-04-15 17:29:25 +020015 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 */
Frédéric Lécaille664741e2022-05-02 18:46:58 +020023struct qc_stream_desc *qc_stream_desc_new(uint64_t id, enum qcs_type type, void *ctx,
Amaury Denoyellee4301da2022-04-19 17:59:50 +020024 struct quic_conn *qc)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020025{
26 struct qc_stream_desc *stream;
27
Willy Tarreaua4482272022-05-27 09:11:02 +020028 stream = pool_alloc(pool_head_quic_stream_desc);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020029 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);
Frédéric Lécaille664741e2022-05-02 18:46:58 +020034 qc->rx.strms[type].nb_streams++;
Amaury Denoyelleb22c0462022-04-21 11:00:41 +020035 stream->qc = qc;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020036
Amaury Denoyellea4569202022-04-15 17:29:25 +020037 stream->buf = NULL;
38 LIST_INIT(&stream->buf_list);
39 stream->buf_offset = 0;
40
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020041 stream->acked_frms = EB_ROOT;
42 stream->ack_offset = 0;
43 stream->release = 0;
44 stream->ctx = ctx;
45
46 return stream;
47}
48
Amaury Denoyellee4301da2022-04-19 17:59:50 +020049/* Mark the stream descriptor <stream> as released. It will be freed as soon as
Amaury Denoyelle93fba322022-05-24 16:53:14 +020050 * all its buffered data are acknowledged. Does nothing if <stream> is already
51 * NULL.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020052 */
Amaury Denoyellee4301da2022-04-19 17:59:50 +020053void qc_stream_desc_release(struct qc_stream_desc *stream)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020054{
Amaury Denoyelle93fba322022-05-24 16:53:14 +020055 if (!stream)
56 return;
57
Amaury Denoyellee4301da2022-04-19 17:59:50 +020058 /* A stream can be released only one time. */
59 BUG_ON(stream->release);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +020060
61 stream->release = 1;
62 stream->ctx = NULL;
63
Amaury Denoyellea4569202022-04-15 17:29:25 +020064 if (LIST_ISEMPTY(&stream->buf_list)) {
65 /* if no buffer left we can free the stream. */
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +020066 qc_stream_desc_free(stream, 0);
Amaury Denoyellea4569202022-04-15 17:29:25 +020067 }
68 else {
69 /* A released stream does not use <stream.buf>. */
70 stream->buf = NULL;
71 }
72}
73
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +020074/* Acknowledge data at <offset> of length <len> for <stream>. It is handled
75 * only if it covers a range corresponding to stream.ack_offset. After data
76 * removal, if the stream does not contains data any more and is already
77 * released, the instance stream is freed. <stream> is set to NULL to indicate
78 * this.
79 *
80 * Returns the count of byte removed from stream. Do not forget to check if
81 * <stream> is NULL after invocation.
82 */
Amaury Denoyelled2f80a22022-04-15 17:30:49 +020083int qc_stream_desc_ack(struct qc_stream_desc **stream, size_t offset, size_t len)
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +020084{
85 struct qc_stream_desc *s = *stream;
86 struct qc_stream_buf *stream_buf;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +020087 struct quic_conn *qc = s->qc;
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +020088 struct buffer *buf;
89 size_t diff;
90
91 if (offset + len <= s->ack_offset || offset > s->ack_offset)
92 return 0;
93
94 /* There must be at least a buffer or we must not report an ACK. */
95 BUG_ON(LIST_ISEMPTY(&s->buf_list));
96
97 /* get oldest buffer from buf_list */
98 stream_buf = LIST_NEXT(&s->buf_list, struct qc_stream_buf *, list);
99 buf = &stream_buf->buf;
100
101 diff = offset + len - s->ack_offset;
102 s->ack_offset += diff;
103 b_del(buf, diff);
104
105 /* nothing more to do if buf still not empty. */
106 if (b_data(buf))
107 return diff;
108
109 /* buf is empty and can now be freed. Do not forget to reset current
110 * buf ptr if we were working on it.
111 */
112 LIST_DELETE(&stream_buf->list);
113 if (stream_buf == s->buf) {
114 /* current buf must always be last entry in buflist */
115 BUG_ON(!LIST_ISEMPTY(&s->buf_list));
116 s->buf = NULL;
117 }
118
119 b_free(buf);
Willy Tarreaua4482272022-05-27 09:11:02 +0200120 pool_free(pool_head_quic_stream_buf, stream_buf);
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200121 offer_buffers(NULL, 1);
122
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200123 /* notify MUX about available buffers. */
124 --qc->stream_buf_count;
125 if (qc->mux_state == QC_MUX_READY) {
126 if (qc->qcc->flags & QC_CF_CONN_FULL) {
127 qc->qcc->flags &= ~QC_CF_CONN_FULL;
128 tasklet_wakeup(qc->qcc->wait_event.tasklet);
129 }
130 }
131
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200132 /* Free stream instance if already released and no buffers left. */
133 if (s->release && LIST_ISEMPTY(&s->buf_list)) {
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200134 qc_stream_desc_free(s, 0);
Amaury Denoyelle1b81dda2022-04-21 09:32:53 +0200135 *stream = NULL;
136 }
137
138 return diff;
139}
140
Amaury Denoyellea4569202022-04-15 17:29:25 +0200141/* Free the stream descriptor <stream> content. This function should be used
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200142 * when all its data have been acknowledged or on full connection closing if <closing>
143 * boolean is set to 1. It must only be called after the stream is released.
Amaury Denoyellea4569202022-04-15 17:29:25 +0200144 */
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200145void qc_stream_desc_free(struct qc_stream_desc *stream, int closing)
Amaury Denoyellea4569202022-04-15 17:29:25 +0200146{
147 struct qc_stream_buf *buf, *buf_back;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200148 struct quic_conn *qc = stream->qc;
Amaury Denoyellea4569202022-04-15 17:29:25 +0200149 struct eb64_node *frm_node;
150 unsigned int free_count = 0;
151
152 /* This function only deals with released streams. */
153 BUG_ON(!stream->release);
154
155 /* free remaining stream buffers */
156 list_for_each_entry_safe(buf, buf_back, &stream->buf_list, list) {
Frédéric Lécailleea4a5cb2022-08-20 18:59:36 +0200157 if (!(b_data(&buf->buf)) || closing) {
Amaury Denoyellea4569202022-04-15 17:29:25 +0200158 b_free(&buf->buf);
159 LIST_DELETE(&buf->list);
Willy Tarreaua4482272022-05-27 09:11:02 +0200160 pool_free(pool_head_quic_stream_buf, buf);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200161
162 ++free_count;
163 }
164 }
165
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200166 if (free_count) {
Amaury Denoyellea4569202022-04-15 17:29:25 +0200167 offer_buffers(NULL, free_count);
168
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200169 qc->stream_buf_count -= free_count;
170 if (qc->mux_state == QC_MUX_READY) {
171 /* notify MUX about available buffers. */
172 if (qc->qcc->flags & QC_CF_CONN_FULL) {
173 qc->qcc->flags &= ~QC_CF_CONN_FULL;
174 tasklet_wakeup(qc->qcc->wait_event.tasklet);
175 }
176 }
177 }
178
Amaury Denoyellea4569202022-04-15 17:29:25 +0200179 /* qc_stream_desc might be freed before having received all its ACKs.
180 * This is the case if some frames were retransmitted.
181 */
182 frm_node = eb64_first(&stream->acked_frms);
183 while (frm_node) {
184 struct quic_stream *strm;
185 struct quic_frame *frm;
186
Frédéric Lécaillea54e49d2022-05-10 15:15:24 +0200187 strm = eb64_entry(frm_node, struct quic_stream, offset);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200188
189 frm_node = eb64_next(frm_node);
190 eb64_delete(&strm->offset);
191
192 frm = container_of(strm, struct quic_frame, stream);
Frédéric Lécailleda342552022-04-25 10:28:49 +0200193 qc_release_frm(qc, frm);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200194 }
195
196 eb64_delete(&stream->by_id);
Willy Tarreaua4482272022-05-27 09:11:02 +0200197 pool_free(pool_head_quic_stream_desc, stream);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200198}
199
200/* Return the current buffer of <stream>. May be NULL if not allocated. */
201struct buffer *qc_stream_buf_get(struct qc_stream_desc *stream)
202{
203 if (!stream->buf)
204 return NULL;
205
206 return &stream->buf->buf;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200207}
208
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200209/* Check if a new stream buffer can be allocated for the connection <qc>.
210 * Returns a boolean.
211 */
Amaury Denoyelle1b2dba52022-04-15 17:32:04 +0200212static int qc_stream_buf_avail(struct quic_conn *qc)
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200213{
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200214 return qc->stream_buf_count < global.tune.quic_streams_buf;
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200215}
216
217/* Allocate a new current buffer for <stream>. The buffer limit count for the
218 * connection is checked first. This function is not allowed if current buffer
219 * is not NULL prior to this call. The new buffer represents stream payload at
220 * offset <offset>.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200221 *
Amaury Denoyellea4569202022-04-15 17:29:25 +0200222 * Returns the buffer or NULL.
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200223 */
Amaury Denoyellea4569202022-04-15 17:29:25 +0200224struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream,
225 uint64_t offset)
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200226{
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200227 struct quic_conn *qc = stream->qc;
228
Amaury Denoyellea4569202022-04-15 17:29:25 +0200229 /* current buffer must be released first before allocate a new one. */
230 BUG_ON(stream->buf);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200231
Amaury Denoyelled2f80a22022-04-15 17:30:49 +0200232 if (!qc_stream_buf_avail(qc))
233 return NULL;
234
235 ++qc->stream_buf_count;
236
Amaury Denoyellea4569202022-04-15 17:29:25 +0200237 stream->buf_offset = offset;
Willy Tarreaua4482272022-05-27 09:11:02 +0200238 stream->buf = pool_alloc(pool_head_quic_stream_buf);
Amaury Denoyellea4569202022-04-15 17:29:25 +0200239 if (!stream->buf)
240 return NULL;
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200241
Amaury Denoyellea4569202022-04-15 17:29:25 +0200242 stream->buf->buf = BUF_NULL;
243 LIST_APPEND(&stream->buf_list, &stream->buf->list);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200244
Amaury Denoyellea4569202022-04-15 17:29:25 +0200245 return &stream->buf->buf;
246}
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200247
Amaury Denoyellea4569202022-04-15 17:29:25 +0200248/* Release the current buffer of <stream>. It will be kept internally by
249 * the <stream>. The current buffer cannot be NULL.
250 */
251void qc_stream_buf_release(struct qc_stream_desc *stream)
252{
253 /* current buffer already released */
254 BUG_ON(!stream->buf);
Amaury Denoyelle0cc02a32022-04-19 17:21:11 +0200255
Amaury Denoyellea4569202022-04-15 17:29:25 +0200256 stream->buf = NULL;
257 stream->buf_offset = 0;
258}