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