| 
									
										
										
										
											2022-09-15 19:29:10 +08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2023-09-07 16:59:15 +08:00
										 |  |  |  * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2022-09-15 19:29:10 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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)); | 
					
						
							| 
									
										
										
										
											2022-10-13 00:44:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-15 19:29:10 +08:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2022-09-15 19:48:50 +08:00
										 |  |  |     ex->public.had_max_streams_bidi_frame  = 0; | 
					
						
							|  |  |  |     ex->public.had_max_streams_uni_frame   = 0; | 
					
						
							| 
									
										
										
										
											2022-09-15 19:29:10 +08:00
										 |  |  |     ex->public.had_ack_frame               = 0; | 
					
						
							| 
									
										
										
										
											2023-08-18 18:55:50 +08:00
										 |  |  |     ex->public.had_conn_close              = 0; | 
					
						
							| 
									
										
										
										
											2022-09-15 19:29:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-13 00:44:40 +08:00
										 |  |  | const QUIC_TXPIM_CHUNK *ossl_quic_txpim_pkt_get_chunks(const QUIC_TXPIM_PKT *fpkt) | 
					
						
							| 
									
										
										
										
											2022-09-15 19:29:10 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ex->chunks_need_sort) { | 
					
						
							| 
									
										
										
										
											2022-09-15 19:48:50 +08:00
										 |  |  |         /*
 | 
					
						
							|  |  |  |          * List of chunks will generally be very small so there is no issue | 
					
						
							|  |  |  |          * simply sorting here. | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2022-09-15 19:29:10 +08:00
										 |  |  |         qsort(ex->chunks, ex->num_chunks, sizeof(QUIC_TXPIM_CHUNK), compare); | 
					
						
							|  |  |  |         ex->chunks_need_sort = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ex->chunks; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-13 00:44:40 +08:00
										 |  |  | size_t ossl_quic_txpim_pkt_get_num_chunks(const QUIC_TXPIM_PKT *fpkt) | 
					
						
							| 
									
										
										
										
											2022-09-15 19:29:10 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ex->num_chunks; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-09-15 19:48:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-13 00:44:40 +08:00
										 |  |  | size_t ossl_quic_txpim_get_in_use(const QUIC_TXPIM *txpim) | 
					
						
							| 
									
										
										
										
											2022-09-15 19:48:50 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     return txpim->in_use; | 
					
						
							|  |  |  | } |