2 * Copyright 2014 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>
26 #include <boost/static_assert.hpp>
39 * A structure to free a struct addrinfo when it goes out of scope.
41 struct ScopedAddrInfo {
42 explicit ScopedAddrInfo(struct addrinfo* info) : info(info) {}
47 struct addrinfo* info;
51 * A simple data structure for parsing a host-and-port string.
53 * Accepts a string of the form "<host>:<port>" or just "<port>",
54 * and contains two string pointers to the host and the port portion of the
57 * The HostAndPort may contain pointers into the original string. It is
58 * responsible for the user to ensure that the input string is valid for the
59 * lifetime of the HostAndPort structure.
62 HostAndPort(const char* str, bool hostRequired)
67 // Look for the last colon
68 const char* colon = strrchr(str, ':');
69 if (colon == nullptr) {
70 // No colon, just a port number.
72 throw std::invalid_argument(
73 "expected a host and port string of the "
74 "form \"<host>:<port>\"");
80 // We have to make a copy of the string so we can modify it
81 // and change the colon to a NUL terminator.
82 allocated = strdup(str);
84 throw std::bad_alloc();
87 char *allocatedColon = allocated + (colon - str);
88 *allocatedColon = '\0';
90 port = allocatedColon + 1;
91 // bracketed IPv6 address, remove the brackets
92 // allocatedColon[-1] is fine, as allocatedColon >= host and
93 // *allocatedColon != *host therefore allocatedColon > host
94 if (*host == '[' && allocatedColon[-1] == ']') {
95 allocatedColon[-1] = '\0';
109 } // unnamed namespace
113 bool SocketAddress::isPrivateAddress() const {
114 auto family = getFamily();
115 if (family == AF_INET || family == AF_INET6) {
116 return storage_.addr.isPrivate() ||
117 (storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal());
118 } else if (external_) {
119 // Unix addresses are always local to a host. Return true,
120 // since this conforms to the semantics of returning true for IP loopback
127 bool SocketAddress::isLoopbackAddress() const {
128 auto family = getFamily();
129 if (family == AF_INET || family == AF_INET6) {
130 return storage_.addr.isLoopback();
131 } else if (external_) {
132 // Return true for UNIX addresses, since they are always local to a host.
138 void SocketAddress::setFromHostPort(const char* host, uint16_t port) {
139 ScopedAddrInfo results(getAddrInfo(host, port, 0));
140 setFromAddrInfo(results.info);
143 void SocketAddress::setFromIpPort(const char* ip, uint16_t port) {
144 ScopedAddrInfo results(getAddrInfo(ip, port, AI_NUMERICHOST));
145 setFromAddrInfo(results.info);
148 void SocketAddress::setFromLocalPort(uint16_t port) {
149 ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
150 setFromLocalAddr(results.info);
153 void SocketAddress::setFromLocalPort(const char* port) {
154 ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
155 setFromLocalAddr(results.info);
158 void SocketAddress::setFromLocalIpPort(const char* addressAndPort) {
159 HostAndPort hp(addressAndPort, false);
160 ScopedAddrInfo results(getAddrInfo(hp.host, hp.port,
161 AI_NUMERICHOST | AI_ADDRCONFIG));
162 setFromLocalAddr(results.info);
165 void SocketAddress::setFromIpPort(const char* addressAndPort) {
166 HostAndPort hp(addressAndPort, true);
167 ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, AI_NUMERICHOST));
168 setFromAddrInfo(results.info);
171 void SocketAddress::setFromHostPort(const char* hostAndPort) {
172 HostAndPort hp(hostAndPort, true);
173 ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, 0));
174 setFromAddrInfo(results.info);
177 void SocketAddress::setFromPath(const char* path, size_t len) {
183 storage_.un.len = offsetof(struct sockaddr_un, sun_path) + len;
184 if (len > sizeof(storage_.un.addr->sun_path)) {
185 throw std::invalid_argument(
186 "socket path too large to fit into sockaddr_un");
187 } else if (len == sizeof(storage_.un.addr->sun_path)) {
188 // Note that there will be no terminating NUL in this case.
189 // We allow this since getsockname() and getpeername() may return
190 // Unix socket addresses with paths that fit exactly in sun_path with no
192 memcpy(storage_.un.addr->sun_path, path, len);
194 memcpy(storage_.un.addr->sun_path, path, len + 1);
198 void SocketAddress::setFromPeerAddress(int socket) {
199 setFromSocket(socket, getpeername);
202 void SocketAddress::setFromLocalAddress(int socket) {
203 setFromSocket(socket, getsockname);
206 void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
209 if (address->sa_family == AF_INET) {
210 port = ntohs(((sockaddr_in*)address)->sin_port);
211 } else if (address->sa_family == AF_INET6) {
212 port = ntohs(((sockaddr_in6*)address)->sin6_port);
213 } else if (address->sa_family == AF_UNIX) {
214 // We need an explicitly specified length for AF_UNIX addresses,
215 // to be able to distinguish anonymous addresses from addresses
216 // in Linux's abstract namespace.
217 throw std::invalid_argument(
218 "SocketAddress::setFromSockaddr(): the address "
219 "length must be explicitly specified when "
220 "setting AF_UNIX addresses");
222 throw std::invalid_argument(
223 "SocketAddress::setFromSockaddr() called "
224 "with unsupported address type");
230 storage_.addr = folly::IPAddress(address);
234 void SocketAddress::setFromSockaddr(const struct sockaddr* address,
236 // Check the length to make sure we can access address->sa_family
237 if (addrlen < (offsetof(struct sockaddr, sa_family) +
238 sizeof(address->sa_family))) {
239 throw std::invalid_argument(
240 "SocketAddress::setFromSockaddr() called "
241 "with length too short for a sockaddr");
244 if (address->sa_family == AF_INET) {
245 if (addrlen < sizeof(struct sockaddr_in)) {
246 throw std::invalid_argument(
247 "SocketAddress::setFromSockaddr() called "
248 "with length too short for a sockaddr_in");
250 setFromSockaddr(reinterpret_cast<const struct sockaddr_in*>(address));
251 } else if (address->sa_family == AF_INET6) {
252 if (addrlen < sizeof(struct sockaddr_in6)) {
253 throw std::invalid_argument(
254 "SocketAddress::setFromSockaddr() called "
255 "with length too short for a sockaddr_in6");
257 setFromSockaddr(reinterpret_cast<const struct sockaddr_in6*>(address));
258 } else if (address->sa_family == AF_UNIX) {
259 setFromSockaddr(reinterpret_cast<const struct sockaddr_un*>(address),
262 throw std::invalid_argument(
263 "SocketAddress::setFromSockaddr() called "
264 "with unsupported address type");
268 void SocketAddress::setFromSockaddr(const struct sockaddr_in* address) {
269 assert(address->sin_family == AF_INET);
270 setFromSockaddr((sockaddr*)address);
273 void SocketAddress::setFromSockaddr(const struct sockaddr_in6* address) {
274 assert(address->sin6_family == AF_INET6);
275 setFromSockaddr((sockaddr*)address);
278 void SocketAddress::setFromSockaddr(const struct sockaddr_un* address,
280 assert(address->sun_family == AF_UNIX);
281 if (addrlen > sizeof(struct sockaddr_un)) {
282 throw std::invalid_argument(
283 "SocketAddress::setFromSockaddr() called "
284 "with length too long for a sockaddr_un");
287 prepFamilyChange(AF_UNIX);
288 memcpy(storage_.un.addr, address, addrlen);
289 updateUnixAddressLength(addrlen);
291 // Fill the rest with 0s, just for safety
292 if (addrlen < sizeof(struct sockaddr_un)) {
293 char *p = reinterpret_cast<char*>(storage_.un.addr);
294 memset(p + addrlen, 0, sizeof(struct sockaddr_un) - addrlen);
298 const folly::IPAddress& SocketAddress::getIPAddress() const {
299 auto family = getFamily();
300 if (family != AF_INET && family != AF_INET6) {
301 throw InvalidAddressFamilyException(family);
303 return storage_.addr;
306 socklen_t SocketAddress::getActualSize() const {
308 return storage_.un.len;
310 switch (getFamily()) {
313 return sizeof(struct sockaddr_in);
315 return sizeof(struct sockaddr_in6);
317 throw std::invalid_argument(
318 "SocketAddress::getActualSize() called "
319 "with unrecognized address family");
323 std::string SocketAddress::getFullyQualified() const {
324 auto family = getFamily();
325 if (family != AF_INET && family != AF_INET6) {
326 throw std::invalid_argument("Can't get address str for non ip address");
328 return storage_.addr.toFullyQualified();
331 std::string SocketAddress::getAddressStr() const {
332 char buf[INET6_ADDRSTRLEN];
333 getAddressStr(buf, sizeof(buf));
337 void SocketAddress::getAddressStr(char* buf, size_t buflen) const {
338 auto family = getFamily();
339 if (family != AF_INET && family != AF_INET6) {
340 throw std::invalid_argument("Can't get address str for non ip address");
342 std::string ret = storage_.addr.str();
343 size_t len = std::min(buflen, ret.size());
344 memcpy(buf, ret.data(), len);
348 uint16_t SocketAddress::getPort() const {
349 switch (getFamily()) {
354 throw std::invalid_argument(
355 "SocketAddress::getPort() called on non-IP "
360 void SocketAddress::setPort(uint16_t port) {
361 switch (getFamily()) {
367 throw std::invalid_argument(
368 "SocketAddress::setPort() called on non-IP "
373 void SocketAddress::convertToIPv4() {
374 if (!tryConvertToIPv4()) {
375 throw std::invalid_argument(
376 "convertToIPv4() called on an addresse that is "
377 "not an IPv4-mapped address");
381 bool SocketAddress::tryConvertToIPv4() {
382 if (!isIPv4Mapped()) {
386 storage_.addr = folly::IPAddress::createIPv4(storage_.addr);
390 bool SocketAddress::mapToIPv6() {
391 if (getFamily() != AF_INET) {
395 storage_.addr = folly::IPAddress::createIPv6(storage_.addr);
399 std::string SocketAddress::getHostStr() const {
400 return getIpString(0);
403 std::string SocketAddress::getPath() const {
405 throw std::invalid_argument(
406 "SocketAddress: attempting to get path "
407 "for a non-Unix address");
410 if (storage_.un.pathLength() == 0) {
412 return std::string();
414 if (storage_.un.addr->sun_path[0] == '\0') {
415 // abstract namespace
416 return std::string(storage_.un.addr->sun_path, storage_.un.pathLength());
419 return std::string(storage_.un.addr->sun_path,
420 strnlen(storage_.un.addr->sun_path,
421 storage_.un.pathLength()));
424 std::string SocketAddress::describe() const {
426 if (storage_.un.pathLength() == 0) {
427 return "<anonymous unix address>";
430 if (storage_.un.addr->sun_path[0] == '\0') {
431 // Linux supports an abstract namespace for unix socket addresses
432 return "<abstract unix address>";
435 return std::string(storage_.un.addr->sun_path,
436 strnlen(storage_.un.addr->sun_path,
437 storage_.un.pathLength()));
439 switch (getFamily()) {
441 return "<uninitialized address>";
444 char buf[NI_MAXHOST + 16];
445 getAddressStr(buf, sizeof(buf));
446 size_t iplen = strlen(buf);
447 snprintf(buf + iplen, sizeof(buf) - iplen, ":%" PRIu16, getPort());
452 char buf[NI_MAXHOST + 18];
454 getAddressStr(buf + 1, sizeof(buf) - 1);
455 size_t iplen = strlen(buf);
456 snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort());
462 snprintf(buf, sizeof(buf), "<unknown address family %d>",
469 bool SocketAddress::operator==(const SocketAddress& other) const {
470 if (external_ != other.external_ || other.getFamily() != getFamily()) {
474 // anonymous addresses are never equal to any other addresses
475 if (storage_.un.pathLength() == 0 ||
476 other.storage_.un.pathLength() == 0) {
480 if (storage_.un.len != other.storage_.un.len) {
483 int cmp = memcmp(storage_.un.addr->sun_path,
484 other.storage_.un.addr->sun_path,
485 storage_.un.pathLength());
489 switch (getFamily()) {
492 return (other.storage_.addr == storage_.addr) &&
493 (other.port_ == port_);
495 throw std::invalid_argument(
496 "SocketAddress: unsupported address family "
501 bool SocketAddress::prefixMatch(const SocketAddress& other,
502 unsigned prefixLength) const {
503 if (other.getFamily() != getFamily()) {
506 int mask_length = 128;
507 switch (getFamily()) {
513 auto prefix = folly::IPAddress::longestCommonPrefix(
514 {storage_.addr, mask_length},
515 {other.storage_.addr, mask_length});
516 return prefix.second >= prefixLength;
524 size_t SocketAddress::hash() const {
525 size_t seed = folly::hash::twang_mix64(getFamily());
528 enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) };
529 const char *path = storage_.un.addr->sun_path;
530 size_t pathLength = storage_.un.pathLength();
531 // TODO: this probably could be made more efficient
532 for (unsigned int n = 0; n < pathLength; ++n) {
533 boost::hash_combine(seed, folly::hash::twang_mix64(path[n]));
537 switch (getFamily()) {
540 boost::hash_combine(seed, port_);
541 boost::hash_combine(seed, storage_.addr.hash());
551 // get void*'s for all entries on the stack
552 size = backtrace(array, 20);
553 // print out all the frames to stderr
554 fprintf(stderr, "Exception: \n");
555 backtrace_symbols_fd(array, size, STDERR_FILENO);
556 LOG(FATAL) << "Invalid ip address: " << describe();
557 throw std::invalid_argument(
558 "SocketAddress: unsupported address family "
565 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
568 // getaddrinfo() requires the port number as a string
569 char portString[sizeof("65535")];
570 snprintf(portString, sizeof(portString), "%" PRIu16, port);
572 return getAddrInfo(host, portString, flags);
575 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
578 struct addrinfo hints;
579 memset(&hints, 0, sizeof(hints));
580 hints.ai_family = AF_UNSPEC;
581 hints.ai_socktype = SOCK_STREAM;
582 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | flags;
584 struct addrinfo *results;
585 int error = getaddrinfo(host, port, &hints, &results);
587 auto os = folly::to<std::string>(
588 "Failed to resolve address for \"", host, "\": ",
589 gai_strerror(error), " (error=", error, ")");
590 throw std::system_error(error, std::generic_category(), os);
596 void SocketAddress::setFromAddrInfo(const struct addrinfo* info) {
597 setFromSockaddr(info->ai_addr, info->ai_addrlen);
600 void SocketAddress::setFromLocalAddr(const struct addrinfo* info) {
601 // If an IPv6 address is present, prefer to use it, since IPv4 addresses
602 // can be mapped into IPv6 space.
603 for (const struct addrinfo* ai = info; ai != nullptr; ai = ai->ai_next) {
604 if (ai->ai_family == AF_INET6) {
605 setFromSockaddr(ai->ai_addr, ai->ai_addrlen);
610 // Otherwise, just use the first address in the list.
611 setFromSockaddr(info->ai_addr, info->ai_addrlen);
614 void SocketAddress::setFromSocket(int socket,
615 int (*fn)(int, sockaddr*, socklen_t*)) {
616 // Try to put the address into a local storage buffer.
617 sockaddr_storage tmp_sock;
618 socklen_t addrLen = sizeof(tmp_sock);
619 if (fn(socket, (sockaddr*)&tmp_sock, &addrLen) != 0) {
620 folly::throwSystemError("setFromSocket() failed");
623 setFromSockaddr((sockaddr*)&tmp_sock, addrLen);
626 std::string SocketAddress::getIpString(int flags) const {
627 char addrString[NI_MAXHOST];
628 getIpString(addrString, sizeof(addrString), flags);
629 return std::string(addrString);
632 void SocketAddress::getIpString(char *buf, size_t buflen, int flags) const {
633 auto family = getFamily();
634 if (family != AF_INET &&
635 family != AF_INET6) {
636 throw std::invalid_argument(
637 "SocketAddress: attempting to get IP address "
638 "for a non-IP address");
641 sockaddr_storage tmp_sock;
642 storage_.addr.toSockaddrStorage(&tmp_sock, port_);
643 int rc = getnameinfo((sockaddr*)&tmp_sock, sizeof(sockaddr_storage),
644 buf, buflen, nullptr, 0, flags);
646 auto os = folly::to<std::string>(
647 "getnameinfo() failed in getIpString() error = ",
649 throw std::system_error(rc, std::generic_category(), os);
653 void SocketAddress::updateUnixAddressLength(socklen_t addrlen) {
654 if (addrlen < offsetof(struct sockaddr_un, sun_path)) {
655 throw std::invalid_argument(
656 "SocketAddress: attempted to set a Unix socket "
657 "with a length too short for a sockaddr_un");
660 storage_.un.len = addrlen;
661 if (storage_.un.pathLength() == 0) {
666 if (storage_.un.addr->sun_path[0] == '\0') {
667 // abstract namespace. honor the specified length
669 // Call strnlen(), just in case the length was overspecified.
670 socklen_t maxLength = addrlen - offsetof(struct sockaddr_un, sun_path);
671 size_t pathLength = strnlen(storage_.un.addr->sun_path, maxLength);
672 storage_.un.len = offsetof(struct sockaddr_un, sun_path) + pathLength;
676 bool SocketAddress::operator<(const SocketAddress& other) const {
677 if (getFamily() != other.getFamily()) {
678 return getFamily() < other.getFamily();
682 // Anonymous addresses can't be compared to anything else.
683 // Return that they are never less than anything.
685 // Note that this still meets the requirements for a strict weak
686 // ordering, so we can use this operator<() with standard C++ containers.
687 size_t thisPathLength = storage_.un.pathLength();
688 if (thisPathLength == 0) {
691 size_t otherPathLength = other.storage_.un.pathLength();
692 if (otherPathLength == 0) {
696 // Compare based on path length first, for efficiency
697 if (thisPathLength != otherPathLength) {
698 return thisPathLength < otherPathLength;
700 int cmp = memcmp(storage_.un.addr->sun_path,
701 other.storage_.un.addr->sun_path,
705 switch (getFamily()) {
708 if (port_ != other.port_) {
709 return port_ < other.port_;
713 storage_.addr < other.storage_.addr;
717 throw std::invalid_argument(
718 "SocketAddress: unsupported address family for comparing");
722 size_t hash_value(const SocketAddress& address) {
723 return address.hash();
726 std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) {
727 os << addr.describe();