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
109086 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)
214
retiring_list;
215
216
/* Number of entries on the retiring_list. */
217
size_t num_retiring;
218
219
/* preferred_rcid has been changed? */
220
unsigned int preferred_rcid_changed : 1;
221
222
/* Do we have any RCID we can use currently? */
223
unsigned int have_preferred_rcid : 1;
224
225
/* QUIC handshake has been completed? */
226
unsigned int handshake_complete : 1;
227
228
/* odcid was set (not necessarily still valid as a RCID)? */
229
unsigned int added_initial_odcid : 1;
230
/* retry_odcid was set (not necessarily still valid as a RCID?) */
231
unsigned int added_retry_odcid : 1;
232
/* An initial RCID was added as an RCID structure? */
233
unsigned int added_initial_rcid : 1;
234
/* Has a RCID roll been manually requested? */
235
unsigned int roll_requested : 1;
236
};
237
238
/*
239
* Caller must periodically pop retired RCIDs and handle them. If the caller
240
* fails to do so, fail safely rather than start exhibiting integer rollover.
241
* Limit the total number of numbered RCIDs to an implausibly large but safe
242
* value.
243
*/
244
#define MAX_NUMBERED_RCIDS (SIZE_MAX / 2)
245
246
static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid,
247
unsigned int state);
248
249
/* Check invariants of an RCID */
250
static void rcidm_check_rcid(QUIC_RCIDM *rcidm, RCID *rcid)
251
{
252
assert(rcid->state == RCID_STATE_PENDING
253
|| rcid->state == RCID_STATE_CUR
254
|| rcid->state == RCID_STATE_RETIRING);
255
assert((rcid->state == RCID_STATE_PENDING)
256
== (rcid->pq_idx != SIZE_MAX));
257
assert((rcid->state == RCID_STATE_CUR)
258
== (rcidm->cur_rcid == rcid));
259
assert((ossl_list_retiring_next(rcid) != NULL
260
|| ossl_list_retiring_prev(rcid) != NULL
261
|| ossl_list_retiring_head(&rcidm->retiring_list) == rcid)
262
== (rcid->state == RCID_STATE_RETIRING));
263
assert(rcid->type != RCID_TYPE_INITIAL || rcid->seq_num == 0);
264
assert(rcid->type != RCID_TYPE_PREF_ADDR || rcid->seq_num == 1);
265
assert(rcid->seq_num <= OSSL_QUIC_VLINT_MAX);
266
assert(rcid->cid.id_len > 0 && rcid->cid.id_len <= QUIC_MAX_CONN_ID_LEN);
267
assert(rcid->seq_num >= rcidm->retire_prior_to
268
|| rcid->state == RCID_STATE_RETIRING);
269
assert(rcidm->num_changes == 0 || rcidm->handshake_complete);
270
assert(rcid->state != RCID_STATE_RETIRING || rcidm->num_retiring > 0);
271
}
272
273
static int rcid_cmp(const RCID *a, const RCID *b)
274
{
275
if (a->seq_num < b->seq_num)
276
return -1;
277
if (a->seq_num > b->seq_num)
278
return 1;
279
return 0;
280
}
281
282
QUIC_RCIDM *ossl_quic_rcidm_new(const QUIC_CONN_ID *initial_odcid)
283
{
284
QUIC_RCIDM *rcidm;
285
286
if ((rcidm = OPENSSL_zalloc(sizeof(*rcidm))) == NULL)
287
return NULL;
288
289
if ((rcidm->rcids = ossl_pqueue_RCID_new(rcid_cmp)) == NULL) {
290
OPENSSL_free(rcidm);
291
return NULL;
292
}
293
294
if (initial_odcid != NULL) {
295
rcidm->initial_odcid = *initial_odcid;
296
rcidm->added_initial_odcid = 1;
297
}
298
299
rcidm_update(rcidm);
300
return rcidm;
301
}
302
303
void ossl_quic_rcidm_free(QUIC_RCIDM *rcidm)
304
{
305
RCID *rcid, *rnext;
306
307
if (rcidm == NULL)
308
return;
309
310
OPENSSL_free(rcidm->cur_rcid);
311
while ((rcid = ossl_pqueue_RCID_pop(rcidm->rcids)) != NULL)
312
OPENSSL_free(rcid);
313
314
OSSL_LIST_FOREACH_DELSAFE(rcid, rnext, retiring, &rcidm->retiring_list)
315
OPENSSL_free(rcid);
316
317
ossl_pqueue_RCID_free(rcidm->rcids);
318
OPENSSL_free(rcidm);
319
}
320
321
static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm,
322
const QUIC_CONN_ID *rcid)
323
{
324
if (rcid == NULL) {
325
rcidm->preferred_rcid_changed = 1;
326
rcidm->have_preferred_rcid = 0;
327
return;
328
}
329
330
if (ossl_quic_conn_id_eq(&rcidm->preferred_rcid, rcid))
331
return;
332
333
rcidm->preferred_rcid = *rcid;
334
rcidm->preferred_rcid_changed = 1;
335
rcidm->have_preferred_rcid = 1;
336
}
337
338
/*
339
* RCID Lifecycle Management
340
* =========================
341
*/
342
static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num,
343
const QUIC_CONN_ID *cid,
344
unsigned int type)
345
{
346
RCID *rcid;
347
348
if (cid->id_len < 1 || cid->id_len > QUIC_MAX_CONN_ID_LEN
349
|| seq_num > OSSL_QUIC_VLINT_MAX
350
|| ossl_pqueue_RCID_num(rcidm->rcids) + rcidm->num_retiring
351
> MAX_NUMBERED_RCIDS)
352
return NULL;
353
354
if ((rcid = OPENSSL_zalloc(sizeof(*rcid))) == NULL)
355
return NULL;
356
357
rcid->seq_num = seq_num;
358
rcid->cid = *cid;
359
rcid->type = type;
360
361
if (rcid->seq_num >= rcidm->retire_prior_to) {
362
rcid->state = RCID_STATE_PENDING;
363
364
if (!ossl_pqueue_RCID_push(rcidm->rcids, rcid, &rcid->pq_idx)) {
365
OPENSSL_free(rcid);
366
return NULL;
367
}
368
} else {
369
/* RCID is immediately retired upon creation. */
370
rcid->state = RCID_STATE_RETIRING;
371
rcid->pq_idx = SIZE_MAX;
372
ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid);
373
++rcidm->num_retiring;
374
}
375
376
rcidm_check_rcid(rcidm, rcid);
377
return rcid;
378
}
379
380
static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid,
381
unsigned int state)
382
{
383
unsigned int old_state = rcid->state;
384
385
assert(state >= old_state && state <= RCID_STATE_RETIRING);
386
rcidm_check_rcid(rcidm, rcid);
387
if (state == old_state)
388
return;
389
390
if (rcidm->cur_rcid != NULL && state == RCID_STATE_CUR) {
391
rcidm_transition_rcid(rcidm, rcidm->cur_rcid, RCID_STATE_RETIRING);
392
assert(rcidm->cur_rcid == NULL);
393
}
394
395
if (old_state == RCID_STATE_PENDING) {
396
ossl_pqueue_RCID_remove(rcidm->rcids, rcid->pq_idx);
397
rcid->pq_idx = SIZE_MAX;
398
}
399
400
rcid->state = state;
401
402
if (state == RCID_STATE_CUR) {
403
rcidm->cur_rcid = rcid;
404
} else if (state == RCID_STATE_RETIRING) {
405
if (old_state == RCID_STATE_CUR)
406
rcidm->cur_rcid = NULL;
407
408
ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid);
409
++rcidm->num_retiring;
410
}
411
412
rcidm_check_rcid(rcidm, rcid);
413
}
414
415
static void rcidm_free_rcid(QUIC_RCIDM *rcidm, RCID *rcid)
416
{
417
if (rcid == NULL)
418
return;
419
420
rcidm_check_rcid(rcidm, rcid);
421
422
switch (rcid->state) {
423
case RCID_STATE_PENDING:
424
ossl_pqueue_RCID_remove(rcidm->rcids, rcid->pq_idx);
425
break;
426
case RCID_STATE_CUR:
427
rcidm->cur_rcid = NULL;
428
break;
429
case RCID_STATE_RETIRING:
430
ossl_list_retiring_remove(&rcidm->retiring_list, rcid);
431
--rcidm->num_retiring;
432
break;
433
default:
434
assert(0);
435
break;
436
}
437
438
OPENSSL_free(rcid);
439
}
440
441
static void rcidm_handle_retire_prior_to(QUIC_RCIDM *rcidm,
442
uint64_t retire_prior_to)
443
{
444
RCID *rcid;
445
446
if (retire_prior_to <= rcidm->retire_prior_to)
447
return;
448
449
/*
450
* Retire the current RCID (if any) if it is affected.
451
*/
452
if (rcidm->cur_rcid != NULL && rcidm->cur_rcid->seq_num < retire_prior_to)
453
rcidm_transition_rcid(rcidm, rcidm->cur_rcid, RCID_STATE_RETIRING);
454
455
/*
456
* Any other RCIDs needing retirement will be at the start of the priority
457
* queue, so just stop once we see a higher sequence number exceeding the
458
* threshold.
459
*/
460
while ((rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) != NULL
461
&& rcid->seq_num < retire_prior_to)
462
rcidm_transition_rcid(rcidm, rcid, RCID_STATE_RETIRING);
463
464
rcidm->retire_prior_to = retire_prior_to;
465
}
466
467
/*
468
* Decision Logic
469
* ==============
470
*/
471
472
static void rcidm_roll(QUIC_RCIDM *rcidm)
473
{
474
RCID *rcid;
475
476
if ((rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) == NULL)
477
return;
478
479
rcidm_transition_rcid(rcidm, rcid, RCID_STATE_CUR);
480
481
++rcidm->num_changes;
482
rcidm->roll_requested = 0;
483
484
if (rcidm->packets_sent >= PACKETS_PER_RCID)
485
rcidm->packets_sent %= PACKETS_PER_RCID;
486
else
487
rcidm->packets_sent = 0;
488
}
489
490
static void rcidm_update(QUIC_RCIDM *rcidm)
491
{
492
RCID *rcid;
493
494
/*
495
* If we have no current numbered RCID but have one or more pending, use it.
496
*/
497
if (rcidm->cur_rcid == NULL
498
&& (rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) != NULL) {
499
rcidm_transition_rcid(rcidm, rcid, RCID_STATE_CUR);
500
assert(rcidm->cur_rcid != NULL);
501
}
502
503
/* Prefer use of any current numbered RCID we have, if possible. */
504
if (rcidm->cur_rcid != NULL) {
505
rcidm_check_rcid(rcidm, rcidm->cur_rcid);
506
rcidm_set_preferred_rcid(rcidm, &rcidm->cur_rcid->cid);
507
return;
508
}
509
510
/*
511
* If there are no RCIDs from NCID frames we can use, go through the various
512
* kinds of bootstrapping RCIDs we can use in order of priority.
513
*/
514
if (rcidm->added_retry_odcid && !rcidm->handshake_complete) {
515
rcidm_set_preferred_rcid(rcidm, &rcidm->retry_odcid);
516
return;
517
}
518
519
if (rcidm->added_initial_odcid && !rcidm->handshake_complete) {
520
rcidm_set_preferred_rcid(rcidm, &rcidm->initial_odcid);
521
return;
522
}
523
524
/* We don't know of any usable RCIDs */
525
rcidm_set_preferred_rcid(rcidm, NULL);
526
}
527
528
static int rcidm_should_roll(QUIC_RCIDM *rcidm)
529
{
530
/*
531
* Always switch as soon as possible if handshake completes;
532
* and every n packets after handshake completes or the last roll; and
533
* whenever manually requested.
534
*/
535
return rcidm->handshake_complete
536
&& (rcidm->num_changes == 0
537
|| rcidm->packets_sent >= PACKETS_PER_RCID
538
|| rcidm->roll_requested);
539
}
540
541
static void rcidm_tick(QUIC_RCIDM *rcidm)
542
{
543
if (rcidm_should_roll(rcidm))
544
rcidm_roll(rcidm);
545
546
rcidm_update(rcidm);
547
}
548
549
/*
550
* Events
551
* ======
552
*/
553
void ossl_quic_rcidm_on_handshake_complete(QUIC_RCIDM *rcidm)
554
{
555
if (rcidm->handshake_complete)
556
return;
557
558
rcidm->handshake_complete = 1;
559
rcidm_tick(rcidm);
560
}
561
562
void ossl_quic_rcidm_on_packet_sent(QUIC_RCIDM *rcidm, uint64_t num_packets)
563
{
564
if (num_packets == 0)
565
return;
566
567
rcidm->packets_sent += num_packets;
568
rcidm_tick(rcidm);
569
}
570
571
void ossl_quic_rcidm_request_roll(QUIC_RCIDM *rcidm)
572
{
573
rcidm->roll_requested = 1;
574
rcidm_tick(rcidm);
575
}
576
577
/*
578
* Mutation Operations
579
* ===================
580
*/
581
int ossl_quic_rcidm_add_from_initial(QUIC_RCIDM *rcidm,
582
const QUIC_CONN_ID *rcid)
583
{
584
RCID *rcid_obj;
585
586
if (rcidm->added_initial_rcid || rcidm->handshake_complete)
587
return 0;
588
589
rcid_obj = rcidm_create_rcid(rcidm, INITIAL_SEQ_NUM,
590
rcid, RCID_TYPE_INITIAL);
591
if (rcid_obj == NULL)
592
return 0;
593
594
rcidm->added_initial_rcid = 1;
595
rcidm_tick(rcidm);
596
return 1;
597
}
598
599
int ossl_quic_rcidm_add_from_server_retry(QUIC_RCIDM *rcidm,
600
const QUIC_CONN_ID *retry_odcid)
601
{
602
if (rcidm->added_retry_odcid || rcidm->handshake_complete)
603
return 0;
604
605
rcidm->retry_odcid = *retry_odcid;
606
rcidm->added_retry_odcid = 1;
607
rcidm_tick(rcidm);
608
return 1;
609
}
610
611
int ossl_quic_rcidm_add_from_ncid(QUIC_RCIDM *rcidm,
612
const OSSL_QUIC_FRAME_NEW_CONN_ID *ncid)
613
{
614
RCID *rcid;
615
616
rcid = rcidm_create_rcid(rcidm, ncid->seq_num, &ncid->conn_id, RCID_TYPE_NCID);
617
if (rcid == NULL)
618
return 0;
619
620
rcidm_handle_retire_prior_to(rcidm, ncid->retire_prior_to);
621
rcidm_tick(rcidm);
622
return 1;
623
}
624
625
/*
626
* Queries
627
* =======
628
*/
629
630
static int rcidm_get_retire(QUIC_RCIDM *rcidm, uint64_t *seq_num, int peek)
631
{
632
RCID *rcid = ossl_list_retiring_head(&rcidm->retiring_list);
633
634
if (rcid == NULL)
635
return 0;
636
637
if (seq_num != NULL)
638
*seq_num = rcid->seq_num;
639
640
if (!peek)
641
rcidm_free_rcid(rcidm, rcid);
642
643
return 1;
644
}
645
646
int ossl_quic_rcidm_pop_retire_seq_num(QUIC_RCIDM *rcidm,
647
uint64_t *seq_num)
648
{
649
return rcidm_get_retire(rcidm, seq_num, /*peek=*/0);
650
}
651
652
int ossl_quic_rcidm_peek_retire_seq_num(QUIC_RCIDM *rcidm,
653
uint64_t *seq_num)
654
{
655
return rcidm_get_retire(rcidm, seq_num, /*peek=*/1);
656
}
657
658
int ossl_quic_rcidm_get_preferred_tx_dcid(QUIC_RCIDM *rcidm,
659
QUIC_CONN_ID *tx_dcid)
660
{
661
if (!rcidm->have_preferred_rcid)
662
return 0;
663
664
*tx_dcid = rcidm->preferred_rcid;
665
return 1;
666
}
667
668
int ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM *rcidm,
669
int clear)
670
{
671
int r = rcidm->preferred_rcid_changed;
672
673
if (clear)
674
rcidm->preferred_rcid_changed = 0;
675
676
return r;
677
}
678
679
size_t ossl_quic_rcidm_get_num_active(const QUIC_RCIDM *rcidm)
680
{
681
return ossl_pqueue_RCID_num(rcidm->rcids)
682
+ (rcidm->cur_rcid != NULL ? 1 : 0)
683
+ ossl_quic_rcidm_get_num_retiring(rcidm);
684
}
685
686
size_t ossl_quic_rcidm_get_num_retiring(const QUIC_RCIDM *rcidm)
687
{
688
return rcidm->num_retiring;
689
}
690
691