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