aboutsummaryrefslogtreecommitdiff
path: root/ssl/quic/quic_txpim.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/quic/quic_txpim.c')
-rw-r--r--ssl/quic/quic_txpim.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/ssl/quic/quic_txpim.c b/ssl/quic/quic_txpim.c
new file mode 100644
index 000000000000..04b25ee47a04
--- /dev/null
+++ b/ssl/quic/quic_txpim.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2022-2023 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;
+}