2
0

quic_fifd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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_fifd.h"
  10. #include "internal/quic_wire.h"
  11. DEFINE_LIST_OF(tx_history, OSSL_ACKM_TX_PKT);
  12. int ossl_quic_fifd_init(QUIC_FIFD *fifd,
  13. QUIC_CFQ *cfq,
  14. OSSL_ACKM *ackm,
  15. QUIC_TXPIM *txpim,
  16. /* stream_id is UINT64_MAX for the crypto stream */
  17. QUIC_SSTREAM *(*get_sstream_by_id)(uint64_t stream_id,
  18. uint32_t pn_space,
  19. void *arg),
  20. void *get_sstream_by_id_arg,
  21. /* stream_id is UINT64_MAX if not applicable */
  22. void (*regen_frame)(uint64_t frame_type,
  23. uint64_t stream_id,
  24. QUIC_TXPIM_PKT *pkt,
  25. void *arg),
  26. void *regen_frame_arg,
  27. void (*confirm_frame)(uint64_t frame_type,
  28. uint64_t stream_id,
  29. QUIC_TXPIM_PKT *pkt,
  30. void *arg),
  31. void *confirm_frame_arg,
  32. void (*sstream_updated)(uint64_t stream_id,
  33. void *arg),
  34. void *sstream_updated_arg)
  35. {
  36. if (cfq == NULL || ackm == NULL || txpim == NULL
  37. || get_sstream_by_id == NULL || regen_frame == NULL)
  38. return 0;
  39. fifd->cfq = cfq;
  40. fifd->ackm = ackm;
  41. fifd->txpim = txpim;
  42. fifd->get_sstream_by_id = get_sstream_by_id;
  43. fifd->get_sstream_by_id_arg = get_sstream_by_id_arg;
  44. fifd->regen_frame = regen_frame;
  45. fifd->regen_frame_arg = regen_frame_arg;
  46. fifd->confirm_frame = confirm_frame;
  47. fifd->confirm_frame_arg = confirm_frame_arg;
  48. fifd->sstream_updated = sstream_updated;
  49. fifd->sstream_updated_arg = sstream_updated_arg;
  50. return 1;
  51. }
  52. void ossl_quic_fifd_cleanup(QUIC_FIFD *fifd)
  53. {
  54. /* No-op. */
  55. }
  56. static void on_acked(void *arg)
  57. {
  58. QUIC_TXPIM_PKT *pkt = arg;
  59. QUIC_FIFD *fifd = pkt->fifd;
  60. const QUIC_TXPIM_CHUNK *chunks = ossl_quic_txpim_pkt_get_chunks(pkt);
  61. size_t i, num_chunks = ossl_quic_txpim_pkt_get_num_chunks(pkt);
  62. QUIC_SSTREAM *sstream;
  63. QUIC_CFQ_ITEM *cfq_item, *cfq_item_next;
  64. /* STREAM and CRYPTO stream chunks, FINs and stream FC frames */
  65. for (i = 0; i < num_chunks; ++i) {
  66. sstream = fifd->get_sstream_by_id(chunks[i].stream_id,
  67. pkt->ackm_pkt.pkt_space,
  68. fifd->get_sstream_by_id_arg);
  69. if (sstream == NULL)
  70. continue;
  71. if (chunks[i].end >= chunks[i].start)
  72. /* coverity[check_return]: Best effort - we cannot fail here. */
  73. ossl_quic_sstream_mark_acked(sstream,
  74. chunks[i].start, chunks[i].end);
  75. if (chunks[i].has_fin && chunks[i].stream_id != UINT64_MAX)
  76. ossl_quic_sstream_mark_acked_fin(sstream);
  77. if (chunks[i].has_stop_sending && chunks[i].stream_id != UINT64_MAX)
  78. fifd->confirm_frame(OSSL_QUIC_FRAME_TYPE_STOP_SENDING,
  79. chunks[i].stream_id, pkt,
  80. fifd->confirm_frame_arg);
  81. if (chunks[i].has_reset_stream && chunks[i].stream_id != UINT64_MAX)
  82. fifd->confirm_frame(OSSL_QUIC_FRAME_TYPE_RESET_STREAM,
  83. chunks[i].stream_id, pkt,
  84. fifd->confirm_frame_arg);
  85. if (ossl_quic_sstream_is_totally_acked(sstream))
  86. fifd->sstream_updated(chunks[i].stream_id, fifd->sstream_updated_arg);
  87. }
  88. /* GCR */
  89. for (cfq_item = pkt->retx_head; cfq_item != NULL; cfq_item = cfq_item_next) {
  90. cfq_item_next = cfq_item->pkt_next;
  91. ossl_quic_cfq_release(fifd->cfq, cfq_item);
  92. }
  93. ossl_quic_txpim_pkt_release(fifd->txpim, pkt);
  94. }
  95. static void on_lost(void *arg)
  96. {
  97. QUIC_TXPIM_PKT *pkt = arg;
  98. QUIC_FIFD *fifd = pkt->fifd;
  99. const QUIC_TXPIM_CHUNK *chunks = ossl_quic_txpim_pkt_get_chunks(pkt);
  100. size_t i, num_chunks = ossl_quic_txpim_pkt_get_num_chunks(pkt);
  101. QUIC_SSTREAM *sstream;
  102. QUIC_CFQ_ITEM *cfq_item, *cfq_item_next;
  103. int sstream_updated;
  104. /* STREAM and CRYPTO stream chunks, FIN and stream FC frames */
  105. for (i = 0; i < num_chunks; ++i) {
  106. sstream = fifd->get_sstream_by_id(chunks[i].stream_id,
  107. pkt->ackm_pkt.pkt_space,
  108. fifd->get_sstream_by_id_arg);
  109. if (sstream == NULL)
  110. continue;
  111. sstream_updated = 0;
  112. if (chunks[i].end >= chunks[i].start) {
  113. /*
  114. * Note: If the stream is being reset, we do not need to retransmit
  115. * old data as this is pointless. In this case this will be handled
  116. * by (sstream == NULL) above as the QSM will free the QUIC_SSTREAM
  117. * and our call to get_sstream_by_id above will return NULL.
  118. */
  119. ossl_quic_sstream_mark_lost(sstream,
  120. chunks[i].start, chunks[i].end);
  121. sstream_updated = 1;
  122. }
  123. if (chunks[i].has_fin && chunks[i].stream_id != UINT64_MAX) {
  124. ossl_quic_sstream_mark_lost_fin(sstream);
  125. sstream_updated = 1;
  126. }
  127. if (chunks[i].has_stop_sending && chunks[i].stream_id != UINT64_MAX)
  128. fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_STOP_SENDING,
  129. chunks[i].stream_id, pkt,
  130. fifd->regen_frame_arg);
  131. if (chunks[i].has_reset_stream && chunks[i].stream_id != UINT64_MAX)
  132. fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_RESET_STREAM,
  133. chunks[i].stream_id, pkt,
  134. fifd->regen_frame_arg);
  135. /*
  136. * Inform caller that stream needs an FC frame.
  137. *
  138. * Note: We could track whether an FC frame was sent originally for the
  139. * stream to determine if it really needs to be regenerated or not.
  140. * However, if loss has occurred, it's probably better to ensure the
  141. * peer has up-to-date flow control data for the stream. Given that
  142. * these frames are extremely small, we may as well always send it when
  143. * handling loss.
  144. */
  145. fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA,
  146. chunks[i].stream_id,
  147. pkt,
  148. fifd->regen_frame_arg);
  149. if (sstream_updated && chunks[i].stream_id != UINT64_MAX)
  150. fifd->sstream_updated(chunks[i].stream_id,
  151. fifd->sstream_updated_arg);
  152. }
  153. /* GCR */
  154. for (cfq_item = pkt->retx_head; cfq_item != NULL; cfq_item = cfq_item_next) {
  155. cfq_item_next = cfq_item->pkt_next;
  156. ossl_quic_cfq_mark_lost(fifd->cfq, cfq_item, UINT32_MAX);
  157. }
  158. /* Regenerate flag frames */
  159. if (pkt->had_handshake_done_frame)
  160. fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE,
  161. UINT64_MAX, pkt,
  162. fifd->regen_frame_arg);
  163. if (pkt->had_max_data_frame)
  164. fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_DATA,
  165. UINT64_MAX, pkt,
  166. fifd->regen_frame_arg);
  167. if (pkt->had_max_streams_bidi_frame)
  168. fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI,
  169. UINT64_MAX, pkt,
  170. fifd->regen_frame_arg);
  171. if (pkt->had_max_streams_uni_frame)
  172. fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI,
  173. UINT64_MAX, pkt,
  174. fifd->regen_frame_arg);
  175. if (pkt->had_ack_frame)
  176. /*
  177. * We always use the ACK_WITH_ECN frame type to represent the ACK frame
  178. * type in our callback; we assume it is the caller's job to decide
  179. * whether it wants to send ECN data or not.
  180. */
  181. fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN,
  182. UINT64_MAX, pkt,
  183. fifd->regen_frame_arg);
  184. ossl_quic_txpim_pkt_release(fifd->txpim, pkt);
  185. }
  186. static void on_discarded(void *arg)
  187. {
  188. QUIC_TXPIM_PKT *pkt = arg;
  189. QUIC_FIFD *fifd = pkt->fifd;
  190. QUIC_CFQ_ITEM *cfq_item, *cfq_item_next;
  191. /*
  192. * Don't need to do anything to SSTREAMs for STREAM and CRYPTO streams, as
  193. * we assume caller will clean them up.
  194. */
  195. /* GCR */
  196. for (cfq_item = pkt->retx_head; cfq_item != NULL; cfq_item = cfq_item_next) {
  197. cfq_item_next = cfq_item->pkt_next;
  198. ossl_quic_cfq_release(fifd->cfq, cfq_item);
  199. }
  200. ossl_quic_txpim_pkt_release(fifd->txpim, pkt);
  201. }
  202. int ossl_quic_fifd_pkt_commit(QUIC_FIFD *fifd, QUIC_TXPIM_PKT *pkt)
  203. {
  204. QUIC_CFQ_ITEM *cfq_item;
  205. const QUIC_TXPIM_CHUNK *chunks;
  206. size_t i, num_chunks;
  207. QUIC_SSTREAM *sstream;
  208. pkt->fifd = fifd;
  209. pkt->ackm_pkt.on_lost = on_lost;
  210. pkt->ackm_pkt.on_acked = on_acked;
  211. pkt->ackm_pkt.on_discarded = on_discarded;
  212. pkt->ackm_pkt.cb_arg = pkt;
  213. ossl_list_tx_history_init_elem(&pkt->ackm_pkt);
  214. pkt->ackm_pkt.anext = pkt->ackm_pkt.lnext = NULL;
  215. /*
  216. * Mark the CFQ items which have been added to this packet as having been
  217. * transmitted.
  218. */
  219. for (cfq_item = pkt->retx_head;
  220. cfq_item != NULL;
  221. cfq_item = cfq_item->pkt_next)
  222. ossl_quic_cfq_mark_tx(fifd->cfq, cfq_item);
  223. /*
  224. * Mark the send stream chunks which have been added to the packet as having
  225. * been transmitted.
  226. */
  227. chunks = ossl_quic_txpim_pkt_get_chunks(pkt);
  228. num_chunks = ossl_quic_txpim_pkt_get_num_chunks(pkt);
  229. for (i = 0; i < num_chunks; ++i) {
  230. sstream = fifd->get_sstream_by_id(chunks[i].stream_id,
  231. pkt->ackm_pkt.pkt_space,
  232. fifd->get_sstream_by_id_arg);
  233. if (sstream == NULL)
  234. continue;
  235. if (chunks[i].end >= chunks[i].start
  236. && !ossl_quic_sstream_mark_transmitted(sstream,
  237. chunks[i].start,
  238. chunks[i].end))
  239. return 0;
  240. if (chunks[i].has_fin
  241. && !ossl_quic_sstream_mark_transmitted_fin(sstream,
  242. chunks[i].end + 1))
  243. return 0;
  244. }
  245. /* Inform the ACKM. */
  246. return ossl_ackm_on_tx_packet(fifd->ackm, &pkt->ackm_pkt);
  247. }