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