Coverage Report

Created: 2025-06-13 06:58

/src/openssl32/ssl/quic/quic_txpim.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2022-2023 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
13
typedef struct quic_txpim_pkt_ex_st QUIC_TXPIM_PKT_EX;
14
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;
21
};
22
23
typedef struct quic_txpim_pkt_ex_list {
24
    QUIC_TXPIM_PKT_EX          *head, *tail;
25
} QUIC_TXPIM_PKT_EX_LIST;
26
27
struct quic_txpim_st {
28
    QUIC_TXPIM_PKT_EX_LIST  free_list;
29
    size_t                  in_use;
30
};
31
32
38.7k
#define MAX_ALLOC_CHUNKS 512
33
34
QUIC_TXPIM *ossl_quic_txpim_new(void)
35
22.0k
{
36
22.0k
    QUIC_TXPIM *txpim = OPENSSL_zalloc(sizeof(*txpim));
37
38
22.0k
    if (txpim == NULL)
39
0
        return NULL;
40
41
22.0k
    return txpim;
42
22.0k
}
43
44
static void free_list(QUIC_TXPIM_PKT_EX_LIST *l)
45
22.0k
{
46
22.0k
    QUIC_TXPIM_PKT_EX *n, *nnext;
47
48
420k
    for (n = l->head; n != NULL; n = nnext) {
49
398k
        nnext = n->next;
50
51
398k
        OPENSSL_free(n->chunks);
52
398k
        OPENSSL_free(n);
53
398k
    }
54
55
22.0k
    l->head = l->tail = NULL;
56
22.0k
}
57
58
void ossl_quic_txpim_free(QUIC_TXPIM *txpim)
59
22.0k
{
60
22.0k
    if (txpim == NULL)
61
0
        return;
62
63
22.0k
    assert(txpim->in_use == 0);
64
22.0k
    free_list(&txpim->free_list);
65
22.0k
    OPENSSL_free(txpim);
66
22.0k
}
67
68
static void list_remove(QUIC_TXPIM_PKT_EX_LIST *l, QUIC_TXPIM_PKT_EX *n)
69
23.1M
{
70
23.1M
    if (l->head == n)
71
23.1M
        l->head = n->next;
72
23.1M
    if (l->tail == n)
73
10.3M
        l->tail = n->prev;
74
23.1M
    if (n->prev != NULL)
75
0
        n->prev->next = n->next;
76
23.1M
    if (n->next != NULL)
77
12.7M
        n->next->prev = n->prev;
78
23.1M
    n->prev = n->next = NULL;
79
23.1M
}
80
81
static void list_insert_tail(QUIC_TXPIM_PKT_EX_LIST *l, QUIC_TXPIM_PKT_EX *n)
82
23.5M
{
83
23.5M
    n->prev = l->tail;
84
23.5M
    n->next = NULL;
85
23.5M
    l->tail = n;
86
23.5M
    if (n->prev != NULL)
87
13.1M
        n->prev->next = n;
88
23.5M
    if (l->head == NULL)
89
10.3M
        l->head = n;
90
23.5M
}
91
92
static QUIC_TXPIM_PKT_EX *txpim_get_free(QUIC_TXPIM *txpim)
93
23.1M
{
94
23.1M
    QUIC_TXPIM_PKT_EX *ex = txpim->free_list.head;
95
96
23.1M
    if (ex != NULL)
97
22.7M
        return ex;
98
99
398k
    ex = OPENSSL_zalloc(sizeof(*ex));
100
398k
    if (ex == NULL)
101
0
        return NULL;
102
103
398k
    list_insert_tail(&txpim->free_list, ex);
104
398k
    return ex;
105
398k
}
106
107
static void txpim_clear(QUIC_TXPIM_PKT_EX *ex)
108
23.1M
{
109
23.1M
    memset(&ex->public.ackm_pkt, 0, sizeof(ex->public.ackm_pkt));
110
23.1M
    ossl_quic_txpim_pkt_clear_chunks(&ex->public);
111
23.1M
    ex->public.retx_head                   = NULL;
112
23.1M
    ex->public.fifd                        = NULL;
113
23.1M
    ex->public.had_handshake_done_frame    = 0;
114
23.1M
    ex->public.had_max_data_frame          = 0;
115
23.1M
    ex->public.had_max_streams_bidi_frame  = 0;
116
23.1M
    ex->public.had_max_streams_uni_frame   = 0;
117
23.1M
    ex->public.had_ack_frame               = 0;
118
23.1M
    ex->public.had_conn_close              = 0;
119
23.1M
}
120
121
QUIC_TXPIM_PKT *ossl_quic_txpim_pkt_alloc(QUIC_TXPIM *txpim)
122
23.1M
{
123
23.1M
    QUIC_TXPIM_PKT_EX *ex = txpim_get_free(txpim);
124
125
23.1M
    if (ex == NULL)
126
0
        return NULL;
127
128
23.1M
    txpim_clear(ex);
129
23.1M
    list_remove(&txpim->free_list, ex);
130
23.1M
    ++txpim->in_use;
131
23.1M
    return &ex->public;
132
23.1M
}
133
134
void ossl_quic_txpim_pkt_release(QUIC_TXPIM *txpim, QUIC_TXPIM_PKT *fpkt)
135
23.1M
{
136
23.1M
    QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
137
138
23.1M
    assert(txpim->in_use > 0);
139
23.1M
    --txpim->in_use;
140
23.1M
    list_insert_tail(&txpim->free_list, ex);
141
23.1M
}
142
143
void ossl_quic_txpim_pkt_add_cfq_item(QUIC_TXPIM_PKT *fpkt,
144
                                      QUIC_CFQ_ITEM *item)
