2
0

quic_fifd_test.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. * Copyright 2022 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/packet.h"
  10. #include "internal/quic_txpim.h"
  11. #include "internal/quic_fifd.h"
  12. #include "testutil.h"
  13. static OSSL_TIME cur_time;
  14. static OSSL_TIME fake_now(void *arg) {
  15. return cur_time;
  16. }
  17. static void step_time(uint64_t ms) {
  18. cur_time = ossl_time_add(cur_time, ossl_ms2time(ms));
  19. }
  20. static QUIC_SSTREAM *(*get_sstream_by_id_p)(uint64_t stream_id, void *arg);
  21. static QUIC_SSTREAM *get_sstream_by_id(uint64_t stream_id, void *arg)
  22. {
  23. return get_sstream_by_id_p(stream_id, arg);
  24. }
  25. static void (*regen_frame_p)(uint64_t frame_type, uint64_t stream_id, void *arg);
  26. static void regen_frame(uint64_t frame_type, uint64_t stream_id, void *arg)
  27. {
  28. regen_frame_p(frame_type, stream_id, arg);
  29. }
  30. typedef struct info_st {
  31. QUIC_FIFD fifd;
  32. OSSL_ACKM *ackm;
  33. QUIC_CFQ *cfq;
  34. QUIC_TXPIM *txpim;
  35. OSSL_STATM statm;
  36. OSSL_CC_DATA *ccdata;
  37. QUIC_SSTREAM *sstream[4];
  38. } INFO;
  39. static INFO *cur_info;
  40. static int cb_fail;
  41. static int cfq_freed;
  42. /* ----------------------------------------------------------------------
  43. * 1. Test that a submitted packet, on ack, acks all streams inside of it
  44. * Test that a submitted packet, on ack, calls the get by ID function
  45. * correctly
  46. * Test that a submitted packet, on ack, acks all fins inside it
  47. * Test that a submitted packet, on ack, releases the TXPIM packet
  48. */
  49. static QUIC_SSTREAM *sstream_expect(uint64_t stream_id, void *arg)
  50. {
  51. if (stream_id == 42 || stream_id == 43)
  52. return cur_info->sstream[stream_id - 42];
  53. cb_fail = 1;
  54. return NULL;
  55. }
  56. static uint64_t regen_frame_type[16];
  57. static uint64_t regen_stream_id[16];
  58. static size_t regen_count;
  59. static void regen_expect(uint64_t frame_type, uint64_t stream_id, void *arg)
  60. {
  61. regen_frame_type[regen_count] = frame_type;
  62. regen_stream_id[regen_count] = stream_id;
  63. ++regen_count;
  64. }
  65. static const unsigned char placeholder_data[] = "placeholder";
  66. static void cfq_free_cb_(unsigned char *buf, size_t buf_len, void *arg)
  67. {
  68. if (buf == placeholder_data && buf_len == sizeof(placeholder_data))
  69. cfq_freed = 1;
  70. }
  71. #define TEST_KIND_ACK 0
  72. #define TEST_KIND_LOSS 1
  73. #define TEST_KIND_DISCARD 2
  74. #define TEST_KIND_NUM 3
  75. static int test_generic(INFO *info, int kind)
  76. {
  77. int testresult = 0;
  78. size_t i, consumed = 0;
  79. QUIC_TXPIM_PKT *pkt = NULL, *pkt2 = NULL;
  80. OSSL_QUIC_FRAME_STREAM hdr = {0};
  81. OSSL_QTX_IOVEC iov[2];
  82. size_t num_iov;
  83. QUIC_TXPIM_CHUNK chunk = {42, 0, 11, 0};
  84. OSSL_QUIC_FRAME_ACK ack = {0};
  85. OSSL_QUIC_ACK_RANGE ack_ranges[1] = {0};
  86. QUIC_CFQ_ITEM *cfq_item = NULL;
  87. uint32_t pn_space = (kind == TEST_KIND_DISCARD)
  88. ? QUIC_PN_SPACE_HANDSHAKE : QUIC_PN_SPACE_APP;
  89. cur_time = ossl_seconds2time(1000);
  90. regen_count = 0;
  91. get_sstream_by_id_p = sstream_expect;
  92. regen_frame_p = regen_expect;
  93. if (!TEST_ptr(pkt = ossl_quic_txpim_pkt_alloc(info->txpim)))
  94. goto err;
  95. for (i = 0; i < 2; ++i) {
  96. num_iov = OSSL_NELEM(iov);
  97. if (!TEST_true(ossl_quic_sstream_append(info->sstream[i],
  98. (unsigned char *)"Test message",
  99. 12, &consumed))
  100. || !TEST_size_t_eq(consumed, 12))
  101. goto err;
  102. if (i == 1)
  103. ossl_quic_sstream_fin(info->sstream[i]);
  104. if (!TEST_true(ossl_quic_sstream_get_stream_frame(info->sstream[i], 0,
  105. &hdr, iov, &num_iov))
  106. || !TEST_int_eq(hdr.is_fin, i == 1)
  107. || !TEST_uint64_t_eq(hdr.offset, 0)
  108. || !TEST_uint64_t_eq(hdr.len, 12)
  109. || !TEST_size_t_eq(ossl_quic_sstream_get_buffer_used(info->sstream[i]), 12)
  110. || !TEST_true(ossl_quic_sstream_mark_transmitted(info->sstream[i],
  111. hdr.offset,
  112. hdr.offset + hdr.len - 1)))
  113. goto err;
  114. if (i == 1 && !TEST_true(ossl_quic_sstream_mark_transmitted_fin(info->sstream[i],
  115. hdr.offset + hdr.len)))
  116. goto err;
  117. chunk.has_fin = hdr.is_fin;
  118. chunk.stream_id = 42 + i;
  119. if (!TEST_true(ossl_quic_txpim_pkt_append_chunk(pkt, &chunk)))
  120. goto err;
  121. }
  122. cfq_freed = 0;
  123. if (!TEST_ptr(cfq_item = ossl_quic_cfq_add_frame(info->cfq, 10,
  124. pn_space,
  125. OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID,
  126. placeholder_data,
  127. sizeof(placeholder_data),
  128. cfq_free_cb_, NULL))
  129. || !TEST_ptr_eq(cfq_item, ossl_quic_cfq_get_priority_head(info->cfq, pn_space)))
  130. goto err;
  131. ossl_quic_txpim_pkt_add_cfq_item(pkt, cfq_item);
  132. pkt->ackm_pkt.pkt_num = 0;
  133. pkt->ackm_pkt.pkt_space = pn_space;
  134. pkt->ackm_pkt.largest_acked = QUIC_PN_INVALID;
  135. pkt->ackm_pkt.num_bytes = 50;
  136. pkt->ackm_pkt.time = cur_time;
  137. pkt->ackm_pkt.is_inflight = 1;
  138. pkt->ackm_pkt.is_ack_eliciting = 1;
  139. if (kind == TEST_KIND_LOSS) {
  140. pkt->had_handshake_done_frame = 1;
  141. pkt->had_max_data_frame = 1;
  142. pkt->had_max_streams_bidi_frame = 1;
  143. pkt->had_max_streams_uni_frame = 1;
  144. pkt->had_ack_frame = 1;
  145. }
  146. ack_ranges[0].start = 0;
  147. ack_ranges[0].end = 0;
  148. ack.ack_ranges = ack_ranges;
  149. ack.num_ack_ranges = 1;
  150. if (!TEST_true(ossl_quic_fifd_pkt_commit(&info->fifd, pkt)))
  151. goto err;
  152. /* CFQ item should have been marked as transmitted */
  153. if (!TEST_ptr_null(ossl_quic_cfq_get_priority_head(info->cfq, pn_space)))
  154. goto err;
  155. switch (kind) {
  156. case TEST_KIND_ACK:
  157. if (!TEST_true(ossl_ackm_on_rx_ack_frame(info->ackm, &ack,
  158. pn_space,
  159. cur_time)))
  160. goto err;
  161. for (i = 0; i < 2; ++i)
  162. if (!TEST_size_t_eq(ossl_quic_sstream_get_buffer_used(info->sstream[i]), 0))
  163. goto err;
  164. /* This should fail, which proves the FIN was acked */
  165. if (!TEST_false(ossl_quic_sstream_mark_lost_fin(info->sstream[1])))
  166. goto err;
  167. /* CFQ item must have been released */
  168. if (!TEST_true(cfq_freed))
  169. goto err;
  170. /* No regen calls should have been made */
  171. if (!TEST_size_t_eq(regen_count, 0))
  172. goto err;
  173. break;
  174. case TEST_KIND_LOSS:
  175. /* Trigger loss detection via packet threshold. */
  176. if (!TEST_ptr(pkt2 = ossl_quic_txpim_pkt_alloc(info->txpim)))
  177. goto err;
  178. step_time(10000);
  179. pkt2->ackm_pkt.pkt_num = 50;
  180. pkt2->ackm_pkt.pkt_space = pn_space;
  181. pkt2->ackm_pkt.largest_acked = QUIC_PN_INVALID;
  182. pkt2->ackm_pkt.num_bytes = 50;
  183. pkt2->ackm_pkt.time = cur_time;
  184. pkt2->ackm_pkt.is_inflight = 1;
  185. pkt2->ackm_pkt.is_ack_eliciting = 1;
  186. ack_ranges[0].start = 50;
  187. ack_ranges[0].end = 50;
  188. ack.ack_ranges = ack_ranges;
  189. ack.num_ack_ranges = 1;
  190. if (!TEST_true(ossl_quic_fifd_pkt_commit(&info->fifd, pkt2))
  191. || !TEST_true(ossl_ackm_on_rx_ack_frame(info->ackm, &ack,
  192. pn_space, cur_time)))
  193. goto err;
  194. for (i = 0; i < 2; ++i) {
  195. num_iov = OSSL_NELEM(iov);
  196. /*
  197. * Stream data we sent must have been marked as lost; check by
  198. * ensuring it is returned again
  199. */
  200. if (!TEST_true(ossl_quic_sstream_get_stream_frame(info->sstream[i], 0,
  201. &hdr, iov, &num_iov))
  202. || !TEST_uint64_t_eq(hdr.offset, 0)
  203. || !TEST_uint64_t_eq(hdr.len, 12))
  204. goto err;
  205. }
  206. /* FC frame should have regenerated for each stream */
  207. if (!TEST_size_t_eq(regen_count, 7)
  208. || !TEST_uint64_t_eq(regen_stream_id[0], 42)
  209. || !TEST_uint64_t_eq(regen_frame_type[0], OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA)
  210. || !TEST_uint64_t_eq(regen_stream_id[1], 43)
  211. || !TEST_uint64_t_eq(regen_frame_type[1], OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA)
  212. || !TEST_uint64_t_eq(regen_frame_type[2], OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE)
  213. || !TEST_uint64_t_eq(regen_stream_id[2], UINT64_MAX)
  214. || !TEST_uint64_t_eq(regen_frame_type[3], OSSL_QUIC_FRAME_TYPE_MAX_DATA)
  215. || !TEST_uint64_t_eq(regen_stream_id[3], UINT64_MAX)
  216. || !TEST_uint64_t_eq(regen_frame_type[4], OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI)
  217. || !TEST_uint64_t_eq(regen_stream_id[4], UINT64_MAX)
  218. || !TEST_uint64_t_eq(regen_frame_type[5], OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI)
  219. || !TEST_uint64_t_eq(regen_stream_id[5], UINT64_MAX)
  220. || !TEST_uint64_t_eq(regen_frame_type[6], OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN)
  221. || !TEST_uint64_t_eq(regen_stream_id[6], UINT64_MAX))
  222. goto err;
  223. /* CFQ item should have been marked as lost */
  224. if (!TEST_ptr_eq(cfq_item, ossl_quic_cfq_get_priority_head(info->cfq, pn_space)))
  225. goto err;
  226. /* FIN should have been marked as lost */
  227. num_iov = OSSL_NELEM(iov);
  228. if (!TEST_true(ossl_quic_sstream_get_stream_frame(info->sstream[1], 10,
  229. &hdr, iov, &num_iov))
  230. || !TEST_true(hdr.is_fin)
  231. || !TEST_uint64_t_eq(hdr.len, 0))
  232. goto err;
  233. break;
  234. case TEST_KIND_DISCARD:
  235. if (!TEST_true(ossl_ackm_on_pkt_space_discarded(info->ackm, pn_space)))
  236. goto err;
  237. /* CFQ item must have been released */
  238. if (!TEST_true(cfq_freed))
  239. goto err;
  240. break;
  241. default:
  242. goto err;
  243. }
  244. /* TXPIM must have been released */
  245. if (!TEST_size_t_eq(ossl_quic_txpim_get_in_use(info->txpim), 0))
  246. goto err;
  247. testresult = 1;
  248. err:
  249. return testresult;
  250. }
  251. static int test_fifd(int idx)
  252. {
  253. int testresult = 0;
  254. INFO info = {0};
  255. size_t i;
  256. cur_info = &info;
  257. cb_fail = 0;
  258. if (!TEST_true(ossl_statm_init(&info.statm))
  259. || !TEST_ptr(info.ccdata = ossl_cc_dummy_method.new(NULL, NULL, NULL))
  260. || !TEST_ptr(info.ackm = ossl_ackm_new(fake_now, NULL,
  261. &info.statm,
  262. &ossl_cc_dummy_method,
  263. info.ccdata))
  264. || !TEST_true(ossl_ackm_on_handshake_confirmed(info.ackm))
  265. || !TEST_ptr(info.cfq = ossl_quic_cfq_new())
  266. || !TEST_ptr(info.txpim = ossl_quic_txpim_new())
  267. || !TEST_true(ossl_quic_fifd_init(&info.fifd, info.cfq, info.ackm,
  268. info.txpim,
  269. get_sstream_by_id, NULL,
  270. regen_frame, NULL)))
  271. goto err;
  272. for (i = 0; i < OSSL_NELEM(info.sstream); ++i)
  273. if (!TEST_ptr(info.sstream[i] = ossl_quic_sstream_new(1024)))
  274. goto err;
  275. ossl_statm_update_rtt(&info.statm, ossl_time_zero(), ossl_ms2time(1));
  276. if (!TEST_true(test_generic(&info, idx))
  277. || !TEST_false(cb_fail))
  278. goto err;
  279. testresult = 1;
  280. err:
  281. ossl_quic_fifd_cleanup(&info.fifd);
  282. ossl_quic_cfq_free(info.cfq);
  283. ossl_quic_txpim_free(info.txpim);
  284. ossl_ackm_free(info.ackm);
  285. ossl_statm_destroy(&info.statm);
  286. if (info.ccdata != NULL)
  287. ossl_cc_dummy_method.free(info.ccdata);
  288. for (i = 0; i < OSSL_NELEM(info.sstream); ++i)
  289. ossl_quic_sstream_free(info.sstream[i]);
  290. cur_info = NULL;
  291. return testresult;
  292. }
  293. int setup_tests(void)
  294. {
  295. ADD_ALL_TESTS(test_fifd, TEST_KIND_NUM);
  296. return 1;
  297. }