2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
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
10 #include "internal/quic_txpim.h"
13 typedef struct quic_txpim_pkt_ex_st QUIC_TXPIM_PKT_EX
;
15 struct 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;
23 typedef struct quic_txpim_pkt_ex_list
{
24 QUIC_TXPIM_PKT_EX
*head
, *tail
;
25 } QUIC_TXPIM_PKT_EX_LIST
;
27 struct quic_txpim_st
{
28 QUIC_TXPIM_PKT_EX_LIST free_list
;
32 #define MAX_ALLOC_CHUNKS 512
34 QUIC_TXPIM
*ossl_quic_txpim_new(void)
36 QUIC_TXPIM
*txpim
= OPENSSL_zalloc(sizeof(*txpim
));
44 static void free_list(QUIC_TXPIM_PKT_EX_LIST
*l
)
46 QUIC_TXPIM_PKT_EX
*n
, *nnext
;
48 for (n
= l
->head
; n
!= NULL
; n
= nnext
) {
51 OPENSSL_free(n
->chunks
);
55 l
->head
= l
->tail
= NULL
;
58 void ossl_quic_txpim_free(QUIC_TXPIM
*txpim
)
63 assert(txpim
->in_use
== 0);
64 free_list(&txpim
->free_list
);
68 static void list_remove(QUIC_TXPIM_PKT_EX_LIST
*l
, QUIC_TXPIM_PKT_EX
*n
)
75 n
->prev
->next
= n
->next
;
77 n
->next
->prev
= n
->prev
;
78 n
->prev
= n
->next
= NULL
;
81 static void list_insert_tail(QUIC_TXPIM_PKT_EX_LIST
*l
, QUIC_TXPIM_PKT_EX
*n
)
92 static QUIC_TXPIM_PKT_EX
*txpim_get_free(QUIC_TXPIM
*txpim
)
94 QUIC_TXPIM_PKT_EX
*ex
= txpim
->free_list
.head
;
99 ex
= OPENSSL_zalloc(sizeof(*ex
));
103 list_insert_tail(&txpim
->free_list
, ex
);
107 static void txpim_clear(QUIC_TXPIM_PKT_EX
*ex
)
109 memset(&ex
->public.ackm_pkt
, 0, sizeof(ex
->public.ackm_pkt
));
110 ossl_quic_txpim_pkt_clear_chunks(&ex
->public);
111 ex
->public.retx_head
= NULL
;
112 ex
->public.fifd
= NULL
;
113 ex
->public.had_handshake_done_frame
= 0;
114 ex
->public.had_max_data_frame
= 0;
115 ex
->public.had_max_streams_bidi_frame
= 0;
116 ex
->public.had_max_streams_uni_frame
= 0;
117 ex
->public.had_ack_frame
= 0;
118 ex
->public.had_conn_close
= 0;
121 QUIC_TXPIM_PKT
*ossl_quic_txpim_pkt_alloc(QUIC_TXPIM
*txpim
)
123 QUIC_TXPIM_PKT_EX
*ex
= txpim_get_free(txpim
);
129 list_remove(&txpim
->free_list
, ex
);
134 void ossl_quic_txpim_pkt_release(QUIC_TXPIM
*txpim
, QUIC_TXPIM_PKT
*fpkt
)
136 QUIC_TXPIM_PKT_EX
*ex
= (QUIC_TXPIM_PKT_EX
*)fpkt
;
138 assert(txpim
->in_use
> 0);
140 list_insert_tail(&txpim
->free_list
, ex
);
143 void ossl_quic_txpim_pkt_add_cfq_item(QUIC_TXPIM_PKT
*fpkt
,
146 item
->pkt_next
= fpkt
->retx_head
;
147 item
->pkt_prev
= NULL
;
148 fpkt
->retx_head
= item
;
151 void ossl_quic_txpim_pkt_clear_chunks(QUIC_TXPIM_PKT
*fpkt
)
153 QUIC_TXPIM_PKT_EX
*ex
= (QUIC_TXPIM_PKT_EX
*)fpkt
;
158 int ossl_quic_txpim_pkt_append_chunk(QUIC_TXPIM_PKT
*fpkt
,
159 const QUIC_TXPIM_CHUNK
*chunk
)
161 QUIC_TXPIM_PKT_EX
*ex
= (QUIC_TXPIM_PKT_EX
*)fpkt
;
162 QUIC_TXPIM_CHUNK
*new_chunk
;
163 size_t new_alloc_chunks
= ex
->alloc_chunks
;
165 if (ex
->num_chunks
== ex
->alloc_chunks
) {
166 new_alloc_chunks
= (ex
->alloc_chunks
== 0) ? 4 : ex
->alloc_chunks
* 8 / 5;
167 if (new_alloc_chunks
> MAX_ALLOC_CHUNKS
)
168 new_alloc_chunks
= MAX_ALLOC_CHUNKS
;
169 if (ex
->num_chunks
== new_alloc_chunks
)
172 new_chunk
= OPENSSL_realloc(ex
->chunks
,
173 new_alloc_chunks
* sizeof(QUIC_TXPIM_CHUNK
));
174 if (new_chunk
== NULL
)
177 ex
->chunks
= new_chunk
;
178 ex
->alloc_chunks
= new_alloc_chunks
;
181 ex
->chunks
[ex
->num_chunks
++] = *chunk
;
182 ex
->chunks_need_sort
= 1;
186 static int compare(const void *a
, const void *b
)
188 const QUIC_TXPIM_CHUNK
*ac
= a
, *bc
= b
;
190 if (ac
->stream_id
< bc
->stream_id
)
192 else if (ac
->stream_id
> bc
->stream_id
)
195 if (ac
->start
< bc
->start
)
197 else if (ac
->start
> bc
->start
)
203 const QUIC_TXPIM_CHUNK
*ossl_quic_txpim_pkt_get_chunks(const QUIC_TXPIM_PKT
*fpkt
)
205 QUIC_TXPIM_PKT_EX
*ex
= (QUIC_TXPIM_PKT_EX
*)fpkt
;
207 if (ex
->chunks_need_sort
) {
209 * List of chunks will generally be very small so there is no issue
210 * simply sorting here.
212 qsort(ex
->chunks
, ex
->num_chunks
, sizeof(QUIC_TXPIM_CHUNK
), compare
);
213 ex
->chunks_need_sort
= 0;
219 size_t ossl_quic_txpim_pkt_get_num_chunks(const QUIC_TXPIM_PKT
*fpkt
)
221 QUIC_TXPIM_PKT_EX
*ex
= (QUIC_TXPIM_PKT_EX
*)fpkt
;
223 return ex
->num_chunks
;
226 size_t ossl_quic_txpim_get_in_use(const QUIC_TXPIM
*txpim
)
228 return txpim
->in_use
;