/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(¶ms->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(¶ms->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 |