quic_txpim.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. #include "internal/quic_txpim.h"
  10. #include <stdlib.h>
  11. typedef struct quic_txpim_pkt_ex_st QUIC_TXPIM_PKT_EX;
  12. struct quic_txpim_pkt_ex_st {
  13. QUIC_TXPIM_PKT public;
  14. QUIC_TXPIM_PKT_EX *prev, *next;
  15. QUIC_TXPIM_CHUNK *chunks;
  16. size_t num_chunks, alloc_chunks;
  17. unsigned int chunks_need_sort : 1;
  18. };
  19. typedef struct quic_txpim_pkt_ex_list {
  20. QUIC_TXPIM_PKT_EX *head, *tail;
  21. } QUIC_TXPIM_PKT_EX_LIST;
  22. struct quic_txpim_st {
  23. QUIC_TXPIM_PKT_EX_LIST free_list;
  24. size_t in_use;
  25. };
  26. #define MAX_ALLOC_CHUNKS 512
  27. QUIC_TXPIM *ossl_quic_txpim_new(void)
  28. {
  29. QUIC_TXPIM *txpim = OPENSSL_zalloc(sizeof(*txpim));
  30. if (txpim == NULL)
  31. return NULL;
  32. return txpim;
  33. }
  34. static void free_list(QUIC_TXPIM_PKT_EX_LIST *l)
  35. {
  36. QUIC_TXPIM_PKT_EX *n, *nnext;
  37. for (n = l->head; n != NULL; n = nnext) {
  38. nnext = n->next;
  39. OPENSSL_free(n->chunks);
  40. OPENSSL_free(n);
  41. }
  42. l->head = l->tail = NULL;
  43. }
  44. void ossl_quic_txpim_free(QUIC_TXPIM *txpim)
  45. {
  46. if (txpim == NULL)
  47. return;
  48. assert(txpim->in_use == 0);
  49. free_list(&txpim->free_list);
  50. OPENSSL_free(txpim);
  51. }
  52. static void list_remove(QUIC_TXPIM_PKT_EX_LIST *l, QUIC_TXPIM_PKT_EX *n)
  53. {
  54. if (l->head == n)
  55. l->head = n->next;
  56. if (l->tail == n)
  57. l->tail = n->prev;
  58. if (n->prev != NULL)
  59. n->prev->next = n->next;
  60. if (n->next != NULL)
  61. n->next->prev = n->prev;
  62. n->prev = n->next = NULL;
  63. }
  64. static void list_insert_tail(QUIC_TXPIM_PKT_EX_LIST *l, QUIC_TXPIM_PKT_EX *n)
  65. {
  66. n->prev = l->tail;
  67. n->next = NULL;
  68. l->tail = n;
  69. if (n->prev != NULL)
  70. n->prev->next = n;
  71. if (l->head == NULL)
  72. l->head = n;
  73. }
  74. static QUIC_TXPIM_PKT_EX *txpim_get_free(QUIC_TXPIM *txpim)
  75. {
  76. QUIC_TXPIM_PKT_EX *ex = txpim->free_list.head;
  77. if (ex != NULL)
  78. return ex;
  79. ex = OPENSSL_zalloc(sizeof(*ex));
  80. if (ex == NULL)
  81. return NULL;
  82. list_insert_tail(&txpim->free_list, ex);
  83. return ex;
  84. }
  85. static void txpim_clear(QUIC_TXPIM_PKT_EX *ex)
  86. {
  87. memset(&ex->public.ackm_pkt, 0, sizeof(ex->public.ackm_pkt));
  88. ossl_quic_txpim_pkt_clear_chunks(&ex->public);
  89. ex->public.retx_head = NULL;
  90. ex->public.fifd = NULL;
  91. ex->public.had_handshake_done_frame = 0;
  92. ex->public.had_max_data_frame = 0;
  93. ex->public.had_max_streams_bidi_frame = 0;
  94. ex->public.had_max_streams_uni_frame = 0;
  95. ex->public.had_ack_frame = 0;
  96. ex->public.had_conn_close = 0;
  97. }
  98. QUIC_TXPIM_PKT *ossl_quic_txpim_pkt_alloc(QUIC_TXPIM *txpim)
  99. {
  100. QUIC_TXPIM_PKT_EX *ex = txpim_get_free(txpim);
  101. if (ex == NULL)
  102. return NULL;
  103. txpim_clear(ex);
  104. list_remove(&txpim->free_list, ex);
  105. ++txpim->in_use;
  106. return &ex->public;
  107. }
  108. void ossl_quic_txpim_pkt_release(QUIC_TXPIM *txpim, QUIC_TXPIM_PKT *fpkt)
  109. {
  110. QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
  111. assert(txpim->in_use > 0);
  112. --txpim->in_use;
  113. list_insert_tail(&txpim->free_list, ex);
  114. }
  115. void ossl_quic_txpim_pkt_add_cfq_item(QUIC_TXPIM_PKT *fpkt,
  116. QUIC_CFQ_ITEM *item)
  117. {
  118. item->pkt_next = fpkt->retx_head;
  119. item->pkt_prev = NULL;
  120. fpkt->retx_head = item;
  121. }
  122. void ossl_quic_txpim_pkt_clear_chunks(QUIC_TXPIM_PKT *fpkt)
  123. {
  124. QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
  125. ex->num_chunks = 0;
  126. }
  127. int ossl_quic_txpim_pkt_append_chunk(QUIC_TXPIM_PKT *fpkt,
  128. const QUIC_TXPIM_CHUNK *chunk)
  129. {
  130. QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
  131. QUIC_TXPIM_CHUNK *new_chunk;
  132. size_t new_alloc_chunks = ex->alloc_chunks;
  133. if (ex->num_chunks == ex->alloc_chunks) {
  134. new_alloc_chunks = (ex->alloc_chunks == 0) ? 4 : ex->alloc_chunks * 8 / 5;
  135. if (new_alloc_chunks > MAX_ALLOC_CHUNKS)
  136. new_alloc_chunks = MAX_ALLOC_CHUNKS;
  137. if (ex->num_chunks == new_alloc_chunks)
  138. return 0;
  139. new_chunk = OPENSSL_realloc(ex->chunks,
  140. new_alloc_chunks * sizeof(QUIC_TXPIM_CHUNK));
  141. if (new_chunk == NULL)
  142. return 0;
  143. ex->chunks = new_chunk;
  144. ex->alloc_chunks = new_alloc_chunks;
  145. }
  146. ex->chunks[ex->num_chunks++] = *chunk;
  147. ex->chunks_need_sort = 1;
  148. return 1;
  149. }
  150. static int compare(const void *a, const void *b)
  151. {
  152. const QUIC_TXPIM_CHUNK *ac = a, *bc = b;
  153. if (ac->stream_id < bc->stream_id)
  154. return -1;
  155. else if (ac->stream_id > bc->stream_id)
  156. return 1;
  157. if (ac->start < bc->start)
  158. return -1;
  159. else if (ac->start > bc->start)
  160. return 1;
  161. return 0;
  162. }
  163. const QUIC_TXPIM_CHUNK *ossl_quic_txpim_pkt_get_chunks(const QUIC_TXPIM_PKT *fpkt)
  164. {
  165. QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
  166. if (ex->chunks_need_sort) {
  167. /*
  168. * List of chunks will generally be very small so there is no issue
  169. * simply sorting here.
  170. */
  171. qsort(ex->chunks, ex->num_chunks, sizeof(QUIC_TXPIM_CHUNK), compare);
  172. ex->chunks_need_sort = 0;
  173. }
  174. return ex->chunks;
  175. }
  176. size_t ossl_quic_txpim_pkt_get_num_chunks(const QUIC_TXPIM_PKT *fpkt)
  177. {
  178. QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
  179. return ex->num_chunks;
  180. }
  181. size_t ossl_quic_txpim_get_in_use(const QUIC_TXPIM *txpim)
  182. {
  183. return txpim->in_use;
  184. }