quic_rcidm.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*
  2. * Copyright 2023-2024 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_rcidm.h"
  10. #include "internal/priority_queue.h"
  11. #include "internal/list.h"
  12. #include "internal/common.h"
  13. /*
  14. * QUIC Remote Connection ID Manager
  15. * =================================
  16. *
  17. * We can receive an arbitrary number of RCIDs via NCID frames. Periodically, we
  18. * may desire (for example for anti-connection fingerprinting reasons, etc.)
  19. * to switch to a new RCID according to some arbitrary policy such as the number
  20. * of packets we have sent.
  21. *
  22. * When we do this we should move to the next RCID in the sequence of received
  23. * RCIDs ordered by sequence number. For example, if a peer sends us three NCID
  24. * frames with sequence numbers 10, 11, 12, we should seek to consume these
  25. * RCIDs in order.
  26. *
  27. * However, due to the possibility of packet reordering in the network, NCID
  28. * frames might be received out of order. Thus if a peer sends us NCID frames
  29. * with sequence numbers 12, 10, 11, we should still consume the RCID with
  30. * sequence number 10 before consuming the RCIDs with sequence numbers 11 or 12.
  31. *
  32. * We use a priority queue for this purpose.
  33. */
  34. static void rcidm_update(QUIC_RCIDM *rcidm);
  35. static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm,
  36. const QUIC_CONN_ID *rcid);
  37. #define PACKETS_PER_RCID 10000
  38. #define INITIAL_SEQ_NUM 0
  39. #define PREF_ADDR_SEQ_NUM 1
  40. /*
  41. * RCID
  42. * ====
  43. *
  44. * The RCID structure is used to track RCIDs which have sequence numbers (i.e.,
  45. * INITIAL, PREF_ADDR and NCID type RCIDs). The RCIDs without sequence numbers
  46. * (Initial ODCIDs and Retry ODCIDs), hereafter referred to as unnumbered RCIDs,
  47. * can logically be viewed as their own type of RCID but are tracked separately
  48. * as singletons without needing a discrete structure.
  49. *
  50. * At any given time an RCID object is in one of these states:
  51. *
  52. *
  53. * (start)
  54. * |
  55. * [add]
  56. * |
  57. * _____v_____ ___________ ____________
  58. * | | | | | |
  59. * | PENDING | --[select]--> | CURRENT | --[retire]--> | RETIRING |
  60. * |___________| |___________| |____________|
  61. * |
  62. * [pop]
  63. * |
  64. * v
  65. * (fin)
  66. *
  67. * The transition through the states is monotonic and irreversible.
  68. * The RCID object is freed when it is popped.
  69. *
  70. * PENDING
  71. * Invariants:
  72. * rcid->state == RCID_STATE_PENDING;
  73. * rcid->pq_idx != SIZE_MAX (debug assert only);
  74. * the RCID is not the current RCID, rcidm->cur_rcid != rcid;
  75. * the RCID is in the priority queue;
  76. * the RCID is not in the retiring_list.
  77. *
  78. * CURRENT
  79. * Invariants:
  80. * rcid->state == RCID_STATE_CUR;
  81. * rcid->pq_idx == SIZE_MAX (debug assert only);
  82. * the RCID is the current RCID, rcidm->cur_rcid == rcid;
  83. * the RCID is not in the priority queue;
  84. * the RCID is not in the retiring_list.
  85. *
  86. * RETIRING
  87. * Invariants:
  88. * rcid->state == RCID_STATE_RETIRING;
  89. * rcid->pq_idx == SIZE_MAX (debug assert only);
  90. * the RCID is not the current RCID, rcidm->cur_rcid != rcid;
  91. * the RCID is not in the priority queue;
  92. * the RCID is in the retiring_list.
  93. *
  94. * Invariant: At most one RCID object is in the CURRENT state at any one time.
  95. *
  96. * (If no RCID object is in the CURRENT state, this means either
  97. * an unnumbered RCID is being used as the preferred RCID
  98. * or we currently have no preferred RCID.)
  99. *
  100. * All of the above states can be considered substates of the 'ACTIVE' state
  101. * for an RCID as specified in RFC 9000. A CID only ceases to be active
  102. * when we send a RETIRE_CONN_ID frame, which is the responsibility of the
  103. * user of the RCIDM and happens after the above state machine is terminated.
  104. */
  105. enum {
  106. RCID_STATE_PENDING,
  107. RCID_STATE_CUR,
  108. RCID_STATE_RETIRING
  109. };
  110. enum {
  111. RCID_TYPE_INITIAL, /* CID is from an peer INITIAL packet (seq 0) */
  112. RCID_TYPE_PREF_ADDR, /* CID is from a preferred_address TPARAM (seq 1) */
  113. RCID_TYPE_NCID /* CID is from a NCID frame */
  114. /*
  115. * INITIAL_ODCID and RETRY_ODCID also conceptually exist but are tracked
  116. * separately.
  117. */
  118. };
  119. typedef struct rcid_st {
  120. OSSL_LIST_MEMBER(retiring, struct rcid_st); /* valid iff RETIRING */
  121. QUIC_CONN_ID cid; /* The actual CID string for this RCID */
  122. uint64_t seq_num;
  123. size_t pq_idx; /* Index of entry into priority queue */
  124. unsigned int state : 2; /* RCID_STATE_* */
  125. unsigned int type : 2; /* RCID_TYPE_* */
  126. } RCID;
  127. DEFINE_PRIORITY_QUEUE_OF(RCID);
  128. DEFINE_LIST_OF(retiring, RCID);
  129. /*
  130. * RCID Manager
  131. * ============
  132. *
  133. * The following "business logic" invariants also apply to the RCIDM
  134. * as a whole:
  135. *
  136. * Invariant: An RCID of INITIAL type has a sequence number of 0.
  137. * Invariant: An RCID of PREF_ADDR type has a sequence number of 1.
  138. *
  139. * Invariant: There is never more than one Initial ODCID
  140. * added throughout the lifetime of an RCIDM.
  141. * Invariant: There is never more than one Retry ODCID
  142. * added throughout the lifetime of an RCIDM.
  143. * Invariant: There is never more than one INITIAL RCID created
  144. * throughout the lifetime of an RCIDM.
  145. * Invariant: There is never more than one PREF_ADDR RCID created
  146. * throughout the lifetime of an RCIDM.
  147. * Invariant: No INITIAL or PREF_ADDR RCID may be added after
  148. * the handshake is completed.
  149. *
  150. */
  151. struct quic_rcidm_st {
  152. /*
  153. * The current RCID we prefer to use (value undefined if
  154. * !have_preferred_rcid).
  155. *
  156. * This is preferentially set to a numbered RCID (represented by an RCID
  157. * object) if we have one (in which case preferred_rcid == cur_rcid->cid);
  158. * otherwise it is set to one of the unnumbered RCIDs (the Initial ODCID or
  159. * Retry ODCID) if available (and cur_rcid == NULL).
  160. */
  161. QUIC_CONN_ID preferred_rcid;
  162. /*
  163. * These are initialized if the corresponding added_ flags are set.
  164. */
  165. QUIC_CONN_ID initial_odcid, retry_odcid;
  166. /*
  167. * Total number of packets sent since we last made a packet count-based RCID
  168. * update decision.
  169. */
  170. uint64_t packets_sent;
  171. /* Number of post-handshake RCID changes we have performed. */
  172. uint64_t num_changes;
  173. /*
  174. * The Retire Prior To watermark value; max(retire_prior_to) of all received
  175. * NCID frames.
  176. */
  177. uint64_t retire_prior_to;
  178. /* (SORT BY seq_num ASC) -> (RCID *) */
  179. PRIORITY_QUEUE_OF(RCID) *rcids;
  180. /*
  181. * Current RCID object we are using. This may differ from the first item in
  182. * the priority queue if we received NCID frames out of order. For example
  183. * if we get seq 5, switch to it immediately, then get seq 4, we want to
  184. * keep using seq 5 until we decide to roll again rather than immediately
  185. * switch to seq 4. Never points to an object on the retiring_list.
  186. */
  187. RCID *cur_rcid;
  188. /*
  189. * When a RCID becomes pending-retirement, it is moved to the retiring_list,
  190. * then freed when it is popped from the retired queue. We use a list for
  191. * this rather than a priority queue as the order in which items are freed
  192. * does not matter. We always append to the tail of the list in order to
  193. * maintain the guarantee that the head (if present) only changes when a
  194. * caller calls pop().
  195. */
  196. OSSL_LIST(retiring) retiring_list;
  197. /* Number of entries on the retiring_list. */
  198. size_t num_retiring;
  199. /* preferred_rcid has been changed? */
  200. unsigned int preferred_rcid_changed : 1;
  201. /* Do we have any RCID we can use currently? */
  202. unsigned int have_preferred_rcid : 1;
  203. /* QUIC handshake has been completed? */
  204. unsigned int handshake_complete : 1;
  205. /* odcid was set (not necessarily still valid as a RCID)? */
  206. unsigned int added_initial_odcid : 1;
  207. /* retry_odcid was set (not necessarily still valid as a RCID?) */
  208. unsigned int added_retry_odcid : 1;
  209. /* An initial RCID was added as an RCID structure? */
  210. unsigned int added_initial_rcid : 1;
  211. /* Has a RCID roll been manually requested? */
  212. unsigned int roll_requested : 1;
  213. };
  214. /*
  215. * Caller must periodically pop retired RCIDs and handle them. If the caller
  216. * fails to do so, fail safely rather than start exhibiting integer rollover.
  217. * Limit the total number of numbered RCIDs to an implausibly large but safe
  218. * value.
  219. */
  220. #define MAX_NUMBERED_RCIDS (SIZE_MAX / 2)
  221. static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid,
  222. unsigned int state);
  223. /* Check invariants of an RCID */
  224. static void rcidm_check_rcid(QUIC_RCIDM *rcidm, RCID *rcid)
  225. {
  226. assert(rcid->state == RCID_STATE_PENDING
  227. || rcid->state == RCID_STATE_CUR
  228. || rcid->state == RCID_STATE_RETIRING);
  229. assert((rcid->state == RCID_STATE_PENDING)
  230. == (rcid->pq_idx != SIZE_MAX));
  231. assert((rcid->state == RCID_STATE_CUR)
  232. == (rcidm->cur_rcid == rcid));
  233. assert((ossl_list_retiring_next(rcid) != NULL
  234. || ossl_list_retiring_prev(rcid) != NULL
  235. || ossl_list_retiring_head(&rcidm->retiring_list) == rcid)
  236. == (rcid->state == RCID_STATE_RETIRING));
  237. assert(rcid->type != RCID_TYPE_INITIAL || rcid->seq_num == 0);
  238. assert(rcid->type != RCID_TYPE_PREF_ADDR || rcid->seq_num == 1);
  239. assert(rcid->seq_num <= OSSL_QUIC_VLINT_MAX);
  240. assert(rcid->cid.id_len > 0 && rcid->cid.id_len <= QUIC_MAX_CONN_ID_LEN);
  241. assert(rcid->seq_num >= rcidm->retire_prior_to
  242. || rcid->state == RCID_STATE_RETIRING);
  243. assert(rcidm->num_changes == 0 || rcidm->handshake_complete);
  244. assert(rcid->state != RCID_STATE_RETIRING || rcidm->num_retiring > 0);
  245. }
  246. static int rcid_cmp(const RCID *a, const RCID *b)
  247. {
  248. if (a->seq_num < b->seq_num)
  249. return -1;
  250. if (a->seq_num > b->seq_num)
  251. return 1;
  252. return 0;
  253. }
  254. QUIC_RCIDM *ossl_quic_rcidm_new(const QUIC_CONN_ID *initial_odcid)
  255. {
  256. QUIC_RCIDM *rcidm;
  257. if ((rcidm = OPENSSL_zalloc(sizeof(*rcidm))) == NULL)
  258. return NULL;
  259. if ((rcidm->rcids = ossl_pqueue_RCID_new(rcid_cmp)) == NULL) {
  260. OPENSSL_free(rcidm);
  261. return NULL;
  262. }
  263. if (initial_odcid != NULL) {
  264. rcidm->initial_odcid = *initial_odcid;
  265. rcidm->added_initial_odcid = 1;
  266. }
  267. rcidm_update(rcidm);
  268. return rcidm;
  269. }
  270. void ossl_quic_rcidm_free(QUIC_RCIDM *rcidm)
  271. {
  272. RCID *rcid, *rnext;
  273. if (rcidm == NULL)
  274. return;
  275. OPENSSL_free(rcidm->cur_rcid);
  276. while ((rcid = ossl_pqueue_RCID_pop(rcidm->rcids)) != NULL)
  277. OPENSSL_free(rcid);
  278. LIST_FOREACH_DELSAFE(rcid, rnext, retiring, &rcidm->retiring_list)
  279. OPENSSL_free(rcid);
  280. ossl_pqueue_RCID_free(rcidm->rcids);
  281. OPENSSL_free(rcidm);
  282. }
  283. static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm,
  284. const QUIC_CONN_ID *rcid)
  285. {
  286. if (rcid == NULL) {
  287. rcidm->preferred_rcid_changed = 1;
  288. rcidm->have_preferred_rcid = 0;
  289. return;
  290. }
  291. if (ossl_quic_conn_id_eq(&rcidm->preferred_rcid, rcid))
  292. return;
  293. rcidm->preferred_rcid = *rcid;
  294. rcidm->preferred_rcid_changed = 1;
  295. rcidm->have_preferred_rcid = 1;
  296. }
  297. /*
  298. * RCID Lifecycle Management
  299. * =========================
  300. */
  301. static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num,
  302. const QUIC_CONN_ID *cid,
  303. unsigned int type)
  304. {
  305. RCID *rcid;
  306. if (cid->id_len < 1 || cid->id_len > QUIC_MAX_CONN_ID_LEN
  307. || seq_num > OSSL_QUIC_VLINT_MAX
  308. || ossl_pqueue_RCID_num(rcidm->rcids) + rcidm->num_retiring
  309. > MAX_NUMBERED_RCIDS)
  310. return NULL;
  311. if ((rcid = OPENSSL_zalloc(sizeof(*rcid))) == NULL)
  312. return NULL;
  313. rcid->seq_num = seq_num;
  314. rcid->cid = *cid;
  315. rcid->type = type;
  316. if (rcid->seq_num >= rcidm->retire_prior_to) {
  317. rcid->state = RCID_STATE_PENDING;
  318. if (!ossl_pqueue_RCID_push(rcidm->rcids, rcid, &rcid->pq_idx)) {
  319. OPENSSL_free(rcid);
  320. return NULL;
  321. }
  322. } else {
  323. /* RCID is immediately retired upon creation. */
  324. rcid->state = RCID_STATE_RETIRING;
  325. rcid->pq_idx = SIZE_MAX;
  326. ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid);
  327. ++rcidm->num_retiring;
  328. }
  329. rcidm_check_rcid(rcidm, rcid);
  330. return rcid;
  331. }
  332. static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid,
  333. unsigned int state)
  334. {
  335. unsigned int old_state = rcid->state;
  336. assert(state >= old_state && state <= RCID_STATE_RETIRING);
  337. rcidm_check_rcid(rcidm, rcid);
  338. if (state == old_state)
  339. return;
  340. if (rcidm->cur_rcid != NULL && state == RCID_STATE_CUR) {
  341. rcidm_transition_rcid(rcidm, rcidm->cur_rcid, RCID_STATE_RETIRING);
  342. assert(rcidm->cur_rcid == NULL);
  343. }
  344. if (old_state == RCID_STATE_PENDING) {
  345. ossl_pqueue_RCID_remove(rcidm->rcids, rcid->pq_idx);
  346. rcid->pq_idx = SIZE_MAX;
  347. }
  348. rcid->state = state;
  349. if (state == RCID_STATE_CUR) {
  350. rcidm->cur_rcid = rcid;
  351. } else if (state == RCID_STATE_RETIRING) {
  352. if (old_state == RCID_STATE_CUR)
  353. rcidm->cur_rcid = NULL;
  354. ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid);
  355. ++rcidm->num_retiring;
  356. }
  357. rcidm_check_rcid(rcidm, rcid);
  358. }
  359. static void rcidm_free_rcid(QUIC_RCIDM *rcidm, RCID *rcid)
  360. {
  361. if (rcid == NULL)
  362. return;
  363. rcidm_check_rcid(rcidm, rcid);
  364. switch (rcid->state) {
  365. case RCID_STATE_PENDING:
  366. ossl_pqueue_RCID_remove(rcidm->rcids, rcid->pq_idx);
  367. break;
  368. case RCID_STATE_CUR:
  369. rcidm->cur_rcid = NULL;
  370. break;
  371. case RCID_STATE_RETIRING:
  372. ossl_list_retiring_remove(&rcidm->retiring_list, rcid);
  373. --rcidm->num_retiring;
  374. break;
  375. default:
  376. assert(0);
  377. break;
  378. }
  379. OPENSSL_free(rcid);
  380. }
  381. static void rcidm_handle_retire_prior_to(QUIC_RCIDM *rcidm,
  382. uint64_t retire_prior_to)
  383. {
  384. RCID *rcid;
  385. if (retire_prior_to <= rcidm->retire_prior_to)
  386. return;
  387. /*
  388. * Retire the current RCID (if any) if it is affected.
  389. */
  390. if (rcidm->cur_rcid != NULL && rcidm->cur_rcid->seq_num < retire_prior_to)
  391. rcidm_transition_rcid(rcidm, rcidm->cur_rcid, RCID_STATE_RETIRING);
  392. /*
  393. * Any other RCIDs needing retirement will be at the start of the priority
  394. * queue, so just stop once we see a higher sequence number exceeding the
  395. * threshold.
  396. */
  397. while ((rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) != NULL
  398. && rcid->seq_num < retire_prior_to)
  399. rcidm_transition_rcid(rcidm, rcid, RCID_STATE_RETIRING);
  400. rcidm->retire_prior_to = retire_prior_to;
  401. }
  402. /*
  403. * Decision Logic
  404. * ==============
  405. */
  406. static void rcidm_roll(QUIC_RCIDM *rcidm)
  407. {
  408. RCID *rcid;
  409. if ((rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) == NULL)
  410. return;
  411. rcidm_transition_rcid(rcidm, rcid, RCID_STATE_CUR);
  412. ++rcidm->num_changes;
  413. rcidm->roll_requested = 0;
  414. if (rcidm->packets_sent >= PACKETS_PER_RCID)
  415. rcidm->packets_sent %= PACKETS_PER_RCID;
  416. else
  417. rcidm->packets_sent = 0;
  418. }
  419. static void rcidm_update(QUIC_RCIDM *rcidm)
  420. {
  421. RCID *rcid;
  422. /*
  423. * If we have no current numbered RCID but have one or more pending, use it.
  424. */
  425. if (rcidm->cur_rcid == NULL
  426. && (rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) != NULL) {
  427. rcidm_transition_rcid(rcidm, rcid, RCID_STATE_CUR);
  428. assert(rcidm->cur_rcid != NULL);
  429. }
  430. /* Prefer use of any current numbered RCID we have, if possible. */
  431. if (rcidm->cur_rcid != NULL) {
  432. rcidm_check_rcid(rcidm, rcidm->cur_rcid);
  433. rcidm_set_preferred_rcid(rcidm, &rcidm->cur_rcid->cid);
  434. return;
  435. }
  436. /*
  437. * If there are no RCIDs from NCID frames we can use, go through the various
  438. * kinds of bootstrapping RCIDs we can use in order of priority.
  439. */
  440. if (rcidm->added_retry_odcid && !rcidm->handshake_complete) {
  441. rcidm_set_preferred_rcid(rcidm, &rcidm->retry_odcid);
  442. return;
  443. }
  444. if (rcidm->added_initial_odcid && !rcidm->handshake_complete) {
  445. rcidm_set_preferred_rcid(rcidm, &rcidm->initial_odcid);
  446. return;
  447. }
  448. /* We don't know of any usable RCIDs */
  449. rcidm_set_preferred_rcid(rcidm, NULL);
  450. }
  451. static int rcidm_should_roll(QUIC_RCIDM *rcidm)
  452. {
  453. /*
  454. * Always switch as soon as possible if handshake completes;
  455. * and every n packets after handshake completes or the last roll; and
  456. * whenever manually requested.
  457. */
  458. return rcidm->handshake_complete
  459. && (rcidm->num_changes == 0
  460. || rcidm->packets_sent >= PACKETS_PER_RCID
  461. || rcidm->roll_requested);
  462. }
  463. static void rcidm_tick(QUIC_RCIDM *rcidm)
  464. {
  465. if (rcidm_should_roll(rcidm))
  466. rcidm_roll(rcidm);
  467. rcidm_update(rcidm);
  468. }
  469. /*
  470. * Events
  471. * ======
  472. */
  473. void ossl_quic_rcidm_on_handshake_complete(QUIC_RCIDM *rcidm)
  474. {
  475. if (rcidm->handshake_complete)
  476. return;
  477. rcidm->handshake_complete = 1;
  478. rcidm_tick(rcidm);
  479. }
  480. void ossl_quic_rcidm_on_packet_sent(QUIC_RCIDM *rcidm, uint64_t num_packets)
  481. {
  482. if (num_packets == 0)
  483. return;
  484. rcidm->packets_sent += num_packets;
  485. rcidm_tick(rcidm);
  486. }
  487. void ossl_quic_rcidm_request_roll(QUIC_RCIDM *rcidm)
  488. {
  489. rcidm->roll_requested = 1;
  490. rcidm_tick(rcidm);
  491. }
  492. /*
  493. * Mutation Operations
  494. * ===================
  495. */
  496. int ossl_quic_rcidm_add_from_initial(QUIC_RCIDM *rcidm,
  497. const QUIC_CONN_ID *rcid)
  498. {
  499. RCID *rcid_obj;
  500. if (rcidm->added_initial_rcid || rcidm->handshake_complete)
  501. return 0;
  502. rcid_obj = rcidm_create_rcid(rcidm, INITIAL_SEQ_NUM,
  503. rcid, RCID_TYPE_INITIAL);
  504. if (rcid_obj == NULL)
  505. return 0;
  506. rcidm->added_initial_rcid = 1;
  507. rcidm_tick(rcidm);
  508. return 1;
  509. }
  510. int ossl_quic_rcidm_add_from_server_retry(QUIC_RCIDM *rcidm,
  511. const QUIC_CONN_ID *retry_odcid)
  512. {
  513. if (rcidm->added_retry_odcid || rcidm->handshake_complete)
  514. return 0;
  515. rcidm->retry_odcid = *retry_odcid;
  516. rcidm->added_retry_odcid = 1;
  517. rcidm_tick(rcidm);
  518. return 1;
  519. }
  520. int ossl_quic_rcidm_add_from_ncid(QUIC_RCIDM *rcidm,
  521. const OSSL_QUIC_FRAME_NEW_CONN_ID *ncid)
  522. {
  523. RCID *rcid;
  524. rcid = rcidm_create_rcid(rcidm, ncid->seq_num, &ncid->conn_id, RCID_TYPE_NCID);
  525. if (rcid == NULL)
  526. return 0;
  527. rcidm_handle_retire_prior_to(rcidm, ncid->retire_prior_to);
  528. rcidm_tick(rcidm);
  529. return 1;
  530. }
  531. /*
  532. * Queries
  533. * =======
  534. */
  535. static int rcidm_get_retire(QUIC_RCIDM *rcidm, uint64_t *seq_num, int peek)
  536. {
  537. RCID *rcid = ossl_list_retiring_head(&rcidm->retiring_list);
  538. if (rcid == NULL)
  539. return 0;
  540. if (seq_num != NULL)
  541. *seq_num = rcid->seq_num;
  542. if (!peek)
  543. rcidm_free_rcid(rcidm, rcid);
  544. return 1;
  545. }
  546. int ossl_quic_rcidm_pop_retire_seq_num(QUIC_RCIDM *rcidm,
  547. uint64_t *seq_num)
  548. {
  549. return rcidm_get_retire(rcidm, seq_num, /*peek=*/0);
  550. }
  551. int ossl_quic_rcidm_peek_retire_seq_num(QUIC_RCIDM *rcidm,
  552. uint64_t *seq_num)
  553. {
  554. return rcidm_get_retire(rcidm, seq_num, /*peek=*/1);
  555. }
  556. int ossl_quic_rcidm_get_preferred_tx_dcid(QUIC_RCIDM *rcidm,
  557. QUIC_CONN_ID *tx_dcid)
  558. {
  559. if (!rcidm->have_preferred_rcid)
  560. return 0;
  561. *tx_dcid = rcidm->preferred_rcid;
  562. return 1;
  563. }
  564. int ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM *rcidm,
  565. int clear)
  566. {
  567. int r = rcidm->preferred_rcid_changed;
  568. if (clear)
  569. rcidm->preferred_rcid_changed = 0;
  570. return r;
  571. }
  572. size_t ossl_quic_rcidm_get_num_active(const QUIC_RCIDM *rcidm)
  573. {
  574. return ossl_pqueue_RCID_num(rcidm->rcids)
  575. + (rcidm->cur_rcid != NULL ? 1 : 0)
  576. + ossl_quic_rcidm_get_num_retiring(rcidm);
  577. }
  578. size_t ossl_quic_rcidm_get_num_retiring(const QUIC_RCIDM *rcidm)
  579. {
  580. return rcidm->num_retiring;
  581. }