Coverage Report

Created: 2026-09-03 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/third_party/ngtcp2/lib/ngtcp2_pmtud.c
Line
Count
Source
1
/*
2
 * ngtcp2
3
 *
4
 * Copyright (c) 2022 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_pmtud.h"
26
27
#include <assert.h>
28
29
#include "ngtcp2_mem.h"
30
#include "ngtcp2_macro.h"
31
32
/* NGTCP2_PMTUD_PROBE_NUM_MAX is the maximum number of packets sent
33
   for each probe. */
34
0
#define NGTCP2_PMTUD_PROBE_NUM_MAX 3
35
36
static uint16_t pmtud_default_probes[] = {
37
  1454 - 48, /* The well known MTU used by a domestic optic fiber
38
                service in Japan. */
39
  1390 - 48, /* Typical Tunneled MTU */
40
  1280 - 48, /* IPv6 minimum MTU */
41
  1492 - 48, /* PPPoE */
42
};
43
44
int ngtcp2_pmtud_new(ngtcp2_pmtud **ppmtud, size_t max_udp_payload_size,
45
                     size_t hard_max_udp_payload_size, int64_t tx_pkt_num,
46
                     const uint16_t *probes, size_t probeslen,
47
0
                     const ngtcp2_mem *mem) {
48
0
  ngtcp2_pmtud *pmtud = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_pmtud));
49
50
0
  if (pmtud == NULL) {
51
0
    return NGTCP2_ERR_NOMEM;
52
0
  }
53
54
0
  pmtud->mem = mem;
55
0
  pmtud->mtu_idx = 0;
56
0
  pmtud->num_pkts_sent = 0;
57
0
  pmtud->expiry = UINT64_MAX;
58
0
  pmtud->tx_pkt_num = tx_pkt_num;
59
0
  pmtud->max_udp_payload_size = max_udp_payload_size;
60
0
  pmtud->hard_max_udp_payload_size = hard_max_udp_payload_size;
61
0
  pmtud->min_fail_udp_payload_size = SIZE_MAX;
62
63
0
  if (probeslen) {
64
0
    pmtud->probes = probes;
65
0
    pmtud->probeslen = probeslen;
66
0
  } else {
67
0
    pmtud->probes = pmtud_default_probes;
68
0
    pmtud->probeslen = ngtcp2_arraylen(pmtud_default_probes);
69
0
  }
70
71
0
  for (; pmtud->mtu_idx < pmtud->probeslen; ++pmtud->mtu_idx) {
72
0
    if (pmtud->probes[pmtud->mtu_idx] > pmtud->hard_max_udp_payload_size) {
73
0
      continue;
74
0
    }
75
0
    if (pmtud->probes[pmtud->mtu_idx] > pmtud->max_udp_payload_size) {
76
0
      break;
77
0
    }
78
0
  }
79
80
0
  *ppmtud = pmtud;
81
82
0
  return 0;
83
0
}
84
85
0
void ngtcp2_pmtud_del(ngtcp2_pmtud *pmtud) {
86
0
  if (!pmtud) {
87
0
    return;
88
0
  }
89
90
0
  ngtcp2_mem_free(pmtud->mem, pmtud);
91
0
}
92
93
0
size_t ngtcp2_pmtud_probelen(ngtcp2_pmtud *pmtud) {
94
0
  assert(pmtud->mtu_idx < pmtud->probeslen);
95
96
0
  return pmtud->probes[pmtud->mtu_idx];
97
0
}
98
99
void ngtcp2_pmtud_probe_sent(ngtcp2_pmtud *pmtud, ngtcp2_duration pto,
100
0
                             ngtcp2_tstamp ts) {
101
0
  ngtcp2_tstamp timeout;
102
103
0
  if (++pmtud->num_pkts_sent < NGTCP2_PMTUD_PROBE_NUM_MAX) {
104
0
    timeout = pto;
105
0
  } else {
106
0
    timeout = 3 * pto;
107
0
  }
108
109
0
  pmtud->expiry = ts + timeout;
110
0
}
111
112
0
int ngtcp2_pmtud_require_probe(ngtcp2_pmtud *pmtud) {
113
0
  return pmtud->expiry == UINT64_MAX;
114
0
}
115
116
0
static void pmtud_next_probe(ngtcp2_pmtud *pmtud) {
117
0
  assert(pmtud->mtu_idx < pmtud->probeslen);
118
119
0
  ++pmtud->mtu_idx;
120
0
  pmtud->num_pkts_sent = 0;
121
0
  pmtud->expiry = UINT64_MAX;
122
123
0
  for (; pmtud->mtu_idx < pmtud->probeslen; ++pmtud->mtu_idx) {
124
0
    if (pmtud->probes[pmtud->mtu_idx] <= pmtud->max_udp_payload_size ||
125
0
        pmtud->probes[pmtud->mtu_idx] > pmtud->hard_max_udp_payload_size) {
126
0
      continue;
127
0
    }
128
129
0
    if (pmtud->probes[pmtud->mtu_idx] < pmtud->min_fail_udp_payload_size) {
130
0
      break;
131
0
    }
132
0
  }
133
0
}
134
135
0
void ngtcp2_pmtud_probe_success(ngtcp2_pmtud *pmtud, size_t payloadlen) {
136
0
  pmtud->max_udp_payload_size =
137
0
    ngtcp2_max_size(pmtud->max_udp_payload_size, payloadlen);
138
139
0
  assert(pmtud->mtu_idx < pmtud->probeslen);
140
141
0
  if (pmtud->probes[pmtud->mtu_idx] > pmtud->max_udp_payload_size) {
142
0
    return;
143
0
  }
144
145
0
  pmtud_next_probe(pmtud);
146
0
}
147
148
0
void ngtcp2_pmtud_handle_expiry(ngtcp2_pmtud *pmtud, ngtcp2_tstamp ts) {
149
0
  if (ts < pmtud->expiry) {
150
0
    return;
151
0
  }
152
153
0
  pmtud->expiry = UINT64_MAX;
154
155
0
  if (pmtud->num_pkts_sent < NGTCP2_PMTUD_PROBE_NUM_MAX) {
156
0
    return;
157
0
  }
158
159
0
  pmtud->min_fail_udp_payload_size = ngtcp2_min_size(
160
0
    pmtud->min_fail_udp_payload_size, pmtud->probes[pmtud->mtu_idx]);
161
162
0
  pmtud_next_probe(pmtud);
163
0
}
164
165
0
int ngtcp2_pmtud_finished(ngtcp2_pmtud *pmtud) {
166
0
  return pmtud->mtu_idx >= pmtud->probeslen;
167
0
}