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 int SocketAddress::getPortFrom(const struct sockaddr* address) {
183 switch (address->sa_family) {
185 return ntohs(((sockaddr_in*)address)->sin_port);
188 return ntohs(((sockaddr_in6*)address)->sin6_port);
195 const char* SocketAddress::getFamilyNameFrom(
196 const struct sockaddr* address,
197 const char* defaultResult) {
198 #define GETFAMILYNAMEFROM_IMPL(Family) \
202 switch (address->sa_family) {
203 GETFAMILYNAMEFROM_IMPL(AF_INET);
204 GETFAMILYNAMEFROM_IMPL(AF_INET6);
205 GETFAMILYNAMEFROM_IMPL(AF_UNIX);
206 GETFAMILYNAMEFROM_IMPL(AF_UNSPEC);
209 return defaultResult;
212 #undef GETFAMILYNAMEFROM_IMPL
215 void SocketAddress::setFromPath(StringPiece path) {
216 // Before we touch storage_, check to see if the length is too big.
217 // Note that "storage_.un.addr->sun_path" may not be safe to evaluate here,
218 // but sizeof() just uses its type, and does't evaluate it.
219 if (path.size() > sizeof(storage_.un.addr->sun_path)) {
220 throw std::invalid_argument(
221 "socket path too large to fit into sockaddr_un");
229 size_t len = path.size();
230 storage_.un.len = offsetof(struct sockaddr_un, sun_path) + len;
231 memcpy(storage_.un.addr->sun_path, path.data(), len);
232 // If there is room, put a terminating NUL byte in sun_path. In general the
233 // path should be NUL terminated, although getsockname() and getpeername()
234 // may return Unix socket addresses with paths that fit exactly in sun_path
235 // with no terminating NUL.
236 if (len < sizeof(storage_.un.addr->sun_path)) {
237 storage_.un.addr->sun_path[len] = '\0';
241 void SocketAddress::setFromPeerAddress(SocketDesc socket) {
242 setFromSocket(socket, getpeername);
245 void SocketAddress::setFromLocalAddress(SocketDesc socket) {
246 setFromSocket(socket, getsockname);
249 void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
252 if (address->sa_family == AF_INET) {
253 port = ntohs(((sockaddr_in*)address)->sin_port);
254 } else if (address->sa_family == AF_INET6) {
255 port = ntohs(((sockaddr_in6*)address)->sin6_port);
256 } else if (address->sa_family == AF_UNIX) {
257 // We need an explicitly specified length for AF_UNIX addresses,
258 // to be able to distinguish anonymous addresses from addresses
259 // in Linux's abstract namespace.
260 throw std::invalid_argument(
261 "SocketAddress::setFromSockaddr(): the address "
262 "length must be explicitly specified when "
263 "setting AF_UNIX addresses");
265 throw std::invalid_argument(
266 "SocketAddress::setFromSockaddr() called "
267 "with unsupported address type");
270 setFromIpAddrPort(folly::IPAddress(address), port);
273 void SocketAddress::setFromSockaddr(const struct sockaddr* address,
275 // Check the length to make sure we can access address->sa_family
276 if (addrlen < (offsetof(struct sockaddr, sa_family) +
277 sizeof(address->sa_family))) {
278 throw std::invalid_argument(
279 "SocketAddress::setFromSockaddr() called "
280 "with length too short for a sockaddr");
283 if (address->sa_family == AF_INET) {
284 if (addrlen < sizeof(struct sockaddr_in)) {
285 throw std::invalid_argument(
286 "SocketAddress::setFromSockaddr() called "
287 "with length too short for a sockaddr_in");
289 setFromSockaddr(reinterpret_cast<const struct sockaddr_in*>(address));
290 } else if (address->sa_family == AF_INET6) {
291 if (addrlen < sizeof(struct sockaddr_in6)) {
292 throw std::invalid_argument(
293 "SocketAddress::setFromSockaddr() called "
294 "with length too short for a sockaddr_in6");
296 setFromSockaddr(reinterpret_cast<const struct sockaddr_in6*>(address));
297 } else if (address->sa_family == AF_UNIX) {
298 setFromSockaddr(reinterpret_cast<const struct sockaddr_un*>(address),
301 throw std::invalid_argument(
302 "SocketAddress::setFromSockaddr() called "
303 "with unsupported address type");
307 void SocketAddress::setFromSockaddr(const struct sockaddr_in* address) {
308 assert(address->sin_family == AF_INET);
309 setFromSockaddr((sockaddr*)address);
312 void SocketAddress::setFromSockaddr(const struct sockaddr_in6* address) {
313 assert(address->sin6_family == AF_INET6);
314 setFromSockaddr((sockaddr*)address);
317 void SocketAddress::setFromSockaddr(const struct sockaddr_un* address,
319 assert(address->sun_family == AF_UNIX);
320 if (addrlen > sizeof(struct sockaddr_un)) {
321 throw std::invalid_argument(
322 "SocketAddress::setFromSockaddr() called "
323 "with length too long for a sockaddr_un");
326 prepFamilyChange(AF_UNIX);
327 memcpy(storage_.un.addr, address, addrlen);
328 updateUnixAddressLength(addrlen);
330 // Fill the rest with 0s, just for safety
331 if (addrlen < sizeof(struct sockaddr_un)) {
332 char *p = reinterpret_cast<char*>(storage_.un.addr);
333 memset(p + addrlen, 0, sizeof(struct sockaddr_un) - addrlen);
337 const folly::IPAddress& SocketAddress::getIPAddress() const {
338 auto family = getFamily();
339 if (family != AF_INET && family != AF_INET6) {
340 throw InvalidAddressFamilyException(family);
342 return storage_.addr;
345 socklen_t SocketAddress::getActualSize() const {
347 return storage_.un.len;
349 switch (getFamily()) {
352 return sizeof(struct sockaddr_in);
354 return sizeof(struct sockaddr_in6);
356 throw std::invalid_argument(
357 "SocketAddress::getActualSize() called "
358 "with unrecognized address family");
362 std::string SocketAddress::getFullyQualified() const {
363 auto family = getFamily();
364 if (family != AF_INET && family != AF_INET6) {
365 throw std::invalid_argument("Can't get address str for non ip address");
367 return storage_.addr.toFullyQualified();
370 std::string SocketAddress::getAddressStr() const {
371 char buf[INET6_ADDRSTRLEN];
372 getAddressStr(buf, sizeof(buf));
376 void SocketAddress::getAddressStr(char* buf, size_t buflen) const {
377 auto family = getFamily();
378 if (family != AF_INET && family != AF_INET6) {
379 throw std::invalid_argument("Can't get address str for non ip address");
381 std::string ret = storage_.addr.str();
382 size_t len = std::min(buflen, ret.size());
383 memcpy(buf, ret.data(), len);
387 uint16_t SocketAddress::getPort() const {
388 switch (getFamily()) {
393 throw std::invalid_argument(
394 "SocketAddress::getPort() called on non-IP "
399 void SocketAddress::setPort(uint16_t port) {
400 switch (getFamily()) {
406 throw std::invalid_argument(
407 "SocketAddress::setPort() called on non-IP "
412 void SocketAddress::convertToIPv4() {
413 if (!tryConvertToIPv4()) {
414 throw std::invalid_argument(
415 "convertToIPv4() called on an addresse that is "
416 "not an IPv4-mapped address");
420 bool SocketAddress::tryConvertToIPv4() {
421 if (!isIPv4Mapped()) {
425 storage_.addr = folly::IPAddress::createIPv4(storage_.addr);
429 bool SocketAddress::mapToIPv6() {
430 if (getFamily() != AF_INET) {
434 storage_.addr = folly::IPAddress::createIPv6(storage_.addr);
438 std::string SocketAddress::getHostStr() const {
439 return getIpString(0);
442 std::string SocketAddress::getPath() const {
444 throw std::invalid_argument(
445 "SocketAddress: attempting to get path "
446 "for a non-Unix address");
449 if (storage_.un.pathLength() == 0) {
451 return std::string();
453 if (storage_.un.addr->sun_path[0] == '\0') {
454 // abstract namespace
455 return std::string(storage_.un.addr->sun_path, storage_.un.pathLength());
458 return std::string(storage_.un.addr->sun_path,
459 strnlen(storage_.un.addr->sun_path,
460 storage_.un.pathLength()));
463 std::string SocketAddress::describe() const {
465 if (storage_.un.pathLength() == 0) {
466 return "<anonymous unix address>";
469 if (storage_.un.addr->sun_path[0] == '\0') {
470 // Linux supports an abstract namespace for unix socket addresses
471 return "<abstract unix address>";
474 return std::string(storage_.un.addr->sun_path,
475 strnlen(storage_.un.addr->sun_path,
476 storage_.un.pathLength()));
478 switch (getFamily()) {
480 return "<uninitialized address>";
483 char buf[NI_MAXHOST + 16];
484 getAddressStr(buf, sizeof(buf));
485 size_t iplen = strlen(buf);
486 snprintf(buf + iplen, sizeof(buf) - iplen, ":%" PRIu16, getPort());
491 char buf[NI_MAXHOST + 18];
493 getAddressStr(buf + 1, sizeof(buf) - 1);
494 size_t iplen = strlen(buf);
495 snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort());
501 snprintf(buf, sizeof(buf), "<unknown address family %d>",
508 bool SocketAddress::operator==(const SocketAddress& other) const {
509 if (external_ != other.external_ || other.getFamily() != getFamily()) {
513 // anonymous addresses are never equal to any other addresses
514 if (storage_.un.pathLength() == 0 ||
515 other.storage_.un.pathLength() == 0) {
519 if (storage_.un.len != other.storage_.un.len) {
522 int cmp = memcmp(storage_.un.addr->sun_path,
523 other.storage_.un.addr->sun_path,
524 storage_.un.pathLength());
528 switch (getFamily()) {
531 return (other.storage_.addr == storage_.addr) &&
532 (other.port_ == port_);
534 throw std::invalid_argument(
535 "SocketAddress: unsupported address family "
540 bool SocketAddress::prefixMatch(const SocketAddress& other,
541 unsigned prefixLength) const {
542 if (other.getFamily() != getFamily()) {
545 int mask_length = 128;
546 switch (getFamily()) {
552 auto prefix = folly::IPAddress::longestCommonPrefix(
553 {storage_.addr, mask_length},
554 {other.storage_.addr, mask_length});
555 return prefix.second >= prefixLength;
563 size_t SocketAddress::hash() const {
564 size_t seed = folly::hash::twang_mix64(getFamily());
567 enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) };
568 const char *path = storage_.un.addr->sun_path;
569 size_t pathLength = storage_.un.pathLength();
570 // TODO: this probably could be made more efficient
571 for (unsigned int n = 0; n < pathLength; ++n) {
572 boost::hash_combine(seed, folly::hash::twang_mix64(path[n]));
576 switch (getFamily()) {
579 boost::hash_combine(seed, port_);
580 boost::hash_combine(seed, storage_.addr.hash());
588 throw std::invalid_argument(
589 "SocketAddress: unsupported address family "
596 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
599 // getaddrinfo() requires the port number as a string
600 char portString[sizeof("65535")];
601 snprintf(portString, sizeof(portString), "%" PRIu16, port);
603 return getAddrInfo(host, portString, flags);
606 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
609 struct addrinfo hints;
610 memset(&hints, 0, sizeof(hints));
611 hints.ai_family = AF_UNSPEC;
612 hints.ai_socktype = SOCK_STREAM;
613 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | flags;
615 struct addrinfo *results;
616 int error = getaddrinfo(host, port, &hints, &results);
618 auto os = folly::to<std::string>(
619 "Failed to resolve address for \"", host, "\": ",
620 gai_strerror(error), " (error=", error, ")");
621 throw std::system_error(error, std::generic_category(), os);
627 void SocketAddress::setFromAddrInfo(const struct addrinfo* info) {
628 setFromSockaddr(info->ai_addr, info->ai_addrlen);
631 void SocketAddress::setFromLocalAddr(const struct addrinfo* info) {
632 // If an IPv6 address is present, prefer to use it, since IPv4 addresses
633 // can be mapped into IPv6 space.
634 for (const struct addrinfo* ai = info; ai != nullptr; ai = ai->ai_next) {
635 if (ai->ai_family == AF_INET6) {
636 setFromSockaddr(ai->ai_addr, ai->ai_addrlen);
641 // Otherwise, just use the first address in the list.
642 setFromSockaddr(info->ai_addr, info->ai_addrlen);
645 void SocketAddress::setFromSocket(SocketDesc socket, GetPeerNameFunc fn) {
646 // Try to put the address into a local storage buffer.
647 sockaddr_storage tmp_sock;
648 socklen_t addrLen = sizeof(tmp_sock);
649 if (fn(socket, (sockaddr*)&tmp_sock, &addrLen) != 0) {
650 folly::throwSystemError("setFromSocket() failed");
653 setFromSockaddr((sockaddr*)&tmp_sock, addrLen);
656 std::string SocketAddress::getIpString(int flags) const {
657 char addrString[NI_MAXHOST];
658 getIpString(addrString, sizeof(addrString), flags);
659 return std::string(addrString);
662 void SocketAddress::getIpString(char *buf, size_t buflen, int flags) const {
663 auto family = getFamily();
664 if (family != AF_INET &&
665 family != AF_INET6) {
666 throw std::invalid_argument(
667 "SocketAddress: attempting to get IP address "
668 "for a non-IP address");
671 sockaddr_storage tmp_sock;
672 storage_.addr.toSockaddrStorage(&tmp_sock, port_);
673 int rc = getnameinfo((sockaddr*)&tmp_sock, sizeof(sockaddr_storage),
674 buf, buflen, nullptr, 0, flags);
676 auto os = folly::to<std::string>(
677 "getnameinfo() failed in getIpString() error = ",
679 throw std::system_error(rc, std::generic_category(), os);
683 void SocketAddress::updateUnixAddressLength(socklen_t addrlen) {
684 if (addrlen < offsetof(struct sockaddr_un, sun_path)) {
685 throw std::invalid_argument(
686 "SocketAddress: attempted to set a Unix socket "
687 "with a length too short for a sockaddr_un");
690 storage_.un.len = addrlen;
691 if (storage_.un.pathLength() == 0) {
696 if (storage_.un.addr->sun_path[0] == '\0') {
697 // abstract namespace. honor the specified length
699 // Call strnlen(), just in case the length was overspecified.
700 socklen_t maxLength = addrlen - offsetof(struct sockaddr_un, sun_path);
701 size_t pathLength = strnlen(storage_.un.addr->sun_path, maxLength);
702 storage_.un.len = offsetof(struct sockaddr_un, sun_path) + pathLength;
706 bool SocketAddress::operator<(const SocketAddress& other) const {
707 if (getFamily() != other.getFamily()) {
708 return getFamily() < other.getFamily();
712 // Anonymous addresses can't be compared to anything else.
713 // Return that they are never less than anything.
715 // Note that this still meets the requirements for a strict weak
716 // ordering, so we can use this operator<() with standard C++ containers.
717 size_t thisPathLength = storage_.un.pathLength();
718 if (thisPathLength == 0) {
721 size_t otherPathLength = other.storage_.un.pathLength();
722 if (otherPathLength == 0) {
726 // Compare based on path length first, for efficiency
727 if (thisPathLength != otherPathLength) {
728 return thisPathLength < otherPathLength;
730 int cmp = memcmp(storage_.un.addr->sun_path,
731 other.storage_.un.addr->sun_path,
735 switch (getFamily()) {
738 if (port_ != other.port_) {
739 return port_ < other.port_;
743 storage_.addr < other.storage_.addr;
747 throw std::invalid_argument(
748 "SocketAddress: unsupported address family for comparing");
752 size_t hash_value(const SocketAddress& address) {
753 return address.hash();
756 std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) {
757 os << addr.describe();