quic_cfq.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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_cfq.h"
  10. #include "internal/numbers.h"
  11. typedef struct quic_cfq_item_ex_st QUIC_CFQ_ITEM_EX;
  12. struct quic_cfq_item_ex_st {
  13. QUIC_CFQ_ITEM public;
  14. QUIC_CFQ_ITEM_EX *prev, *next;
  15. unsigned char *encoded;
  16. cfq_free_cb *free_cb;
  17. void *free_cb_arg;
  18. uint64_t frame_type;
  19. size_t encoded_len;
  20. uint32_t priority, pn_space, flags;
  21. int state;
  22. };
  23. uint64_t ossl_quic_cfq_item_get_frame_type(const QUIC_CFQ_ITEM *item)
  24. {
  25. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  26. return ex->frame_type;
  27. }
  28. const unsigned char *ossl_quic_cfq_item_get_encoded(const QUIC_CFQ_ITEM *item)
  29. {
  30. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  31. return ex->encoded;
  32. }
  33. size_t ossl_quic_cfq_item_get_encoded_len(const QUIC_CFQ_ITEM *item)
  34. {
  35. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  36. return ex->encoded_len;
  37. }
  38. int ossl_quic_cfq_item_get_state(const QUIC_CFQ_ITEM *item)
  39. {
  40. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  41. return ex->state;
  42. }
  43. uint32_t ossl_quic_cfq_item_get_pn_space(const QUIC_CFQ_ITEM *item)
  44. {
  45. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  46. return ex->pn_space;
  47. }
  48. int ossl_quic_cfq_item_is_unreliable(const QUIC_CFQ_ITEM *item)
  49. {
  50. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  51. return (ex->flags & QUIC_CFQ_ITEM_FLAG_UNRELIABLE) != 0;
  52. }
  53. typedef struct quic_cfq_item_list_st {
  54. QUIC_CFQ_ITEM_EX *head, *tail;
  55. } QUIC_CFQ_ITEM_LIST;
  56. struct quic_cfq_st {
  57. /*
  58. * Invariant: A CFQ item is always in exactly one of these lists, never more
  59. * or less than one.
  60. *
  61. * Invariant: The list the CFQ item is determined exactly by the state field
  62. * of the item.
  63. */
  64. QUIC_CFQ_ITEM_LIST new_list, tx_list, free_list;
  65. };
  66. static int compare(const QUIC_CFQ_ITEM_EX *a, const QUIC_CFQ_ITEM_EX *b)
  67. {
  68. if (a->pn_space < b->pn_space)
  69. return -1;
  70. else if (a->pn_space > b->pn_space)
  71. return 1;
  72. if (a->priority > b->priority)
  73. return -1;
  74. else if (a->priority < b->priority)
  75. return 1;
  76. return 0;
  77. }
  78. static void list_remove(QUIC_CFQ_ITEM_LIST *l, QUIC_CFQ_ITEM_EX *n)
  79. {
  80. if (l->head == n)
  81. l->head = n->next;
  82. if (l->tail == n)
  83. l->tail = n->prev;
  84. if (n->prev != NULL)
  85. n->prev->next = n->next;
  86. if (n->next != NULL)
  87. n->next->prev = n->prev;
  88. n->prev = n->next = NULL;
  89. }
  90. static void list_insert_head(QUIC_CFQ_ITEM_LIST *l, QUIC_CFQ_ITEM_EX *n)
  91. {
  92. n->next = l->head;
  93. n->prev = NULL;
  94. l->head = n;
  95. if (n->next != NULL)
  96. n->next->prev = n;
  97. if (l->tail == NULL)
  98. l->tail = n;
  99. }
  100. static void list_insert_tail(QUIC_CFQ_ITEM_LIST *l, QUIC_CFQ_ITEM_EX *n)
  101. {
  102. n->prev = l->tail;
  103. n->next = NULL;
  104. l->tail = n;
  105. if (n->prev != NULL)
  106. n->prev->next = n;
  107. if (l->head == NULL)
  108. l->head = n;
  109. }
  110. static void list_insert_after(QUIC_CFQ_ITEM_LIST *l,
  111. QUIC_CFQ_ITEM_EX *ref,
  112. QUIC_CFQ_ITEM_EX *n)
  113. {
  114. n->prev = ref;
  115. n->next = ref->next;
  116. if (ref->next != NULL)
  117. ref->next->prev = n;
  118. ref->next = n;
  119. if (l->tail == ref)
  120. l->tail = n;
  121. }
  122. static void list_insert_sorted(QUIC_CFQ_ITEM_LIST *l, QUIC_CFQ_ITEM_EX *n,
  123. int (*cmp)(const QUIC_CFQ_ITEM_EX *a,
  124. const QUIC_CFQ_ITEM_EX *b))
  125. {
  126. QUIC_CFQ_ITEM_EX *p = l->head, *pprev = NULL;
  127. if (p == NULL) {
  128. l->head = l->tail = n;
  129. n->prev = n->next = NULL;
  130. return;
  131. }
  132. for (; p != NULL && cmp(p, n) < 0; pprev = p, p = p->next);
  133. if (p == NULL)
  134. list_insert_tail(l, n);
  135. else if (pprev == NULL)
  136. list_insert_head(l, n);
  137. else
  138. list_insert_after(l, pprev, n);
  139. }
  140. QUIC_CFQ *ossl_quic_cfq_new(void)
  141. {
  142. QUIC_CFQ *cfq = OPENSSL_zalloc(sizeof(*cfq));
  143. if (cfq == NULL)
  144. return NULL;
  145. return cfq;
  146. }
  147. static void clear_item(QUIC_CFQ_ITEM_EX *item)
  148. {
  149. if (item->free_cb != NULL) {
  150. item->free_cb(item->encoded, item->encoded_len, item->free_cb_arg);
  151. item->free_cb = NULL;
  152. item->encoded = NULL;
  153. item->encoded_len = 0;
  154. }
  155. item->state = -1;
  156. }
  157. static void free_list_items(QUIC_CFQ_ITEM_LIST *l)
  158. {
  159. QUIC_CFQ_ITEM_EX *p, *pnext;
  160. for (p = l->head; p != NULL; p = pnext) {
  161. pnext = p->next;
  162. clear_item(p);
  163. OPENSSL_free(p);
  164. }
  165. }
  166. void ossl_quic_cfq_free(QUIC_CFQ *cfq)
  167. {
  168. if (cfq == NULL)
  169. return;
  170. free_list_items(&cfq->new_list);
  171. free_list_items(&cfq->tx_list);
  172. free_list_items(&cfq->free_list);
  173. OPENSSL_free(cfq);
  174. }
  175. static QUIC_CFQ_ITEM_EX *cfq_get_free(QUIC_CFQ *cfq)
  176. {
  177. QUIC_CFQ_ITEM_EX *item = cfq->free_list.head;
  178. if (item != NULL)
  179. return item;
  180. item = OPENSSL_zalloc(sizeof(*item));
  181. if (item == NULL)
  182. return NULL;
  183. item->state = -1;
  184. list_insert_tail(&cfq->free_list, item);
  185. return item;
  186. }
  187. QUIC_CFQ_ITEM *ossl_quic_cfq_add_frame(QUIC_CFQ *cfq,
  188. uint32_t priority,
  189. uint32_t pn_space,
  190. uint64_t frame_type,
  191. uint32_t flags,
  192. const unsigned char *encoded,
  193. size_t encoded_len,
  194. cfq_free_cb *free_cb,
  195. void *free_cb_arg)
  196. {
  197. QUIC_CFQ_ITEM_EX *item = cfq_get_free(cfq);
  198. if (item == NULL)
  199. return NULL;
  200. item->priority = priority;
  201. item->frame_type = frame_type;
  202. item->pn_space = pn_space;
  203. item->encoded = (unsigned char *)encoded;
  204. item->encoded_len = encoded_len;
  205. item->free_cb = free_cb;
  206. item->free_cb_arg = free_cb_arg;
  207. item->state = QUIC_CFQ_STATE_NEW;
  208. item->flags = flags;
  209. list_remove(&cfq->free_list, item);
  210. list_insert_sorted(&cfq->new_list, item, compare);
  211. return &item->public;
  212. }
  213. void ossl_quic_cfq_mark_tx(QUIC_CFQ *cfq, QUIC_CFQ_ITEM *item)
  214. {
  215. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  216. switch (ex->state) {
  217. case QUIC_CFQ_STATE_NEW:
  218. list_remove(&cfq->new_list, ex);
  219. list_insert_tail(&cfq->tx_list, ex);
  220. ex->state = QUIC_CFQ_STATE_TX;
  221. break;
  222. case QUIC_CFQ_STATE_TX:
  223. break; /* nothing to do */
  224. default:
  225. assert(0); /* invalid state (e.g. in free state) */
  226. break;
  227. }
  228. }
  229. void ossl_quic_cfq_mark_lost(QUIC_CFQ *cfq, QUIC_CFQ_ITEM *item,
  230. uint32_t priority)
  231. {
  232. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  233. if (ossl_quic_cfq_item_is_unreliable(item)) {
  234. ossl_quic_cfq_release(cfq, item);
  235. return;
  236. }
  237. switch (ex->state) {
  238. case QUIC_CFQ_STATE_NEW:
  239. if (priority != UINT32_MAX && priority != ex->priority) {
  240. list_remove(&cfq->new_list, ex);
  241. ex->priority = priority;
  242. list_insert_sorted(&cfq->new_list, ex, compare);
  243. }
  244. break; /* nothing to do */
  245. case QUIC_CFQ_STATE_TX:
  246. if (priority != UINT32_MAX)
  247. ex->priority = priority;
  248. list_remove(&cfq->tx_list, ex);
  249. list_insert_sorted(&cfq->new_list, ex, compare);
  250. ex->state = QUIC_CFQ_STATE_NEW;
  251. break;
  252. default:
  253. assert(0); /* invalid state (e.g. in free state) */
  254. break;
  255. }
  256. }
  257. /*
  258. * Releases a CFQ item. The item may be in either state (NEW or TX) prior to the
  259. * call. The QUIC_CFQ_ITEM pointer must not be used following this call.
  260. */
  261. void ossl_quic_cfq_release(QUIC_CFQ *cfq, QUIC_CFQ_ITEM *item)
  262. {
  263. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  264. switch (ex->state) {
  265. case QUIC_CFQ_STATE_NEW:
  266. list_remove(&cfq->new_list, ex);
  267. list_insert_tail(&cfq->free_list, ex);
  268. clear_item(ex);
  269. break;
  270. case QUIC_CFQ_STATE_TX:
  271. list_remove(&cfq->tx_list, ex);
  272. list_insert_tail(&cfq->free_list, ex);
  273. clear_item(ex);
  274. break;
  275. default:
  276. assert(0); /* invalid state (e.g. in free state) */
  277. break;
  278. }
  279. }
  280. QUIC_CFQ_ITEM *ossl_quic_cfq_get_priority_head(const QUIC_CFQ *cfq,
  281. uint32_t pn_space)
  282. {
  283. QUIC_CFQ_ITEM_EX *item = cfq->new_list.head;
  284. for (; item != NULL && item->pn_space != pn_space; item = item->next);
  285. if (item == NULL)
  286. return NULL;
  287. return &item->public;
  288. }
  289. QUIC_CFQ_ITEM *ossl_quic_cfq_item_get_priority_next(const QUIC_CFQ_ITEM *item,
  290. uint32_t pn_space)
  291. {
  292. QUIC_CFQ_ITEM_EX *ex = (QUIC_CFQ_ITEM_EX *)item;
  293. if (ex == NULL)
  294. return NULL;
  295. ex = ex->next;
  296. for (; ex != NULL && ex->pn_space != pn_space; ex = ex->next);
  297. if (ex == NULL)
  298. return NULL; /* ubsan */
  299. return &ex->public;
  300. }