mirror of
https://github.com/openssl/openssl.git
synced 2025-01-06 13:26:43 +08:00
0b31072e08
If we want to send a CONNECTION_CLOSE frame then one is enough unless we are scheduled to send another one. Now that we can create more than one datagram in one go this is now required. Reviewed-by: Hugo Landau <hlandau@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/21798)
230 lines
5.7 KiB
C
230 lines
5.7 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_bidi_frame = 0;
|
|
ex->public.had_max_streams_uni_frame = 0;
|
|
ex->public.had_ack_frame = 0;
|
|
ex->public.had_conn_close = 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(const QUIC_TXPIM_PKT *fpkt)
|
|
{
|
|
QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
|
|
|
|
if (ex->chunks_need_sort) {
|
|
/*
|
|
* List of chunks will generally be very small so there is no issue
|
|
* simply sorting here.
|
|
*/
|
|
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(const QUIC_TXPIM_PKT *fpkt)
|
|
{
|
|
QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
|
|
|
|
return ex->num_chunks;
|
|
}
|
|
|
|
size_t ossl_quic_txpim_get_in_use(const QUIC_TXPIM *txpim)
|
|
{
|
|
return txpim->in_use;
|
|
}
|