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