1 | /* |
2 | * Copyright 2014-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #ifndef __STDC_FORMAT_MACROS |
18 | #define __STDC_FORMAT_MACROS |
19 | #endif |
20 | |
21 | #include <folly/SocketAddress.h> |
22 | |
23 | #include <cerrno> |
24 | #include <cstdio> |
25 | #include <cstring> |
26 | #include <sstream> |
27 | #include <string> |
28 | #include <system_error> |
29 | |
30 | #include <boost/functional/hash.hpp> |
31 | |
32 | #include <folly/CppAttributes.h> |
33 | #include <folly/Exception.h> |
34 | #include <folly/Format.h> |
35 | #include <folly/hash/Hash.h> |
36 | #include <folly/net/NetOps.h> |
37 | #include <folly/net/NetworkSocket.h> |
38 | |
39 | namespace { |
40 | |
41 | /** |
42 | * A structure to free a struct addrinfo when it goes out of scope. |
43 | */ |
44 | struct ScopedAddrInfo { |
45 | explicit ScopedAddrInfo(struct addrinfo* addrinfo) : info(addrinfo) {} |
46 | ~ScopedAddrInfo() { |
47 | freeaddrinfo(info); |
48 | } |
49 | |
50 | struct addrinfo* info; |
51 | }; |
52 | |
53 | /** |
54 | * A simple data structure for parsing a host-and-port string. |
55 | * |
56 | * Accepts a string of the form "<host>:<port>" or just "<port>", |
57 | * and contains two string pointers to the host and the port portion of the |
58 | * string. |
59 | * |
60 | * The HostAndPort may contain pointers into the original string. It is |
61 | * responsible for the user to ensure that the input string is valid for the |
62 | * lifetime of the HostAndPort structure. |
63 | */ |
64 | struct HostAndPort { |
65 | HostAndPort(const char* str, bool hostRequired) |
66 | : host(nullptr), port(nullptr), allocated(nullptr) { |
67 | // Look for the last colon |
68 | const char* colon = strrchr(str, ':'); |
69 | if (colon == nullptr) { |
70 | // No colon, just a port number. |
71 | if (hostRequired) { |
72 | throw std::invalid_argument( |
73 | "expected a host and port string of the " |
74 | "form \"<host>:<port>\"" ); |
75 | } |
76 | port = str; |
77 | return; |
78 | } |
79 | |
80 | // We have to make a copy of the string so we can modify it |
81 | // and change the colon to a NUL terminator. |
82 | allocated = strdup(str); |
83 | if (!allocated) { |
84 | throw std::bad_alloc(); |
85 | } |
86 | |
87 | char* allocatedColon = allocated + (colon - str); |
88 | *allocatedColon = '\0'; |
89 | host = allocated; |
90 | port = allocatedColon + 1; |
91 | // bracketed IPv6 address, remove the brackets |
92 | // allocatedColon[-1] is fine, as allocatedColon >= host and |
93 | // *allocatedColon != *host therefore allocatedColon > host |
94 | if (*host == '[' && allocatedColon[-1] == ']') { |
95 | allocatedColon[-1] = '\0'; |
96 | ++host; |
97 | } |
98 | } |
99 | |
100 | ~HostAndPort() { |
101 | free(allocated); |
102 | } |
103 | |
104 | const char* host; |
105 | const char* port; |
106 | char* allocated; |
107 | }; |
108 | |
109 | } // namespace |
110 | |
111 | namespace folly { |
112 | |
113 | bool SocketAddress::isPrivateAddress() const { |
114 | auto family = getFamily(); |
115 | if (family == AF_INET || family == AF_INET6) { |
116 | return storage_.addr.isPrivate() || |
117 | (storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal()); |
118 | } else if (external_) { |
119 | // Unix addresses are always local to a host. Return true, |
120 | // since this conforms to the semantics of returning true for IP loopback |
121 | // addresses. |
122 | return true; |
123 | } |
124 | return false; |
125 | } |
126 | |
127 | bool SocketAddress::isLoopbackAddress() const { |
128 | auto family = getFamily(); |
129 | if (family == AF_INET || family == AF_INET6) { |
130 | return storage_.addr.isLoopback(); |
131 | } else if (external_) { |
132 | // Return true for UNIX addresses, since they are always local to a host. |
133 | return true; |
134 | } |
135 | return false; |
136 | } |
137 | |
138 | void SocketAddress::setFromHostPort(const char* host, uint16_t port) { |
139 | ScopedAddrInfo results(getAddrInfo(host, port, 0)); |
140 | setFromAddrInfo(results.info); |
141 | } |
142 | |
143 | void SocketAddress::setFromIpPort(const char* ip, uint16_t port) { |
144 | ScopedAddrInfo results(getAddrInfo(ip, port, AI_NUMERICHOST)); |
145 | setFromAddrInfo(results.info); |
146 | } |
147 | |
148 | void SocketAddress::setFromIpAddrPort(const IPAddress& ipAddr, uint16_t port) { |
149 | if (external_) { |
150 | storage_.un.free(); |
151 | external_ = false; |
152 | } |
153 | storage_.addr = ipAddr; |
154 | port_ = port; |
155 | } |
156 | |
157 | void SocketAddress::setFromLocalPort(uint16_t port) { |
158 | ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG)); |
159 | setFromLocalAddr(results.info); |
160 | } |
161 | |
162 | void SocketAddress::setFromLocalPort(const char* port) { |
163 | ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG)); |
164 | setFromLocalAddr(results.info); |
165 | } |
166 | |
167 | void SocketAddress::setFromLocalIpPort(const char* addressAndPort) { |
168 | HostAndPort hp(addressAndPort, false); |
169 | ScopedAddrInfo results( |
170 | getAddrInfo(hp.host, hp.port, AI_NUMERICHOST | AI_ADDRCONFIG)); |
171 | setFromLocalAddr(results.info); |
172 | } |
173 | |
174 | void SocketAddress::setFromIpPort(const char* addressAndPort) { |
175 | HostAndPort hp(addressAndPort, true); |
176 | ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, AI_NUMERICHOST)); |
177 | setFromAddrInfo(results.info); |
178 | } |
179 | |
180 | void SocketAddress::setFromHostPort(const char* hostAndPort) { |
181 | HostAndPort hp(hostAndPort, true); |
182 | ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, 0)); |
183 | setFromAddrInfo(results.info); |
184 | } |
185 | |
186 | int SocketAddress::getPortFrom(const struct sockaddr* address) { |
187 | switch (address->sa_family) { |
188 | case AF_INET: |
189 | return ntohs(((sockaddr_in*)address)->sin_port); |
190 | |
191 | case AF_INET6: |
192 | return ntohs(((sockaddr_in6*)address)->sin6_port); |
193 | |
194 | default: |
195 | return -1; |
196 | } |
197 | } |
198 | |
199 | const char* SocketAddress::getFamilyNameFrom( |
200 | const struct sockaddr* address, |
201 | const char* defaultResult) { |
202 | #define GETFAMILYNAMEFROM_IMPL(Family) \ |
203 | case Family: \ |
204 | return #Family |
205 | |
206 | switch (address->sa_family) { |
207 | GETFAMILYNAMEFROM_IMPL(AF_INET); |
208 | GETFAMILYNAMEFROM_IMPL(AF_INET6); |
209 | GETFAMILYNAMEFROM_IMPL(AF_UNIX); |
210 | GETFAMILYNAMEFROM_IMPL(AF_UNSPEC); |
211 | |
212 | default: |
213 | return defaultResult; |
214 | } |
215 | |
216 | #undef GETFAMILYNAMEFROM_IMPL |
217 | } |
218 | |
219 | void SocketAddress::setFromPath(StringPiece path) { |
220 | // Before we touch storage_, check to see if the length is too big. |
221 | // Note that "storage_.un.addr->sun_path" may not be safe to evaluate here, |
222 | // but sizeof() just uses its type, and does't evaluate it. |
223 | if (path.size() > sizeof(storage_.un.addr->sun_path)) { |
224 | throw std::invalid_argument( |
225 | "socket path too large to fit into sockaddr_un" ); |
226 | } |
227 | |
228 | if (!external_) { |
229 | storage_.un.init(); |
230 | external_ = true; |
231 | } |
232 | |
233 | size_t len = path.size(); |
234 | storage_.un.len = socklen_t(offsetof(struct sockaddr_un, sun_path) + len); |
235 | memcpy(storage_.un.addr->sun_path, path.data(), len); |
236 | // If there is room, put a terminating NUL byte in sun_path. In general the |
237 | // path should be NUL terminated, although getsockname() and getpeername() |
238 | // may return Unix socket addresses with paths that fit exactly in sun_path |
239 | // with no terminating NUL. |
240 | if (len < sizeof(storage_.un.addr->sun_path)) { |
241 | storage_.un.addr->sun_path[len] = '\0'; |
242 | } |
243 | } |
244 | |
245 | void SocketAddress::setFromPeerAddress(NetworkSocket socket) { |
246 | setFromSocket(socket, netops::getpeername); |
247 | } |
248 | |
249 | void SocketAddress::setFromLocalAddress(NetworkSocket socket) { |
250 | setFromSocket(socket, netops::getsockname); |
251 | } |
252 | |
253 | void SocketAddress::setFromSockaddr(const struct sockaddr* address) { |
254 | uint16_t port; |
255 | |
256 | if (address->sa_family == AF_INET) { |
257 | port = ntohs(((sockaddr_in*)address)->sin_port); |
258 | } else if (address->sa_family == AF_INET6) { |
259 | port = ntohs(((sockaddr_in6*)address)->sin6_port); |
260 | } else if (address->sa_family == AF_UNIX) { |
261 | // We need an explicitly specified length for AF_UNIX addresses, |
262 | // to be able to distinguish anonymous addresses from addresses |
263 | // in Linux's abstract namespace. |
264 | throw std::invalid_argument( |
265 | "SocketAddress::setFromSockaddr(): the address " |
266 | "length must be explicitly specified when " |
267 | "setting AF_UNIX addresses" ); |
268 | } else { |
269 | throw std::invalid_argument( |
270 | "SocketAddress::setFromSockaddr() called " |
271 | "with unsupported address type" ); |
272 | } |
273 | |
274 | setFromIpAddrPort(folly::IPAddress(address), port); |
275 | } |
276 | |
277 | void SocketAddress::setFromSockaddr( |
278 | const struct sockaddr* address, |
279 | socklen_t addrlen) { |
280 | // Check the length to make sure we can access address->sa_family |
281 | if (addrlen < |
282 | (offsetof(struct sockaddr, sa_family) + sizeof(address->sa_family))) { |
283 | throw std::invalid_argument( |
284 | "SocketAddress::setFromSockaddr() called " |
285 | "with length too short for a sockaddr" ); |
286 | } |
287 | |
288 | if (address->sa_family == AF_INET) { |
289 | if (addrlen < sizeof(struct sockaddr_in)) { |
290 | throw std::invalid_argument( |
291 | "SocketAddress::setFromSockaddr() called " |
292 | "with length too short for a sockaddr_in" ); |
293 | } |
294 | setFromSockaddr(reinterpret_cast<const struct sockaddr_in*>(address)); |
295 | } else if (address->sa_family == AF_INET6) { |
296 | if (addrlen < sizeof(struct sockaddr_in6)) { |
297 | throw std::invalid_argument( |
298 | "SocketAddress::setFromSockaddr() called " |
299 | "with length too short for a sockaddr_in6" ); |
300 | } |
301 | setFromSockaddr(reinterpret_cast<const struct sockaddr_in6*>(address)); |
302 | } else if (address->sa_family == AF_UNIX) { |
303 | setFromSockaddr( |
304 | reinterpret_cast<const struct sockaddr_un*>(address), addrlen); |
305 | } else { |
306 | throw std::invalid_argument( |
307 | "SocketAddress::setFromSockaddr() called " |
308 | "with unsupported address type" ); |
309 | } |
310 | } |
311 | |
312 | void SocketAddress::setFromSockaddr(const struct sockaddr_in* address) { |
313 | assert(address->sin_family == AF_INET); |
314 | setFromSockaddr((sockaddr*)address); |
315 | } |
316 | |
317 | void SocketAddress::setFromSockaddr(const struct sockaddr_in6* address) { |
318 | assert(address->sin6_family == AF_INET6); |
319 | setFromSockaddr((sockaddr*)address); |
320 | } |
321 | |
322 | void SocketAddress::setFromSockaddr( |
323 | const struct sockaddr_un* address, |
324 | socklen_t addrlen) { |
325 | assert(address->sun_family == AF_UNIX); |
326 | if (addrlen > sizeof(struct sockaddr_un)) { |
327 | throw std::invalid_argument( |
328 | "SocketAddress::setFromSockaddr() called " |
329 | "with length too long for a sockaddr_un" ); |
330 | } |
331 | |
332 | if (!external_) { |
333 | storage_.un.init(); |
334 | } |
335 | external_ = true; |
336 | memcpy(storage_.un.addr, address, size_t(addrlen)); |
337 | updateUnixAddressLength(addrlen); |
338 | |
339 | // Fill the rest with 0s, just for safety |
340 | if (addrlen < sizeof(struct sockaddr_un)) { |
341 | char* p = reinterpret_cast<char*>(storage_.un.addr); |
342 | memset(p + addrlen, 0, sizeof(struct sockaddr_un) - addrlen); |
343 | } |
344 | } |
345 | |
346 | const folly::IPAddress& SocketAddress::getIPAddress() const { |
347 | auto family = getFamily(); |
348 | if (family != AF_INET && family != AF_INET6) { |
349 | throw InvalidAddressFamilyException(family); |
350 | } |
351 | return storage_.addr; |
352 | } |
353 | |
354 | socklen_t SocketAddress::getActualSize() const { |
355 | if (external_) { |
356 | return storage_.un.len; |
357 | } |
358 | switch (getFamily()) { |
359 | case AF_UNSPEC: |
360 | case AF_INET: |
361 | return sizeof(struct sockaddr_in); |
362 | case AF_INET6: |
363 | return sizeof(struct sockaddr_in6); |
364 | default: |
365 | throw std::invalid_argument( |
366 | "SocketAddress::getActualSize() called " |
367 | "with unrecognized address family" ); |
368 | } |
369 | } |
370 | |
371 | std::string SocketAddress::getFullyQualified() const { |
372 | if (!isFamilyInet()) { |
373 | throw std::invalid_argument("Can't get address str for non ip address" ); |
374 | } |
375 | return storage_.addr.toFullyQualified(); |
376 | } |
377 | |
378 | std::string SocketAddress::getAddressStr() const { |
379 | if (!isFamilyInet()) { |
380 | throw std::invalid_argument("Can't get address str for non ip address" ); |
381 | } |
382 | return storage_.addr.str(); |
383 | } |
384 | |
385 | bool SocketAddress::isFamilyInet() const { |
386 | auto family = getFamily(); |
387 | return family == AF_INET || family == AF_INET6; |
388 | } |
389 | |
390 | void SocketAddress::getAddressStr(char* buf, size_t buflen) const { |
391 | auto ret = getAddressStr(); |
392 | size_t len = std::min(buflen - 1, ret.size()); |
393 | memcpy(buf, ret.data(), len); |
394 | buf[len] = '\0'; |
395 | } |
396 | |
397 | uint16_t SocketAddress::getPort() const { |
398 | switch (getFamily()) { |
399 | case AF_INET: |
400 | case AF_INET6: |
401 | return port_; |
402 | default: |
403 | throw std::invalid_argument( |
404 | "SocketAddress::getPort() called on non-IP " |
405 | "address" ); |
406 | } |
407 | } |
408 | |
409 | void SocketAddress::setPort(uint16_t port) { |
410 | switch (getFamily()) { |
411 | case AF_INET: |
412 | case AF_INET6: |
413 | port_ = port; |
414 | return; |
415 | default: |
416 | throw std::invalid_argument( |
417 | "SocketAddress::setPort() called on non-IP " |
418 | "address" ); |
419 | } |
420 | } |
421 | |
422 | void SocketAddress::convertToIPv4() { |
423 | if (!tryConvertToIPv4()) { |
424 | throw std::invalid_argument( |
425 | "convertToIPv4() called on an addresse that is " |
426 | "not an IPv4-mapped address" ); |
427 | } |
428 | } |
429 | |
430 | bool SocketAddress::tryConvertToIPv4() { |
431 | if (!isIPv4Mapped()) { |
432 | return false; |
433 | } |
434 | |
435 | storage_.addr = folly::IPAddress::createIPv4(storage_.addr); |
436 | return true; |
437 | } |
438 | |
439 | bool SocketAddress::mapToIPv6() { |
440 | if (getFamily() != AF_INET) { |
441 | return false; |
442 | } |
443 | |
444 | storage_.addr = folly::IPAddress::createIPv6(storage_.addr); |
445 | return true; |
446 | } |
447 | |
448 | std::string SocketAddress::getHostStr() const { |
449 | return getIpString(0); |
450 | } |
451 | |
452 | std::string SocketAddress::getPath() const { |
453 | if (!external_) { |
454 | throw std::invalid_argument( |
455 | "SocketAddress: attempting to get path " |
456 | "for a non-Unix address" ); |
457 | } |
458 | |
459 | if (storage_.un.pathLength() == 0) { |
460 | // anonymous address |
461 | return std::string(); |
462 | } |
463 | if (storage_.un.addr->sun_path[0] == '\0') { |
464 | // abstract namespace |
465 | return std::string( |
466 | storage_.un.addr->sun_path, size_t(storage_.un.pathLength())); |
467 | } |
468 | |
469 | return std::string( |
470 | storage_.un.addr->sun_path, |
471 | strnlen(storage_.un.addr->sun_path, size_t(storage_.un.pathLength()))); |
472 | } |
473 | |
474 | std::string SocketAddress::describe() const { |
475 | if (external_) { |
476 | if (storage_.un.pathLength() == 0) { |
477 | return "<anonymous unix address>" ; |
478 | } |
479 | |
480 | if (storage_.un.addr->sun_path[0] == '\0') { |
481 | // Linux supports an abstract namespace for unix socket addresses |
482 | return "<abstract unix address>" ; |
483 | } |
484 | |
485 | return std::string( |
486 | storage_.un.addr->sun_path, |
487 | strnlen(storage_.un.addr->sun_path, size_t(storage_.un.pathLength()))); |
488 | } |
489 | switch (getFamily()) { |
490 | case AF_UNSPEC: |
491 | return "<uninitialized address>" ; |
492 | case AF_INET: { |
493 | char buf[NI_MAXHOST + 16]; |
494 | getAddressStr(buf, sizeof(buf)); |
495 | size_t iplen = strlen(buf); |
496 | snprintf(buf + iplen, sizeof(buf) - iplen, ":%" PRIu16, getPort()); |
497 | return buf; |
498 | } |
499 | case AF_INET6: { |
500 | char buf[NI_MAXHOST + 18]; |
501 | buf[0] = '['; |
502 | getAddressStr(buf + 1, sizeof(buf) - 1); |
503 | size_t iplen = strlen(buf); |
504 | snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort()); |
505 | return buf; |
506 | } |
507 | default: { |
508 | char buf[64]; |
509 | snprintf(buf, sizeof(buf), "<unknown address family %d>" , getFamily()); |
510 | return buf; |
511 | } |
512 | } |
513 | } |
514 | |
515 | bool SocketAddress::operator==(const SocketAddress& other) const { |
516 | if (external_ != other.external_ || other.getFamily() != getFamily()) { |
517 | return false; |
518 | } |
519 | if (external_) { |
520 | // anonymous addresses are never equal to any other addresses |
521 | if (storage_.un.pathLength() == 0 || other.storage_.un.pathLength() == 0) { |
522 | return false; |
523 | } |
524 | |
525 | if (storage_.un.len != other.storage_.un.len) { |
526 | return false; |
527 | } |
528 | int cmp = memcmp( |
529 | storage_.un.addr->sun_path, |
530 | other.storage_.un.addr->sun_path, |
531 | size_t(storage_.un.pathLength())); |
532 | return cmp == 0; |
533 | } |
534 | |
535 | switch (getFamily()) { |
536 | case AF_INET: |
537 | case AF_INET6: |
538 | return (other.storage_.addr == storage_.addr) && (other.port_ == port_); |
539 | default: |
540 | throw std::invalid_argument( |
541 | "SocketAddress: unsupported address family " |
542 | "for comparison" ); |
543 | } |
544 | } |
545 | |
546 | bool SocketAddress::prefixMatch( |
547 | const SocketAddress& other, |
548 | unsigned prefixLength) const { |
549 | if (other.getFamily() != getFamily()) { |
550 | return false; |
551 | } |
552 | uint8_t mask_length = 128; |
553 | switch (getFamily()) { |
554 | case AF_INET: |
555 | mask_length = 32; |
556 | FOLLY_FALLTHROUGH; |
557 | case AF_INET6: { |
558 | auto prefix = folly::IPAddress::longestCommonPrefix( |
559 | {storage_.addr, mask_length}, {other.storage_.addr, mask_length}); |
560 | return prefix.second >= prefixLength; |
561 | } |
562 | default: |
563 | return false; |
564 | } |
565 | } |
566 | |
567 | size_t SocketAddress::hash() const { |
568 | size_t seed = folly::hash::twang_mix64(getFamily()); |
569 | |
570 | if (external_) { |
571 | enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) }; |
572 | const char* path = storage_.un.addr->sun_path; |
573 | auto pathLength = storage_.un.pathLength(); |
574 | // TODO: this probably could be made more efficient |
575 | for (off_t n = 0; n < pathLength; ++n) { |
576 | boost::hash_combine(seed, folly::hash::twang_mix64(uint64_t(path[n]))); |
577 | } |
578 | } |
579 | |
580 | switch (getFamily()) { |
581 | case AF_INET: |
582 | case AF_INET6: { |
583 | boost::hash_combine(seed, port_); |
584 | boost::hash_combine(seed, storage_.addr.hash()); |
585 | break; |
586 | } |
587 | case AF_UNIX: |
588 | DCHECK(external_); |
589 | break; |
590 | case AF_UNSPEC: |
591 | default: |
592 | throw std::invalid_argument( |
593 | "SocketAddress: unsupported address family " |
594 | "for hashing" ); |
595 | } |
596 | |
597 | return seed; |
598 | } |
599 | |
600 | struct addrinfo* |
601 | SocketAddress::getAddrInfo(const char* host, uint16_t port, int flags) { |
602 | // getaddrinfo() requires the port number as a string |
603 | char portString[sizeof("65535" )]; |
604 | snprintf(portString, sizeof(portString), "%" PRIu16, port); |
605 | |
606 | return getAddrInfo(host, portString, flags); |
607 | } |
608 | |
609 | struct addrinfo* |
610 | SocketAddress::getAddrInfo(const char* host, const char* port, int flags) { |
611 | struct addrinfo hints; |
612 | memset(&hints, 0, sizeof(hints)); |
613 | hints.ai_family = AF_UNSPEC; |
614 | hints.ai_socktype = SOCK_STREAM; |
615 | hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | flags; |
616 | |
617 | struct addrinfo* results; |
618 | int error = getaddrinfo(host, port, &hints, &results); |
619 | if (error != 0) { |
620 | auto os = folly::sformat( |
621 | "Failed to resolve address for '{}': {} (error={})" , |
622 | host, |
623 | gai_strerror(error), |
624 | error); |
625 | throw std::system_error(error, std::generic_category(), os); |
626 | } |
627 | |
628 | return results; |
629 | } |
630 | |
631 | void SocketAddress::setFromAddrInfo(const struct addrinfo* info) { |
632 | setFromSockaddr(info->ai_addr, socklen_t(info->ai_addrlen)); |
633 | } |
634 | |
635 | void SocketAddress::setFromLocalAddr(const struct addrinfo* info) { |
636 | // If an IPv6 address is present, prefer to use it, since IPv4 addresses |
637 | // can be mapped into IPv6 space. |
638 | for (const struct addrinfo* ai = info; ai != nullptr; ai = ai->ai_next) { |
639 | if (ai->ai_family == AF_INET6) { |
640 | setFromSockaddr(ai->ai_addr, socklen_t(ai->ai_addrlen)); |
641 | return; |
642 | } |
643 | } |
644 | |
645 | // Otherwise, just use the first address in the list. |
646 | setFromSockaddr(info->ai_addr, socklen_t(info->ai_addrlen)); |
647 | } |
648 | |
649 | void SocketAddress::setFromSocket( |
650 | NetworkSocket socket, |
651 | int (*fn)(NetworkSocket, struct sockaddr*, socklen_t*)) { |
652 | // Try to put the address into a local storage buffer. |
653 | sockaddr_storage tmp_sock; |
654 | socklen_t addrLen = sizeof(tmp_sock); |
655 | if (fn(socket, (sockaddr*)&tmp_sock, &addrLen) != 0) { |
656 | folly::throwSystemError("setFromSocket() failed" ); |
657 | } |
658 | |
659 | setFromSockaddr((sockaddr*)&tmp_sock, addrLen); |
660 | } |
661 | |
662 | std::string SocketAddress::getIpString(int flags) const { |
663 | char addrString[NI_MAXHOST]; |
664 | getIpString(addrString, sizeof(addrString), flags); |
665 | return std::string(addrString); |
666 | } |
667 | |
668 | void SocketAddress::getIpString(char* buf, size_t buflen, int flags) const { |
669 | auto family = getFamily(); |
670 | if (family != AF_INET && family != AF_INET6) { |
671 | throw std::invalid_argument( |
672 | "SocketAddress: attempting to get IP address " |
673 | "for a non-IP address" ); |
674 | } |
675 | |
676 | sockaddr_storage tmp_sock; |
677 | storage_.addr.toSockaddrStorage(&tmp_sock, port_); |
678 | int rc = getnameinfo( |
679 | (sockaddr*)&tmp_sock, |
680 | sizeof(sockaddr_storage), |
681 | buf, |
682 | buflen, |
683 | nullptr, |
684 | 0, |
685 | flags); |
686 | if (rc != 0) { |
687 | auto os = sformat( |
688 | "getnameinfo() failed in getIpString() error = {}" , gai_strerror(rc)); |
689 | throw std::system_error(rc, std::generic_category(), os); |
690 | } |
691 | } |
692 | |
693 | void SocketAddress::updateUnixAddressLength(socklen_t addrlen) { |
694 | if (addrlen < offsetof(struct sockaddr_un, sun_path)) { |
695 | throw std::invalid_argument( |
696 | "SocketAddress: attempted to set a Unix socket " |
697 | "with a length too short for a sockaddr_un" ); |
698 | } |
699 | |
700 | storage_.un.len = addrlen; |
701 | if (storage_.un.pathLength() == 0) { |
702 | // anonymous address |
703 | return; |
704 | } |
705 | |
706 | if (storage_.un.addr->sun_path[0] == '\0') { |
707 | // abstract namespace. honor the specified length |
708 | } else { |
709 | // Call strnlen(), just in case the length was overspecified. |
710 | size_t maxLength = addrlen - offsetof(struct sockaddr_un, sun_path); |
711 | size_t pathLength = strnlen(storage_.un.addr->sun_path, maxLength); |
712 | storage_.un.len = |
713 | socklen_t(offsetof(struct sockaddr_un, sun_path) + pathLength); |
714 | } |
715 | } |
716 | |
717 | bool SocketAddress::operator<(const SocketAddress& other) const { |
718 | if (getFamily() != other.getFamily()) { |
719 | return getFamily() < other.getFamily(); |
720 | } |
721 | |
722 | if (external_) { |
723 | // Anonymous addresses can't be compared to anything else. |
724 | // Return that they are never less than anything. |
725 | // |
726 | // Note that this still meets the requirements for a strict weak |
727 | // ordering, so we can use this operator<() with standard C++ containers. |
728 | auto thisPathLength = storage_.un.pathLength(); |
729 | if (thisPathLength == 0) { |
730 | return false; |
731 | } |
732 | auto otherPathLength = other.storage_.un.pathLength(); |
733 | if (otherPathLength == 0) { |
734 | return true; |
735 | } |
736 | |
737 | // Compare based on path length first, for efficiency |
738 | if (thisPathLength != otherPathLength) { |
739 | return thisPathLength < otherPathLength; |
740 | } |
741 | int cmp = memcmp( |
742 | storage_.un.addr->sun_path, |
743 | other.storage_.un.addr->sun_path, |
744 | size_t(thisPathLength)); |
745 | return cmp < 0; |
746 | } |
747 | switch (getFamily()) { |
748 | case AF_INET: |
749 | case AF_INET6: { |
750 | if (port_ != other.port_) { |
751 | return port_ < other.port_; |
752 | } |
753 | |
754 | return storage_.addr < other.storage_.addr; |
755 | } |
756 | case AF_UNSPEC: |
757 | default: |
758 | throw std::invalid_argument( |
759 | "SocketAddress: unsupported address family for comparing" ); |
760 | } |
761 | } |
762 | |
763 | size_t hash_value(const SocketAddress& address) { |
764 | return address.hash(); |
765 | } |
766 | |
767 | std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) { |
768 | os << addr.describe(); |
769 | return os; |
770 | } |
771 | |
772 | } // namespace folly |
773 | |