1 | //===-- SocketAddress.cpp -------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Note: This file is used on Darwin by debugserver, so it needs to remain as |
10 | // self contained as possible, and devoid of references to LLVM unless |
11 | // there is compelling reason. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #if defined(_MSC_VER) |
16 | #define _WINSOCK_DEPRECATED_NO_WARNINGS |
17 | #endif |
18 | |
19 | #include "lldb/Host/SocketAddress.h" |
20 | #include <cstddef> |
21 | #include <cstdio> |
22 | |
23 | #if !defined(_WIN32) |
24 | #include <arpa/inet.h> |
25 | #endif |
26 | |
27 | #include <cassert> |
28 | #include <cstring> |
29 | |
30 | #include "lldb/Host/PosixApi.h" |
31 | |
32 | // WindowsXP needs an inet_ntop implementation |
33 | #ifdef _WIN32 |
34 | |
35 | #ifndef INET6_ADDRSTRLEN // might not be defined in older Windows SDKs |
36 | #define INET6_ADDRSTRLEN 46 |
37 | #endif |
38 | |
39 | // TODO: implement shortened form "::" for runs of zeros |
40 | const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) { |
41 | if (size == 0) { |
42 | return nullptr; |
43 | } |
44 | |
45 | switch (af) { |
46 | case AF_INET: { |
47 | { |
48 | const char *formatted = inet_ntoa(*static_cast<const in_addr *>(src)); |
49 | if (formatted && strlen(formatted) < static_cast<size_t>(size)) { |
50 | return ::strcpy(dst, formatted); |
51 | } |
52 | } |
53 | return nullptr; |
54 | case AF_INET6: { |
55 | char tmp[INET6_ADDRSTRLEN] = {0}; |
56 | const uint16_t *src16 = static_cast<const uint16_t *>(src); |
57 | int full_size = ::snprintf( |
58 | tmp, sizeof(tmp), "%x:%x:%x:%x:%x:%x:%x:%x" , ntohs(src16[0]), |
59 | ntohs(src16[1]), ntohs(src16[2]), ntohs(src16[3]), ntohs(src16[4]), |
60 | ntohs(src16[5]), ntohs(src16[6]), ntohs(src16[7])); |
61 | if (full_size < static_cast<int>(size)) { |
62 | return ::strcpy(dst, tmp); |
63 | } |
64 | return nullptr; |
65 | } |
66 | } |
67 | } |
68 | return nullptr; |
69 | } |
70 | #endif |
71 | |
72 | using namespace lldb_private; |
73 | |
74 | // SocketAddress constructor |
75 | SocketAddress::SocketAddress() { Clear(); } |
76 | |
77 | SocketAddress::SocketAddress(const struct sockaddr &s) { m_socket_addr.sa = s; } |
78 | |
79 | SocketAddress::SocketAddress(const struct sockaddr_in &s) { |
80 | m_socket_addr.sa_ipv4 = s; |
81 | } |
82 | |
83 | SocketAddress::SocketAddress(const struct sockaddr_in6 &s) { |
84 | m_socket_addr.sa_ipv6 = s; |
85 | } |
86 | |
87 | SocketAddress::SocketAddress(const struct sockaddr_storage &s) { |
88 | m_socket_addr.sa_storage = s; |
89 | } |
90 | |
91 | SocketAddress::SocketAddress(const struct addrinfo *addr_info) { |
92 | *this = addr_info; |
93 | } |
94 | |
95 | // Destructor |
96 | SocketAddress::~SocketAddress() = default; |
97 | |
98 | void SocketAddress::Clear() { |
99 | memset(s: &m_socket_addr, c: 0, n: sizeof(m_socket_addr)); |
100 | } |
101 | |
102 | bool SocketAddress::IsValid() const { return GetLength() != 0; } |
103 | |
104 | static socklen_t GetFamilyLength(sa_family_t family) { |
105 | switch (family) { |
106 | case AF_INET: |
107 | return sizeof(struct sockaddr_in); |
108 | case AF_INET6: |
109 | return sizeof(struct sockaddr_in6); |
110 | } |
111 | assert(0 && "Unsupported address family" ); |
112 | return 0; |
113 | } |
114 | |
115 | socklen_t SocketAddress::GetLength() const { |
116 | #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ |
117 | defined(__OpenBSD__) |
118 | return m_socket_addr.sa.sa_len; |
119 | #else |
120 | return GetFamilyLength(family: GetFamily()); |
121 | #endif |
122 | } |
123 | |
124 | socklen_t SocketAddress::GetMaxLength() { return sizeof(sockaddr_t); } |
125 | |
126 | sa_family_t SocketAddress::GetFamily() const { |
127 | return m_socket_addr.sa.sa_family; |
128 | } |
129 | |
130 | void SocketAddress::SetFamily(sa_family_t family) { |
131 | m_socket_addr.sa.sa_family = family; |
132 | #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ |
133 | defined(__OpenBSD__) |
134 | m_socket_addr.sa.sa_len = GetFamilyLength(family); |
135 | #endif |
136 | } |
137 | |
138 | std::string SocketAddress::GetIPAddress() const { |
139 | char str[INET6_ADDRSTRLEN] = {0}; |
140 | switch (GetFamily()) { |
141 | case AF_INET: |
142 | if (inet_ntop(af: GetFamily(), cp: &m_socket_addr.sa_ipv4.sin_addr, buf: str, |
143 | len: sizeof(str))) |
144 | return str; |
145 | break; |
146 | case AF_INET6: |
147 | if (inet_ntop(af: GetFamily(), cp: &m_socket_addr.sa_ipv6.sin6_addr, buf: str, |
148 | len: sizeof(str))) |
149 | return str; |
150 | break; |
151 | } |
152 | return "" ; |
153 | } |
154 | |
155 | uint16_t SocketAddress::GetPort() const { |
156 | switch (GetFamily()) { |
157 | case AF_INET: |
158 | return ntohs(netshort: m_socket_addr.sa_ipv4.sin_port); |
159 | case AF_INET6: |
160 | return ntohs(netshort: m_socket_addr.sa_ipv6.sin6_port); |
161 | } |
162 | return 0; |
163 | } |
164 | |
165 | bool SocketAddress::SetPort(uint16_t port) { |
166 | switch (GetFamily()) { |
167 | case AF_INET: |
168 | m_socket_addr.sa_ipv4.sin_port = htons(hostshort: port); |
169 | return true; |
170 | |
171 | case AF_INET6: |
172 | m_socket_addr.sa_ipv6.sin6_port = htons(hostshort: port); |
173 | return true; |
174 | } |
175 | return false; |
176 | } |
177 | |
178 | // SocketAddress assignment operator |
179 | const SocketAddress &SocketAddress:: |
180 | operator=(const struct addrinfo *addr_info) { |
181 | Clear(); |
182 | if (addr_info && addr_info->ai_addr && addr_info->ai_addrlen > 0 && |
183 | size_t(addr_info->ai_addrlen) <= sizeof m_socket_addr) { |
184 | ::memcpy(dest: &m_socket_addr, src: addr_info->ai_addr, n: addr_info->ai_addrlen); |
185 | } |
186 | return *this; |
187 | } |
188 | |
189 | const SocketAddress &SocketAddress::operator=(const struct sockaddr &s) { |
190 | m_socket_addr.sa = s; |
191 | return *this; |
192 | } |
193 | |
194 | const SocketAddress &SocketAddress::operator=(const struct sockaddr_in &s) { |
195 | m_socket_addr.sa_ipv4 = s; |
196 | return *this; |
197 | } |
198 | |
199 | const SocketAddress &SocketAddress::operator=(const struct sockaddr_in6 &s) { |
200 | m_socket_addr.sa_ipv6 = s; |
201 | return *this; |
202 | } |
203 | |
204 | const SocketAddress &SocketAddress:: |
205 | operator=(const struct sockaddr_storage &s) { |
206 | m_socket_addr.sa_storage = s; |
207 | return *this; |
208 | } |
209 | |
210 | bool SocketAddress::getaddrinfo(const char *host, const char *service, |
211 | int ai_family, int ai_socktype, int ai_protocol, |
212 | int ai_flags) { |
213 | Clear(); |
214 | |
215 | auto addresses = GetAddressInfo(hostname: host, servname: service, ai_family, ai_socktype, |
216 | ai_protocol, ai_flags); |
217 | if (!addresses.empty()) |
218 | *this = addresses[0]; |
219 | return IsValid(); |
220 | } |
221 | |
222 | std::vector<SocketAddress> |
223 | SocketAddress::GetAddressInfo(const char *hostname, const char *servname, |
224 | int ai_family, int ai_socktype, int ai_protocol, |
225 | int ai_flags) { |
226 | std::vector<SocketAddress> addr_list; |
227 | |
228 | struct addrinfo hints; |
229 | memset(s: &hints, c: 0, n: sizeof(hints)); |
230 | hints.ai_family = ai_family; |
231 | hints.ai_socktype = ai_socktype; |
232 | hints.ai_protocol = ai_protocol; |
233 | hints.ai_flags = ai_flags; |
234 | |
235 | struct addrinfo *service_info_list = nullptr; |
236 | int err = ::getaddrinfo(name: hostname, service: servname, req: &hints, pai: &service_info_list); |
237 | if (err == 0 && service_info_list) { |
238 | for (struct addrinfo *service_ptr = service_info_list; |
239 | service_ptr != nullptr; service_ptr = service_ptr->ai_next) { |
240 | addr_list.emplace_back(args: SocketAddress(service_ptr)); |
241 | } |
242 | } |
243 | |
244 | if (service_info_list) |
245 | ::freeaddrinfo(ai: service_info_list); |
246 | return addr_list; |
247 | } |
248 | |
249 | bool SocketAddress::SetToLocalhost(sa_family_t family, uint16_t port) { |
250 | switch (family) { |
251 | case AF_INET: |
252 | SetFamily(AF_INET); |
253 | if (SetPort(port)) { |
254 | m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
255 | return true; |
256 | } |
257 | break; |
258 | |
259 | case AF_INET6: |
260 | SetFamily(AF_INET6); |
261 | if (SetPort(port)) { |
262 | m_socket_addr.sa_ipv6.sin6_addr = in6addr_loopback; |
263 | return true; |
264 | } |
265 | break; |
266 | } |
267 | Clear(); |
268 | return false; |
269 | } |
270 | |
271 | bool SocketAddress::SetToAnyAddress(sa_family_t family, uint16_t port) { |
272 | switch (family) { |
273 | case AF_INET: |
274 | SetFamily(AF_INET); |
275 | if (SetPort(port)) { |
276 | m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl(INADDR_ANY); |
277 | return true; |
278 | } |
279 | break; |
280 | |
281 | case AF_INET6: |
282 | SetFamily(AF_INET6); |
283 | if (SetPort(port)) { |
284 | m_socket_addr.sa_ipv6.sin6_addr = in6addr_any; |
285 | return true; |
286 | } |
287 | break; |
288 | } |
289 | Clear(); |
290 | return false; |
291 | } |
292 | |
293 | bool SocketAddress::IsAnyAddr() const { |
294 | return (GetFamily() == AF_INET) |
295 | ? m_socket_addr.sa_ipv4.sin_addr.s_addr == htonl(INADDR_ANY) |
296 | : 0 == memcmp(s1: &m_socket_addr.sa_ipv6.sin6_addr, s2: &in6addr_any, n: 16); |
297 | } |
298 | |
299 | bool SocketAddress::IsLocalhost() const { |
300 | return (GetFamily() == AF_INET) |
301 | ? m_socket_addr.sa_ipv4.sin_addr.s_addr == htonl(INADDR_LOOPBACK) |
302 | : 0 == memcmp(s1: &m_socket_addr.sa_ipv6.sin6_addr, s2: &in6addr_loopback, |
303 | n: 16); |
304 | } |
305 | |
306 | bool SocketAddress::operator==(const SocketAddress &rhs) const { |
307 | if (GetFamily() != rhs.GetFamily()) |
308 | return false; |
309 | if (GetLength() != rhs.GetLength()) |
310 | return false; |
311 | switch (GetFamily()) { |
312 | case AF_INET: |
313 | return m_socket_addr.sa_ipv4.sin_addr.s_addr == |
314 | rhs.m_socket_addr.sa_ipv4.sin_addr.s_addr; |
315 | case AF_INET6: |
316 | return 0 == memcmp(s1: &m_socket_addr.sa_ipv6.sin6_addr, |
317 | s2: &rhs.m_socket_addr.sa_ipv6.sin6_addr, n: 16); |
318 | } |
319 | return false; |
320 | } |
321 | |
322 | bool SocketAddress::operator!=(const SocketAddress &rhs) const { |
323 | return !(*this == rhs); |
324 | } |
325 | |