openssl/ssl/quic/quic_txpim.c

218 lines
5.4 KiB
C

/*
* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/quic_txpim.h"
#include <stdlib.h>
typedef struct quic_txpim_pkt_ex_st QUIC_TXPIM_PKT_EX;
struct quic_txpim_pkt_ex_st {
QUIC_TXPIM_PKT public;
QUIC_TXPIM_PKT_EX *prev, *next;
QUIC_TXPIM_CHUNK *chunks;
size_t num_chunks, alloc_chunks;
unsigned int chunks_need_sort : 1;
};
typedef struct quic_txpim_pkt_ex_list {
QUIC_TXPIM_PKT_EX *head, *tail;
} QUIC_TXPIM_PKT_EX_LIST;
struct quic_txpim_st {
QUIC_TXPIM_PKT_EX_LIST free_list;
size_t in_use;
};
#define MAX_ALLOC_CHUNKS 512
QUIC_TXPIM *ossl_quic_txpim_new(void)
{
QUIC_TXPIM *txpim = OPENSSL_zalloc(sizeof(*txpim));
if (txpim == NULL)
return NULL;
return txpim;
}
static void free_list(QUIC_TXPIM_PKT_EX_LIST *l)
{
QUIC_TXPIM_PKT_EX *n, *nnext;
for (n = l->head; n != NULL; n = nnext) {
nnext = n->next;
OPENSSL_free(n->chunks);
OPENSSL_free(n);
}
l->head = l->tail = NULL;
}
void ossl_quic_txpim_free(QUIC_TXPIM *txpim)
{
if (txpim == NULL)
return;
assert(txpim->in_use == 0);
free_list(&txpim->free_list);
OPENSSL_free(txpim);
}
static void list_remove(QUIC_TXPIM_PKT_EX_LIST *l, QUIC_TXPIM_PKT_EX *n)
{
if (l->head == n)
l->head = n->next;
if (l->tail == n)
l->tail = n->prev;
if (n->prev != NULL)
n->prev->next = n->next;
if (n->next != NULL)
n->next->prev = n->prev;
n->prev = n->next = NULL;
}
static void list_insert_tail(QUIC_TXPIM_PKT_EX_LIST *l, QUIC_TXPIM_PKT_EX *n)
{
n->prev = l->tail;
n->next = NULL;
l->tail = n;
if (n->prev != NULL)
n->prev->next = n;
if (l->head == NULL)
l->head = n;
}
static QUIC_TXPIM_PKT_EX *txpim_get_free(QUIC_TXPIM *txpim)
{
QUIC_TXPIM_PKT_EX *ex = txpim->free_list.head;
if (ex != NULL)
return ex;
ex = OPENSSL_zalloc(sizeof(*ex));
if (ex == NULL)
return NULL;
list_insert_tail(&txpim->free_list, ex);
return ex;
}
static void txpim_clear(QUIC_TXPIM_PKT_EX *ex)
{
memset(&ex->public.ackm_pkt, 0, sizeof(ex->public.ackm_pkt));
ossl_quic_txpim_pkt_clear_chunks(&ex->public);
ex->public.retx_head = NULL;
ex->public.fifd = NULL;
ex->public.had_handshake_done_frame = 0;
ex->public.had_max_data_frame = 0;
ex->public.had_max_streams_frame = 0;
ex->public.had_ack_frame = 0;
}
QUIC_TXPIM_PKT *ossl_quic_txpim_pkt_alloc(QUIC_TXPIM *txpim)
{
QUIC_TXPIM_PKT_EX *ex = txpim_get_free(txpim);
if (ex == NULL)
return NULL;
txpim_clear(ex);
list_remove(&txpim->free_list, ex);
++txpim->in_use;
return &ex->public;
}
void ossl_quic_txpim_pkt_release(QUIC_TXPIM *txpim, QUIC_TXPIM_PKT *fpkt)
{
QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
assert(txpim->in_use > 0);
--txpim->in_use;
list_insert_tail(&txpim->free_list, ex);
}
void ossl_quic_txpim_pkt_add_cfq_item(QUIC_TXPIM_PKT *fpkt,
QUIC_CFQ_ITEM *item)
{
item->pkt_next = fpkt->retx_head;
item->pkt_prev = NULL;
fpkt->retx_head = item;
}
void ossl_quic_txpim_pkt_clear_chunks(QUIC_TXPIM_PKT *fpkt)
{
QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
ex->num_chunks = 0;
}
int ossl_quic_txpim_pkt_append_chunk(QUIC_TXPIM_PKT *fpkt,
const QUIC_TXPIM_CHUNK *chunk)
{
QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
QUIC_TXPIM_CHUNK *new_chunk;
size_t new_alloc_chunks = ex->alloc_chunks;
if (ex->num_chunks == ex->alloc_chunks) {
new_alloc_chunks = (ex->alloc_chunks == 0) ? 4 : ex->alloc_chunks * 8 / 5;
if (new_alloc_chunks > MAX_ALLOC_CHUNKS)
new_alloc_chunks = MAX_ALLOC_CHUNKS;
if (ex->num_chunks == new_alloc_chunks)
return 0;
new_chunk = OPENSSL_realloc(ex->chunks,
new_alloc_chunks * sizeof(QUIC_TXPIM_CHUNK));
if (new_chunk == NULL)
return 0;
ex->chunks = new_chunk;
ex->alloc_chunks = new_alloc_chunks;
}
ex->chunks[ex->num_chunks++] = *chunk;
ex->chunks_need_sort = 1;
return 1;
}
static int compare(const void *a, const void *b)
{
const QUIC_TXPIM_CHUNK *ac = a, *bc = b;
if (ac->stream_id < bc->stream_id)
return -1;
else if (ac->stream_id > bc->stream_id)
return 1;
if (ac->start < bc->start)
return -1;
else if (ac->start > bc->start)
return 1;
return 0;
}
const QUIC_TXPIM_CHUNK *ossl_quic_txpim_pkt_get_chunks(QUIC_TXPIM_PKT *fpkt)
{
QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
if (ex->chunks_need_sort) {
qsort(ex->chunks, ex->num_chunks, sizeof(QUIC_TXPIM_CHUNK), compare);
ex->chunks_need_sort = 0;
}
return ex->chunks;
}
size_t ossl_quic_txpim_pkt_get_num_chunks(QUIC_TXPIM_PKT *fpkt)
{
QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
return ex->num_chunks;
}