Coverage Report

Created: 2026-06-07 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/third_party/ngtcp2/lib/ngtcp2_pv.c
Line
Count
Source
1
/*
2
 * ngtcp2
3
 *
4
 * Copyright (c) 2019 ngtcp2 contributors
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining
7
 * a copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sublicense, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be
15
 * included in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
#include "ngtcp2_pv.h"
26
27
#include <string.h>
28
#include <assert.h>
29
30
#include "ngtcp2_mem.h"
31
#include "ngtcp2_log.h"
32
#include "ngtcp2_macro.h"
33
#include "ngtcp2_addr.h"
34
#include "ngtcp2_str.h"
35
36
void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent,
37
                          const ngtcp2_path_challenge_data *data,
38
0
                          ngtcp2_tstamp expiry, uint8_t flags) {
39
0
  *pvent = (ngtcp2_pv_entry){
40
0
    .expiry = expiry,
41
0
    .flags = flags,
42
0
    .data = *data,
43
0
  };
44
0
}
45
46
int ngtcp2_pv_new(ngtcp2_pv **ppv, const ngtcp2_dcid *dcid,
47
                  ngtcp2_duration timeout, uint8_t flags, ngtcp2_log *log,
48
0
                  const ngtcp2_mem *mem) {
49
0
  (*ppv) = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_pv));
50
0
  if (*ppv == NULL) {
51
0
    return NGTCP2_ERR_NOMEM;
52
0
  }
53
54
0
  ngtcp2_static_ringbuf_pv_ents_init(&(*ppv)->ents);
55
56
0
  ngtcp2_dcid_copy(&(*ppv)->dcid, dcid);
57
58
0
  (*ppv)->mem = mem;
59
0
  (*ppv)->log = log;
60
0
  (*ppv)->timeout = timeout;
61
0
  (*ppv)->fallback_pto = 0;
62
0
  (*ppv)->started_ts = UINT64_MAX;
63
0
  (*ppv)->probe_pkt_left = NGTCP2_PV_NUM_PROBE_PKT;
64
0
  (*ppv)->round = 0;
65
0
  (*ppv)->flags = flags;
66
67
0
  return 0;
68
0
}
69
70
0
void ngtcp2_pv_del(ngtcp2_pv *pv) {
71
0
  if (pv == NULL) {
72
0
    return;
73
0
  }
74
0
  ngtcp2_mem_free(pv->mem, pv);
75
0
}
76
77
void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const ngtcp2_path_challenge_data *data,
78
                         ngtcp2_tstamp expiry, uint8_t flags,
79
0
                         ngtcp2_tstamp ts) {
80
0
  ngtcp2_pv_entry *ent;
81
82
0
  assert(pv->probe_pkt_left);
83
84
0
  if (ngtcp2_ringbuf_len(&pv->ents.rb) == 0) {
85
0
    pv->started_ts = ts;
86
0
  }
87
88
0
  ent = ngtcp2_ringbuf_push_back(&pv->ents.rb);
89
0
  ngtcp2_pv_entry_init(ent, data, expiry, flags);
90
91
0
  pv->flags &= (uint8_t)~NGTCP2_PV_FLAG_CANCEL_TIMER;
92
0
  --pv->probe_pkt_left;
93
0
}
94
95
int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags,
96
0
                       const ngtcp2_path_challenge_data *data) {
97
0
  size_t len = ngtcp2_ringbuf_len(&pv->ents.rb);
98
0
  size_t i;
99
0
  ngtcp2_pv_entry *ent;
100
101
0
  if (len == 0) {
102
0
    return NGTCP2_ERR_INVALID_STATE;
103
0
  }
104
105
0
  for (i = 0; i < len; ++i) {
106
0
    ent = ngtcp2_ringbuf_get(&pv->ents.rb, i);
107
0
    if (ngtcp2_cmemeq(ent->data.data, data->data, sizeof(ent->data.data))) {
108
0
      *pflags = ent->flags;
109
0
      ngtcp2_log_info(pv->log, NGTCP2_LOG_EVENT_PTV, "path has been validated");
110
0
      return 0;
111
0
    }
112
0
  }
113
114
0
  return NGTCP2_ERR_INVALID_ARGUMENT;
115
0
}
116
117
0
void ngtcp2_pv_handle_entry_expiry(ngtcp2_pv *pv, ngtcp2_tstamp ts) {
118
0
  ngtcp2_pv_entry *ent;
119
120
0
  if (ngtcp2_ringbuf_len(&pv->ents.rb) == 0) {
121
0
    return;
122
0
  }
123
124
0
  ent = ngtcp2_ringbuf_get(&pv->ents.rb, ngtcp2_ringbuf_len(&pv->ents.rb) - 1);
125
126
0
  if (ent->expiry > ts) {
127
0
    return;
128
0
  }
129
130
0
  ++pv->round;
131
0
  pv->probe_pkt_left = NGTCP2_PV_NUM_PROBE_PKT;
132
0
}
133
134
0
int ngtcp2_pv_should_send_probe(ngtcp2_pv *pv) {
135
0
  return pv->probe_pkt_left > 0;
136
0
}
137
138
0
int ngtcp2_pv_validation_timed_out(ngtcp2_pv *pv, ngtcp2_tstamp ts) {
139
0
  ngtcp2_tstamp t;
140
0
  ngtcp2_pv_entry *ent;
141
142
0
  if (pv->started_ts == UINT64_MAX) {
143
0
    return 0;
144
0
  }
145
146
0
  assert(ngtcp2_ringbuf_len(&pv->ents.rb));
147
148
0
  ent = ngtcp2_ringbuf_get(&pv->ents.rb, ngtcp2_ringbuf_len(&pv->ents.rb) - 1);
149
150
0
  t = pv->started_ts + pv->timeout;
151
0
  t = ngtcp2_max_uint64(t, ent->expiry);
152
153
0
  return t <= ts;
154
0
}
155
156
0
ngtcp2_tstamp ngtcp2_pv_next_expiry(ngtcp2_pv *pv) {
157
0
  ngtcp2_pv_entry *ent;
158
159
0
  if ((pv->flags & NGTCP2_PV_FLAG_CANCEL_TIMER) ||
160
0
      ngtcp2_ringbuf_len(&pv->ents.rb) == 0) {
161
0
    return UINT64_MAX;
162
0
  }
163
164
0
  ent = ngtcp2_ringbuf_get(&pv->ents.rb, ngtcp2_ringbuf_len(&pv->ents.rb) - 1);
165
166
0
  return ent->expiry;
167
0
}
168
169
0
void ngtcp2_pv_cancel_expired_timer(ngtcp2_pv *pv, ngtcp2_tstamp ts) {
170
0
  ngtcp2_tstamp expiry = ngtcp2_pv_next_expiry(pv);
171
172
0
  if (expiry > ts) {
173
0
    return;
174
0
  }
175
176
0
  pv->flags |= NGTCP2_PV_FLAG_CANCEL_TIMER;
177
0
}
178
179
void ngtcp2_pv_set_fallback(ngtcp2_pv *pv, const ngtcp2_dcid *dcid,
180
0
                            ngtcp2_duration pto) {
181
0
  pv->flags |= NGTCP2_PV_FLAG_FALLBACK_PRESENT;
182
0
  ngtcp2_dcid_copy(&pv->fallback_dcid, dcid);
183
0
  pv->fallback_pto = pto;
184
0
}