145
107k
{
146
107k
    item->pkt_next = fpkt->retx_head;
147
107k
    item->pkt_prev = NULL;
148
107k
    fpkt->retx_head = item;
149
107k
}
150
151
void ossl_quic_txpim_pkt_clear_chunks(QUIC_TXPIM_PKT *fpkt)
152
23.1M
{
153
23.1M
    QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
154
155
23.1M
    ex->num_chunks = 0;
156
23.1M
}
157
158
int ossl_quic_txpim_pkt_append_chunk(QUIC_TXPIM_PKT *fpkt,
159
                                     const QUIC_TXPIM_CHUNK *chunk)
160
46.8k
{
161
46.8k
    QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
162
46.8k
    QUIC_TXPIM_CHUNK *new_chunk;
163
46.8k
    size_t new_alloc_chunks = ex->alloc_chunks;
164
165
46.8k
    if (ex->num_chunks == ex->alloc_chunks) {
166
38.7k
        new_alloc_chunks = (ex->alloc_chunks == 0) ? 4 : ex->alloc_chunks * 8 / 5;
167
38.7k
        if (new_alloc_chunks > MAX_ALLOC_CHUNKS)
168
0
            new_alloc_chunks = MAX_ALLOC_CHUNKS;
169
38.7k
        if (ex->num_chunks == new_alloc_chunks)
170
0
            return 0;
171
172
38.7k
        new_chunk = OPENSSL_realloc(ex->chunks,
173
38.7k
                                    new_alloc_chunks * sizeof(QUIC_TXPIM_CHUNK));
174
38.7k
        if (new_chunk == NULL)
175
0
            return 0;
176
177
38.7k
        ex->chunks          = new_chunk;
178
38.7k
        ex->alloc_chunks    = new_alloc_chunks;
179
38.7k
    }
180
181
46.8k
    ex->chunks[ex->num_chunks++]    = *chunk;
182
46.8k
    ex->chunks_need_sort            = 1;
183
46.8k
    return 1;
184
46.8k
}
185
186
static int compare(const void *a, const void *b)
187
1.86k
{
188
1.86k
    const QUIC_TXPIM_CHUNK *ac = a, *bc = b;
189
190
1.86k
    if (ac->stream_id < bc->stream_id)
191
703
        return -1;
192
1.15k
    else if (ac->stream_id > bc->stream_id)
193
1.03k
        return 1;
194
195
124
    if (ac->start < bc->start)
196
100
        return -1;
197
24
    else if (ac->start > bc->start)
198
0
        return 1;
199
200
24
    return 0;
201
124
}
202
203
const QUIC_TXPIM_CHUNK *ossl_quic_txpim_pkt_get_chunks(const QUIC_TXPIM_PKT *fpkt)
204
1.27M
{
205
1.27M
    QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
206
207
1.27M
    if (ex->chunks_need_sort) {
208
        /*
209
         * List of chunks will generally be very small so there is no issue
210
         * simply sorting here.
211
         */
212
45.4k
        qsort(ex->chunks, ex->num_chunks, sizeof(QUIC_TXPIM_CHUNK), compare);
213
45.4k
        ex->chunks_need_sort = 0;
214
45.4k
    }
215
216
1.27M
    return ex->chunks;
217
1.27M
}
218
219
size_t ossl_quic_txpim_pkt_get_num_chunks(const QUIC_TXPIM_PKT *fpkt)
220
1.27M
{
221
1.27M
    QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
222
223
1.27M
    return ex->num_chunks;
224
1.27M
}
225
226
size_t ossl_quic_txpim_get_in_use(const QUIC_TXPIM *txpim)
227
0
{
228
0
    return txpim->in_use;
229
0
}