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