]> git.ipfire.org Git - thirdparty/openssl.git/blame - ssl/quic/quic_txpim.c
QUIC FIFD
[thirdparty/openssl.git] / ssl / quic / quic_txpim.c
CommitLineData
d77aea59
HL
1/*
2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include "internal/quic_txpim.h"
11#include <stdlib.h>
12
13typedef struct quic_txpim_pkt_ex_st QUIC_TXPIM_PKT_EX;
14
15struct quic_txpim_pkt_ex_st {
16 QUIC_TXPIM_PKT public;
17 QUIC_TXPIM_PKT_EX *prev, *next;
18 QUIC_TXPIM_CHUNK *chunks;
19 size_t num_chunks, alloc_chunks;
20 unsigned int chunks_need_sort : 1;
21};
22
23typedef struct quic_txpim_pkt_ex_list {
24 QUIC_TXPIM_PKT_EX *head, *tail;
25} QUIC_TXPIM_PKT_EX_LIST;
26
27struct quic_txpim_st {
28 QUIC_TXPIM_PKT_EX_LIST free_list;
29 size_t in_use;
30};
31
32#define MAX_ALLOC_CHUNKS 512
33
34QUIC_TXPIM *ossl_quic_txpim_new(void)
35{
36 QUIC_TXPIM *txpim = OPENSSL_zalloc(sizeof(*txpim));
37 if (txpim == NULL)
38 return NULL;
39
40 return txpim;
41}
42
43static void free_list(QUIC_TXPIM_PKT_EX_LIST *l)
44{
45 QUIC_TXPIM_PKT_EX *n, *nnext;
46
47 for (n = l->head; n != NULL; n = nnext) {
48 nnext = n->next;
49
50 OPENSSL_free(n->chunks);
51 OPENSSL_free(n);
52 }
53
54 l->head = l->tail = NULL;
55}
56
57void ossl_quic_txpim_free(QUIC_TXPIM *txpim)
58{
59 if (txpim == NULL)
60 return;
61
62 assert(txpim->in_use == 0);
63 free_list(&txpim->free_list);
64 OPENSSL_free(txpim);
65}
66
67static void list_remove(QUIC_TXPIM_PKT_EX_LIST *l, QUIC_TXPIM_PKT_EX *n)
68{
69 if (l->head == n)
70 l->head = n->next;
71 if (l->tail == n)
72 l->tail = n->prev;
73 if (n->prev != NULL)
74 n->prev->next = n->next;
75 if (n->next != NULL)
76 n->next->prev = n->prev;
77 n->prev = n->next = NULL;
78}
79
80static void list_insert_tail(QUIC_TXPIM_PKT_EX_LIST *l, QUIC_TXPIM_PKT_EX *n)
81{
82 n->prev = l->tail;
83 n->next = NULL;
84 l->tail = n;
85 if (n->prev != NULL)
86 n->prev->next = n;
87 if (l->head == NULL)
88 l->head = n;
89}
90
91static QUIC_TXPIM_PKT_EX *txpim_get_free(QUIC_TXPIM *txpim)
92{
93 QUIC_TXPIM_PKT_EX *ex = txpim->free_list.head;
94
95 if (ex != NULL)
96 return ex;
97
98 ex = OPENSSL_zalloc(sizeof(*ex));
99 if (ex == NULL)
100 return NULL;
101
102 list_insert_tail(&txpim->free_list, ex);
103 return ex;
104}
105
106static void txpim_clear(QUIC_TXPIM_PKT_EX *ex)
107{
108 memset(&ex->public.ackm_pkt, 0, sizeof(ex->public.ackm_pkt));
109 ossl_quic_txpim_pkt_clear_chunks(&ex->public);
110 ex->public.retx_head = NULL;
111 ex->public.fifd = NULL;
112 ex->public.had_handshake_done_frame = 0;
113 ex->public.had_max_data_frame = 0;
0ede517c
HL
114 ex->public.had_max_streams_bidi_frame = 0;
115 ex->public.had_max_streams_uni_frame = 0;
d77aea59
HL
116 ex->public.had_ack_frame = 0;
117}
118
119QUIC_TXPIM_PKT *ossl_quic_txpim_pkt_alloc(QUIC_TXPIM *txpim)
120{
121 QUIC_TXPIM_PKT_EX *ex = txpim_get_free(txpim);
122
123 if (ex == NULL)
124 return NULL;
125
126 txpim_clear(ex);
127 list_remove(&txpim->free_list, ex);
128 ++txpim->in_use;
129 return &ex->public;
130}
131
132void ossl_quic_txpim_pkt_release(QUIC_TXPIM *txpim, QUIC_TXPIM_PKT *fpkt)
133{
134 QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
135
136 assert(txpim->in_use > 0);
137 --txpim->in_use;
138 list_insert_tail(&txpim->free_list, ex);
139}
140
141void ossl_quic_txpim_pkt_add_cfq_item(QUIC_TXPIM_PKT *fpkt,
142 QUIC_CFQ_ITEM *item)
143{
144 item->pkt_next = fpkt->retx_head;
145 item->pkt_prev = NULL;
146 fpkt->retx_head = item;
147}
148
149void ossl_quic_txpim_pkt_clear_chunks(QUIC_TXPIM_PKT *fpkt)
150{
151 QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
152
153 ex->num_chunks = 0;
154}
155
156int ossl_quic_txpim_pkt_append_chunk(QUIC_TXPIM_PKT *fpkt,
157 const QUIC_TXPIM_CHUNK *chunk)
158{
159 QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
160 QUIC_TXPIM_CHUNK *new_chunk;
161 size_t new_alloc_chunks = ex->alloc_chunks;
162
163 if (ex->num_chunks == ex->alloc_chunks) {
164 new_alloc_chunks = (ex->alloc_chunks == 0) ? 4 : ex->alloc_chunks * 8 / 5;
165 if (new_alloc_chunks > MAX_ALLOC_CHUNKS)
166 new_alloc_chunks = MAX_ALLOC_CHUNKS;
167 if (ex->num_chunks == new_alloc_chunks)
168 return 0;
169
170 new_chunk = OPENSSL_realloc(ex->chunks,
171 new_alloc_chunks * sizeof(QUIC_TXPIM_CHUNK));
172 if (new_chunk == NULL)
173 return 0;
174
175 ex->chunks = new_chunk;
176 ex->alloc_chunks = new_alloc_chunks;
177 }
178
179 ex->chunks[ex->num_chunks++] = *chunk;
180 ex->chunks_need_sort = 1;
181 return 1;
182}
183
184static int compare(const void *a, const void *b)
185{
186 const QUIC_TXPIM_CHUNK *ac = a, *bc = b;
187
188 if (ac->stream_id < bc->stream_id)
189 return -1;
190 else if (ac->stream_id > bc->stream_id)
191 return 1;
192
193 if (ac->start < bc->start)
194 return -1;
195 else if (ac->start > bc->start)
196 return 1;
197
198 return 0;
199}
200
201const QUIC_TXPIM_CHUNK *ossl_quic_txpim_pkt_get_chunks(QUIC_TXPIM_PKT *fpkt)
202{
203 QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
204
205 if (ex->chunks_need_sort) {
0ede517c
HL
206 /*
207 * List of chunks will generally be very small so there is no issue
208 * simply sorting here.
209 */
d77aea59
HL
210 qsort(ex->chunks, ex->num_chunks, sizeof(QUIC_TXPIM_CHUNK), compare);
211 ex->chunks_need_sort = 0;
212 }
213
214 return ex->chunks;
215}
216
217size_t ossl_quic_txpim_pkt_get_num_chunks(QUIC_TXPIM_PKT *fpkt)
218{
219 QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
220
221 return ex->num_chunks;
222}
0ede517c
HL
223
224size_t ossl_quic_txpim_get_in_use(QUIC_TXPIM *txpim)
225{
226 return txpim->in_use;
227}