2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef __STDC_FORMAT_MACROS
18 #define __STDC_FORMAT_MACROS
21 #include <folly/SocketAddress.h>
23 #include <folly/Hash.h>
25 #include <boost/functional/hash.hpp>
35 * A structure to free a struct addrinfo when it goes out of scope.
37 struct ScopedAddrInfo {
38 explicit ScopedAddrInfo(struct addrinfo* addrinfo) : info(addrinfo) {}
43 struct addrinfo* info;
47 * A simple data structure for parsing a host-and-port string.
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
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.
58 HostAndPort(const char* str, bool hostRequired)
63 // Look for the last colon
64 const char* colon = strrchr(str, ':');
65 if (colon == nullptr) {
66 // No colon, just a port number.
68 throw std::invalid_argument(
69 "expected a host and port string of the "
70 "form \"<host>:<port>\"");
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);
80 throw std::bad_alloc();
83 char *allocatedColon = allocated + (colon - str);
84 *allocatedColon = '\0';
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';
105 } // unnamed namespace
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
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.
134 void SocketAddress::setFromHostPort(const char* host, uint16_t port) {
135 ScopedAddrInfo results(getAddrInfo(host, port, 0));
136 setFromAddrInfo(results.info);
139 void SocketAddress::setFromIpPort(const char* ip, uint16_t port) {
140 ScopedAddrInfo results(getAddrInfo(ip, port, AI_NUMERICHOST));
141 setFromAddrInfo(results.info);
144 void SocketAddress::setFromIpAddrPort(const IPAddress& ipAddr, uint16_t port) {
149 storage_.addr = ipAddr;
153 void SocketAddress::setFromLocalPort(uint16_t port) {
154 ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
155 setFromLocalAddr(results.info);
158 void SocketAddress::setFromLocalPort(const char* port) {
159 ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
160 setFromLocalAddr(results.info);
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);
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);
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);
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");
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';
208 void SocketAddress::setFromPeerAddress(SocketDesc socket) {
209 setFromSocket(socket, getpeername);
212 void SocketAddress::setFromLocalAddress(SocketDesc socket) {
213 setFromSocket(socket, getsockname);
216 void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
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");
232 throw std::invalid_argument(
233 "SocketAddress::setFromSockaddr() called "
234 "with unsupported address type");
237 setFromIpAddrPort(folly::IPAddress(address), port);
240 void SocketAddress::setFromSockaddr(const struct sockaddr* address,
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");
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");
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");
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),
268 throw std::invalid_argument(
269 "SocketAddress::setFromSockaddr() called "
270 "with unsupported address type");
274 void SocketAddress::setFromSockaddr(const struct sockaddr_in* address) {
275 assert(address->sin_family == AF_INET);
276 setFromSockaddr((sockaddr*)address);
279 void SocketAddress::setFromSockaddr(const struct sockaddr_in6* address) {
280 assert(address->sin6_family == AF_INET6);
281 setFromSockaddr((sockaddr*)address);
284 void SocketAddress::setFromSockaddr(const struct sockaddr_un* address,
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");
293 prepFamilyChange(AF_UNIX);
294 memcpy(storage_.un.addr, address, addrlen);
295 updateUnixAddressLength(addrlen);
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);
304 const folly::IPAddress& SocketAddress::getIPAddress() const {
305 auto family = getFamily();
306 if (family != AF_INET && family != AF_INET6) {
307 throw InvalidAddressFamilyException(family);
309 return storage_.addr;
312 socklen_t SocketAddress::getActualSize() const {
314 return storage_.un.len;
316 switch (getFamily()) {
319 return sizeof(struct sockaddr_in);
321 return sizeof(struct sockaddr_in6);
323 throw std::invalid_argument(
324 "SocketAddress::getActualSize() called "
325 "with unrecognized address family");
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");
334 return storage_.addr.toFullyQualified();
337 std::string SocketAddress::getAddressStr() const {
338 char buf[INET6_ADDRSTRLEN];
339 getAddressStr(buf, sizeof(buf));
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");
348 std::string ret = storage_.addr.str();
349 size_t len = std::min(buflen, ret.size());
350 memcpy(buf, ret.data(), len);
354 uint16_t SocketAddress::getPort() const {
355 switch (getFamily()) {
360 throw std::invalid_argument(
361 "SocketAddress::getPort() called on non-IP "
366 void SocketAddress::setPort(uint16_t port) {
367 switch (getFamily()) {
373 throw std::invalid_argument(
374 "SocketAddress::setPort() called on non-IP "
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");
387 bool SocketAddress::tryConvertToIPv4() {
388 if (!isIPv4Mapped()) {
392 storage_.addr = folly::IPAddress::createIPv4(storage_.addr);
396 bool SocketAddress::mapToIPv6() {
397 if (getFamily() != AF_INET) {
401 storage_.addr = folly::IPAddress::createIPv6(storage_.addr);
405 std::string SocketAddress::getHostStr() const {
406 return getIpString(0);
409 std::string SocketAddress::getPath() const {
411 throw std::invalid_argument(
412 "SocketAddress: attempting to get path "
413 "for a non-Unix address");
416 if (storage_.un.pathLength() == 0) {
418 return std::string();
420 if (storage_.un.addr->sun_path[0] == '\0') {
421 // abstract namespace
422 return std::string(storage_.un.addr->sun_path, storage_.un.pathLength());
425 return std::string(storage_.un.addr->sun_path,
426 strnlen(storage_.un.addr->sun_path,
427 storage_.un.pathLength()));
430 std::string SocketAddress::describe() const {
432 if (storage_.un.pathLength() == 0) {
433 return "<anonymous unix address>";
436 if (storage_.un.addr->sun_path[0] == '\0') {
437 // Linux supports an abstract namespace for unix socket addresses
438 return "<abstract unix address>";
441 return std::string(storage_.un.addr->sun_path,
442 strnlen(storage_.un.addr->sun_path,
443 storage_.un.pathLength()));
445 switch (getFamily()) {
447 return "<uninitialized address>";
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());
458 char buf[NI_MAXHOST + 18];
460 getAddressStr(buf + 1, sizeof(buf) - 1);
461 size_t iplen = strlen(buf);
462 snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort());
468 snprintf(buf, sizeof(buf), "<unknown address family %d>",
475 bool SocketAddress::operator==(const SocketAddress& other) const {
476 if (external_ != other.external_ || other.getFamily() != getFamily()) {
480 // anonymous addresses are never equal to any other addresses
481 if (storage_.un.pathLength() == 0 ||
482 other.storage_.un.pathLength() == 0) {
486 if (storage_.un.len != other.storage_.un.len) {
489 int cmp = memcmp(storage_.un.addr->sun_path,
490 other.storage_.un.addr->sun_path,
491 storage_.un.pathLength());
495 switch (getFamily()) {
498 return (other.storage_.addr == storage_.addr) &&
499 (other.port_ == port_);
501 throw std::invalid_argument(
502 "SocketAddress: unsupported address family "
507 bool SocketAddress::prefixMatch(const SocketAddress& other,
508 unsigned prefixLength) const {
509 if (other.getFamily() != getFamily()) {
512 int mask_length = 128;
513 switch (getFamily()) {
519 auto prefix = folly::IPAddress::longestCommonPrefix(
520 {storage_.addr, mask_length},
521 {other.storage_.addr, mask_length});
522 return prefix.second >= prefixLength;
530 size_t SocketAddress::hash() const {
531 size_t seed = folly::hash::twang_mix64(getFamily());
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]));
543 switch (getFamily()) {
546 boost::hash_combine(seed, port_);
547 boost::hash_combine(seed, storage_.addr.hash());
555 throw std::invalid_argument(
556 "SocketAddress: unsupported address family "
563 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
566 // getaddrinfo() requires the port number as a string
567 char portString[sizeof("65535")];
568 snprintf(portString, sizeof(portString), "%" PRIu16, port);
570 return getAddrInfo(host, portString, flags);
573 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
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;
582 struct addrinfo *results;
583 int error = getaddrinfo(host, port, &hints, &results);
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);
594 void SocketAddress::setFromAddrInfo(const struct addrinfo* info) {
595 setFromSockaddr(info->ai_addr, info->ai_addrlen);
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);
608 // Otherwise, just use the first address in the list.
609 setFromSockaddr(info->ai_addr, info->ai_addrlen);
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");
620 setFromSockaddr((sockaddr*)&tmp_sock, addrLen);
623 std::string SocketAddress::getIpString(int flags) const {
624 char addrString[NI_MAXHOST];
625 getIpString(addrString, sizeof(addrString), flags);
626 return std::string(addrString);
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");
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);
643 auto os = folly::to<std::string>(
644 "getnameinfo() failed in getIpString() error = ",
646 throw std::system_error(rc, std::generic_category(), os);
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");
657 storage_.un.len = addrlen;
658 if (storage_.un.pathLength() == 0) {
663 if (storage_.un.addr->sun_path[0] == '\0') {
664 // abstract namespace. honor the specified length
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;
673 bool SocketAddress::operator<(const SocketAddress& other) const {
674 if (getFamily() != other.getFamily()) {
675 return getFamily() < other.getFamily();
679 // Anonymous addresses can't be compared to anything else.
680 // Return that they are never less than anything.
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) {
688 size_t otherPathLength = other.storage_.un.pathLength();
689 if (otherPathLength == 0) {
693 // Compare based on path length first, for efficiency
694 if (thisPathLength != otherPathLength) {
695 return thisPathLength < otherPathLength;
697 int cmp = memcmp(storage_.un.addr->sun_path,
698 other.storage_.un.addr->sun_path,
702 switch (getFamily()) {
705 if (port_ != other.port_) {
706 return port_ < other.port_;
710 storage_.addr < other.storage_.addr;
714 throw std::invalid_argument(
715 "SocketAddress: unsupported address family for comparing");
719 size_t hash_value(const SocketAddress& address) {
720 return address.hash();
723 std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) {
724 os << addr.describe();