Coverage Report

Created: 2025-12-30 08:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/quic/preferredaddress.cc
Line
Count
Source
1
#if HAVE_OPENSSL
2
#include "guard.h"
3
#ifndef OPENSSL_NO_QUIC
4
#include <env-inl.h>
5
#include <ngtcp2/ngtcp2.h>
6
#include <node_errors.h>
7
#include <node_realm-inl.h>
8
#include <node_sockaddr-inl.h>
9
#include <util-inl.h>
10
#include <uv.h>
11
#include <v8.h>
12
#include "cid.h"
13
#include "preferredaddress.h"
14
15
namespace node {
16
17
using v8::Just;
18
using v8::Local;
19
using v8::Maybe;
20
using v8::Value;
21
22
namespace quic {
23
24
namespace {
25
template <int FAMILY>
26
std::optional<const PreferredAddress::AddressInfo> get_address_info(
27
0
    const ngtcp2_preferred_addr& paddr) {
28
0
  PreferredAddress::AddressInfo address;
29
0
  address.family = FAMILY;
30
0
  if constexpr (FAMILY == AF_INET) {
31
0
    if (!paddr.ipv4_present) return std::nullopt;
32
0
    address.port = paddr.ipv4.sin_port;
33
0
    if (uv_inet_ntop(
34
0
            FAMILY, &paddr.ipv4.sin_addr, address.host, sizeof(address.host)) ==
35
0
        0) {
36
0
      address.address = address.host;
37
0
    }
38
0
  } else {
39
0
    if (!paddr.ipv6_present) return std::nullopt;
40
0
    address.port = paddr.ipv6.sin6_port;
41
0
    if (uv_inet_ntop(FAMILY,
42
0
                     &paddr.ipv6.sin6_addr,
43
0
                     address.host,
44
0
                     sizeof(address.host)) == 0) {
45
0
      address.address = address.host;
46
0
    }
47
0
  }
48
0
  return address;
49
0
}
Unexecuted instantiation: preferredaddress.cc:std::__1::optional<node::quic::PreferredAddress::AddressInfo const> node::quic::(anonymous namespace)::get_address_info<2>(ngtcp2_preferred_addr const&)
Unexecuted instantiation: preferredaddress.cc:std::__1::optional<node::quic::PreferredAddress::AddressInfo const> node::quic::(anonymous namespace)::get_address_info<10>(ngtcp2_preferred_addr const&)
50
51
template <int FAMILY>
52
void copy_to_transport_params(ngtcp2_transport_params* params,
53
0
                              const sockaddr* addr) {
54
0
  params->preferred_addr_present = 1;
55
0
  if constexpr (FAMILY == AF_INET) {
56
0
    params->preferred_addr.ipv4_present = 1;
57
0
    memcpy(&params->preferred_addr.ipv4, addr, sizeof(sockaddr_in));
58
0
  } else {
59
0
    DCHECK_EQ(FAMILY, AF_INET6);
60
0
    params->preferred_addr.ipv6_present = 1;
61
0
    memcpy(&params->preferred_addr.ipv6, addr, sizeof(sockaddr_in6));
62
0
  }
63
0
}
Unexecuted instantiation: preferredaddress.cc:void node::quic::(anonymous namespace)::copy_to_transport_params<2>(ngtcp2_transport_params*, sockaddr const*)
Unexecuted instantiation: preferredaddress.cc:void node::quic::(anonymous namespace)::copy_to_transport_params<10>(ngtcp2_transport_params*, sockaddr const*)
64
65
bool resolve(const PreferredAddress::AddressInfo& address,
66
0
             uv_getaddrinfo_t* req) {
67
0
  addrinfo hints{};
68
0
  hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
69
0
  hints.ai_family = address.family;
70
0
  hints.ai_socktype = SOCK_DGRAM;
71
72
  // ngtcp2 requires the selection of the preferred address
73
  // to be synchronous, which means we have to do a sync resolve
74
  // using uv_getaddrinfo here.
75
0
  return uv_getaddrinfo(nullptr,
76
0
                        req,
77
0
                        nullptr,
78
0
                        address.host,
79
0
                        std::to_string(address.port).data(),
80
0
                        &hints) == 0 &&
81
0
         req->addrinfo != nullptr;
82
0
}
83
}  // namespace
84
85
PreferredAddress::PreferredAddress(ngtcp2_path* dest,
86
                                   const ngtcp2_preferred_addr* paddr)
87
0
    : dest_(dest), paddr_(paddr) {
88
0
  DCHECK_NOT_NULL(paddr);
89
0
  DCHECK_NOT_NULL(dest);
90
0
}
91
92
std::optional<const PreferredAddress::AddressInfo> PreferredAddress::ipv4()
93
0
    const {
94
0
  return get_address_info<AF_INET>(*paddr_);
95
0
}
96
97
std::optional<const PreferredAddress::AddressInfo> PreferredAddress::ipv6()
98
0
    const {
99
0
  return get_address_info<AF_INET6>(*paddr_);
100
0
}
101
102
0
void PreferredAddress::Use(const AddressInfo& address) {
103
0
  uv_getaddrinfo_t req;
104
0
  auto on_exit = OnScopeLeave([&] {
105
0
    if (req.addrinfo != nullptr) uv_freeaddrinfo(req.addrinfo);
106
0
  });
107
108
0
  if (resolve(address, &req)) {
109
0
    DCHECK_NOT_NULL(req.addrinfo);
110
0
    dest_->remote.addrlen = req.addrinfo->ai_addrlen;
111
0
    memcpy(dest_->remote.addr, req.addrinfo->ai_addr, req.addrinfo->ai_addrlen);
112
0
  }
113
0
}
114
115
void PreferredAddress::Set(ngtcp2_transport_params* params,
116
0
                           const sockaddr* addr) {
117
0
  DCHECK_NOT_NULL(params);
118
0
  DCHECK_NOT_NULL(addr);
119
0
  switch (addr->sa_family) {
120
0
    case AF_INET:
121
0
      return copy_to_transport_params<AF_INET>(params, addr);
122
0
    case AF_INET6:
123
0
      return copy_to_transport_params<AF_INET6>(params, addr);
124
0
    default:
125
0
      UNREACHABLE("Unreachable");
126
0
  }
127
  // Any other value is just ignored.
128
0
}
129
130
Maybe<PreferredAddress::Policy> PreferredAddress::tryGetPolicy(
131
0
    Environment* env, Local<Value> value) {
132
0
  return value->IsUndefined() ? Just(Policy::USE_PREFERRED)
133
0
                              : Just(FromV8Value<Policy>(value));
134
0
}
135
136
0
void PreferredAddress::Initialize(Environment* env, Local<v8::Object> target) {
137
  // The QUIC_* constants are expected to be exported out to be used on
138
  // the JavaScript side of the API.
139
0
  static constexpr auto PREFERRED_ADDRESS_USE =
140
0
      static_cast<uint8_t>(Policy::USE_PREFERRED);
141
0
  static constexpr auto PREFERRED_ADDRESS_IGNORE =
142
0
      static_cast<uint8_t>(Policy::IGNORE_PREFERRED);
143
0
  static constexpr auto DEFAULT_PREFERRED_ADDRESS_POLICY =
144
0
      static_cast<uint8_t>(Policy::USE_PREFERRED);
145
146
0
  NODE_DEFINE_CONSTANT(target, PREFERRED_ADDRESS_IGNORE);
147
0
  NODE_DEFINE_CONSTANT(target, PREFERRED_ADDRESS_USE);
148
0
  NODE_DEFINE_CONSTANT(target, DEFAULT_PREFERRED_ADDRESS_POLICY);
149
0
}
150
151
0
const CID PreferredAddress::cid() const {
152
0
  return CID(&paddr_->cid);
153
0
}
154
155
}  // namespace quic
156
}  // namespace node
157
158
#endif  // OPENSSL_NO_QUIC
159
#endif  // HAVE_OPENSSL