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>
26 #include <boost/static_assert.hpp>
36 * A structure to free a struct addrinfo when it goes out of scope.
38 struct ScopedAddrInfo {
39 explicit ScopedAddrInfo(struct addrinfo* info) : info(info) {}
44 struct addrinfo* info;
48 * A simple data structure for parsing a host-and-port string.
50 * Accepts a string of the form "<host>:<port>" or just "<port>",
51 * and contains two string pointers to the host and the port portion of the
54 * The HostAndPort may contain pointers into the original string. It is
55 * responsible for the user to ensure that the input string is valid for the
56 * lifetime of the HostAndPort structure.
59 HostAndPort(const char* str, bool hostRequired)
64 // Look for the last colon
65 const char* colon = strrchr(str, ':');
66 if (colon == nullptr) {
67 // No colon, just a port number.
69 throw std::invalid_argument(
70 "expected a host and port string of the "
71 "form \"<host>:<port>\"");
77 // We have to make a copy of the string so we can modify it
78 // and change the colon to a NUL terminator.
79 allocated = strdup(str);
81 throw std::bad_alloc();
84 char *allocatedColon = allocated + (colon - str);
85 *allocatedColon = '\0';
87 port = allocatedColon + 1;
88 // bracketed IPv6 address, remove the brackets
89 // allocatedColon[-1] is fine, as allocatedColon >= host and
90 // *allocatedColon != *host therefore allocatedColon > host
91 if (*host == '[' && allocatedColon[-1] == ']') {
92 allocatedColon[-1] = '\0';
106 } // unnamed namespace
110 bool SocketAddress::isPrivateAddress() const {
111 auto family = getFamily();
112 if (family == AF_INET || family == AF_INET6) {
113 return storage_.addr.isPrivate() ||
114 (storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal());
115 } else if (external_) {
116 // Unix addresses are always local to a host. Return true,
117 // since this conforms to the semantics of returning true for IP loopback
124 bool SocketAddress::isLoopbackAddress() const {
125 auto family = getFamily();
126 if (family == AF_INET || family == AF_INET6) {
127 return storage_.addr.isLoopback();
128 } else if (external_) {
129 // Return true for UNIX addresses, since they are always local to a host.
135 void SocketAddress::setFromHostPort(const char* host, uint16_t port) {
136 ScopedAddrInfo results(getAddrInfo(host, port, 0));
137 setFromAddrInfo(results.info);
140 void SocketAddress::setFromIpPort(const char* ip, uint16_t port) {
141 ScopedAddrInfo results(getAddrInfo(ip, port, AI_NUMERICHOST));
142 setFromAddrInfo(results.info);
145 void SocketAddress::setFromIpAddrPort(const IPAddress& ipAddr, uint16_t port) {
150 storage_.addr = ipAddr;
154 void SocketAddress::setFromLocalPort(uint16_t port) {
155 ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
156 setFromLocalAddr(results.info);
159 void SocketAddress::setFromLocalPort(const char* port) {
160 ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
161 setFromLocalAddr(results.info);
164 void SocketAddress::setFromLocalIpPort(const char* addressAndPort) {
165 HostAndPort hp(addressAndPort, false);
166 ScopedAddrInfo results(getAddrInfo(hp.host, hp.port,
167 AI_NUMERICHOST | AI_ADDRCONFIG));
168 setFromLocalAddr(results.info);
171 void SocketAddress::setFromIpPort(const char* addressAndPort) {
172 HostAndPort hp(addressAndPort, true);
173 ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, AI_NUMERICHOST));
174 setFromAddrInfo(results.info);
177 void SocketAddress::setFromHostPort(const char* hostAndPort) {
178 HostAndPort hp(hostAndPort, true);
179 ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, 0));
180 setFromAddrInfo(results.info);
183 void SocketAddress::setFromPath(StringPiece path) {
184 // Before we touch storage_, check to see if the length is too big.
185 // Note that "storage_.un.addr->sun_path" may not be safe to evaluate here,
186 // but sizeof() just uses its type, and does't evaluate it.
187 if (path.size() > sizeof(storage_.un.addr->sun_path)) {
188 throw std::invalid_argument(
189 "socket path too large to fit into sockaddr_un");
197 size_t len = path.size();
198 storage_.un.len = offsetof(struct sockaddr_un, sun_path) + len;
199 memcpy(storage_.un.addr->sun_path, path.data(), len);
200 // If there is room, put a terminating NUL byte in sun_path. In general the
201 // path should be NUL terminated, although getsockname() and getpeername()
202 // may return Unix socket addresses with paths that fit exactly in sun_path
203 // with no terminating NUL.
204 if (len < sizeof(storage_.un.addr->sun_path)) {
205 storage_.un.addr->sun_path[len] = '\0';
209 void SocketAddress::setFromPeerAddress(SocketDesc socket) {
210 setFromSocket(socket, getpeername);
213 void SocketAddress::setFromLocalAddress(SocketDesc socket) {
214 setFromSocket(socket, getsockname);
217 void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
220 if (address->sa_family == AF_INET) {
221 port = ntohs(((sockaddr_in*)address)->sin_port);
222 } else if (address->sa_family == AF_INET6) {
223 port = ntohs(((sockaddr_in6*)address)->sin6_port);
224 } else if (address->sa_family == AF_UNIX) {
225 // We need an explicitly specified length for AF_UNIX addresses,
226 // to be able to distinguish anonymous addresses from addresses
227 // in Linux's abstract namespace.
228 throw std::invalid_argument(
229 "SocketAddress::setFromSockaddr(): the address "
230 "length must be explicitly specified when "
231 "setting AF_UNIX addresses");
233 throw std::invalid_argument(
234 "SocketAddress::setFromSockaddr() called "
235 "with unsupported address type");
238 setFromIpAddrPort(folly::IPAddress(address), port);
241 void SocketAddress::setFromSockaddr(const struct sockaddr* address,
243 // Check the length to make sure we can access address->sa_family
244 if (addrlen < (offsetof(struct sockaddr, sa_family) +
245 sizeof(address->sa_family))) {
246 throw std::invalid_argument(
247 "SocketAddress::setFromSockaddr() called "
248 "with length too short for a sockaddr");
251 if (address->sa_family == AF_INET) {
252 if (addrlen < sizeof(struct sockaddr_in)) {
253 throw std::invalid_argument(
254 "SocketAddress::setFromSockaddr() called "
255 "with length too short for a sockaddr_in");
257 setFromSockaddr(reinterpret_cast<const struct sockaddr_in*>(address));
258 } else if (address->sa_family == AF_INET6) {
259 if (addrlen < sizeof(struct sockaddr_in6)) {
260 throw std::invalid_argument(
261 "SocketAddress::setFromSockaddr() called "
262 "with length too short for a sockaddr_in6");
264 setFromSockaddr(reinterpret_cast<const struct sockaddr_in6*>(address));
265 } else if (address->sa_family == AF_UNIX) {
266 setFromSockaddr(reinterpret_cast<const struct sockaddr_un*>(address),
269 throw std::invalid_argument(
270 "SocketAddress::setFromSockaddr() called "
271 "with unsupported address type");
275 void SocketAddress::setFromSockaddr(const struct sockaddr_in* address) {
276 assert(address->sin_family == AF_INET);
277 setFromSockaddr((sockaddr*)address);
280 void SocketAddress::setFromSockaddr(const struct sockaddr_in6* address) {
281 assert(address->sin6_family == AF_INET6);
282 setFromSockaddr((sockaddr*)address);
285 void SocketAddress::setFromSockaddr(const struct sockaddr_un* address,
287 assert(address->sun_family == AF_UNIX);
288 if (addrlen > sizeof(struct sockaddr_un)) {
289 throw std::invalid_argument(
290 "SocketAddress::setFromSockaddr() called "
291 "with length too long for a sockaddr_un");
294 prepFamilyChange(AF_UNIX);
295 memcpy(storage_.un.addr, address, addrlen);
296 updateUnixAddressLength(addrlen);
298 // Fill the rest with 0s, just for safety
299 if (addrlen < sizeof(struct sockaddr_un)) {
300 char *p = reinterpret_cast<char*>(storage_.un.addr);
301 memset(p + addrlen, 0, sizeof(struct sockaddr_un) - addrlen);
305 const folly::IPAddress& SocketAddress::getIPAddress() const {
306 auto family = getFamily();
307 if (family != AF_INET && family != AF_INET6) {
308 throw InvalidAddressFamilyException(family);
310 return storage_.addr;
313 socklen_t SocketAddress::getActualSize() const {
315 return storage_.un.len;
317 switch (getFamily()) {
320 return sizeof(struct sockaddr_in);
322 return sizeof(struct sockaddr_in6);
324 throw std::invalid_argument(
325 "SocketAddress::getActualSize() called "
326 "with unrecognized address family");
330 std::string SocketAddress::getFullyQualified() const {
331 auto family = getFamily();
332 if (family != AF_INET && family != AF_INET6) {
333 throw std::invalid_argument("Can't get address str for non ip address");
335 return storage_.addr.toFullyQualified();
338 std::string SocketAddress::getAddressStr() const {
339 char buf[INET6_ADDRSTRLEN];
340 getAddressStr(buf, sizeof(buf));
344 void SocketAddress::getAddressStr(char* buf, size_t buflen) const {
345 auto family = getFamily();
346 if (family != AF_INET && family != AF_INET6) {
347 throw std::invalid_argument("Can't get address str for non ip address");
349 std::string ret = storage_.addr.str();
350 size_t len = std::min(buflen, ret.size());
351 memcpy(buf, ret.data(), len);
355 uint16_t SocketAddress::getPort() const {
356 switch (getFamily()) {
361 throw std::invalid_argument(
362 "SocketAddress::getPort() called on non-IP "
367 void SocketAddress::setPort(uint16_t port) {
368 switch (getFamily()) {
374 throw std::invalid_argument(
375 "SocketAddress::setPort() called on non-IP "
380 void SocketAddress::convertToIPv4() {
381 if (!tryConvertToIPv4()) {
382 throw std::invalid_argument(
383 "convertToIPv4() called on an addresse that is "
384 "not an IPv4-mapped address");
388 bool SocketAddress::tryConvertToIPv4() {
389 if (!isIPv4Mapped()) {
393 storage_.addr = folly::IPAddress::createIPv4(storage_.addr);
397 bool SocketAddress::mapToIPv6() {
398 if (getFamily() != AF_INET) {
402 storage_.addr = folly::IPAddress::createIPv6(storage_.addr);
406 std::string SocketAddress::getHostStr() const {
407 return getIpString(0);
410 std::string SocketAddress::getPath() const {
412 throw std::invalid_argument(
413 "SocketAddress: attempting to get path "
414 "for a non-Unix address");
417 if (storage_.un.pathLength() == 0) {
419 return std::string();
421 if (storage_.un.addr->sun_path[0] == '\0') {
422 // abstract namespace
423 return std::string(storage_.un.addr->sun_path, storage_.un.pathLength());
426 return std::string(storage_.un.addr->sun_path,
427 strnlen(storage_.un.addr->sun_path,
428 storage_.un.pathLength()));
431 std::string SocketAddress::describe() const {
433 if (storage_.un.pathLength() == 0) {
434 return "<anonymous unix address>";
437 if (storage_.un.addr->sun_path[0] == '\0') {
438 // Linux supports an abstract namespace for unix socket addresses
439 return "<abstract unix address>";
442 return std::string(storage_.un.addr->sun_path,
443 strnlen(storage_.un.addr->sun_path,
444 storage_.un.pathLength()));
446 switch (getFamily()) {
448 return "<uninitialized address>";
451 char buf[NI_MAXHOST + 16];
452 getAddressStr(buf, sizeof(buf));
453 size_t iplen = strlen(buf);
454 snprintf(buf + iplen, sizeof(buf) - iplen, ":%" PRIu16, getPort());
459 char buf[NI_MAXHOST + 18];
461 getAddressStr(buf + 1, sizeof(buf) - 1);
462 size_t iplen = strlen(buf);
463 snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort());
469 snprintf(buf, sizeof(buf), "<unknown address family %d>",
476 bool SocketAddress::operator==(const SocketAddress& other) const {
477 if (external_ != other.external_ || other.getFamily() != getFamily()) {
481 // anonymous addresses are never equal to any other addresses
482 if (storage_.un.pathLength() == 0 ||
483 other.storage_.un.pathLength() == 0) {
487 if (storage_.un.len != other.storage_.un.len) {
490 int cmp = memcmp(storage_.un.addr->sun_path,
491 other.storage_.un.addr->sun_path,
492 storage_.un.pathLength());
496 switch (getFamily()) {
499 return (other.storage_.addr == storage_.addr) &&
500 (other.port_ == port_);
502 throw std::invalid_argument(
503 "SocketAddress: unsupported address family "
508 bool SocketAddress::prefixMatch(const SocketAddress& other,
509 unsigned prefixLength) const {
510 if (other.getFamily() != getFamily()) {
513 int mask_length = 128;
514 switch (getFamily()) {
520 auto prefix = folly::IPAddress::longestCommonPrefix(
521 {storage_.addr, mask_length},
522 {other.storage_.addr, mask_length});
523 return prefix.second >= prefixLength;
531 size_t SocketAddress::hash() const {
532 size_t seed = folly::hash::twang_mix64(getFamily());
535 enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) };
536 const char *path = storage_.un.addr->sun_path;
537 size_t pathLength = storage_.un.pathLength();
538 // TODO: this probably could be made more efficient
539 for (unsigned int n = 0; n < pathLength; ++n) {
540 boost::hash_combine(seed, folly::hash::twang_mix64(path[n]));
544 switch (getFamily()) {
547 boost::hash_combine(seed, port_);
548 boost::hash_combine(seed, storage_.addr.hash());
556 throw std::invalid_argument(
557 "SocketAddress: unsupported address family "
564 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
567 // getaddrinfo() requires the port number as a string
568 char portString[sizeof("65535")];
569 snprintf(portString, sizeof(portString), "%" PRIu16, port);
571 return getAddrInfo(host, portString, flags);
574 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
577 struct addrinfo hints;
578 memset(&hints, 0, sizeof(hints));
579 hints.ai_family = AF_UNSPEC;
580 hints.ai_socktype = SOCK_STREAM;
581 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | flags;
583 struct addrinfo *results;
584 int error = getaddrinfo(host, port, &hints, &results);
586 auto os = folly::to<std::string>(
587 "Failed to resolve address for \"", host, "\": ",
588 gai_strerror(error), " (error=", error, ")");
589 throw std::system_error(error, std::generic_category(), os);
595 void SocketAddress::setFromAddrInfo(const struct addrinfo* info) {
596 setFromSockaddr(info->ai_addr, info->ai_addrlen);
599 void SocketAddress::setFromLocalAddr(const struct addrinfo* info) {
600 // If an IPv6 address is present, prefer to use it, since IPv4 addresses
601 // can be mapped into IPv6 space.
602 for (const struct addrinfo* ai = info; ai != nullptr; ai = ai->ai_next) {
603 if (ai->ai_family == AF_INET6) {
604 setFromSockaddr(ai->ai_addr, ai->ai_addrlen);
609 // Otherwise, just use the first address in the list.
610 setFromSockaddr(info->ai_addr, info->ai_addrlen);
613 void SocketAddress::setFromSocket(SocketDesc socket, GetPeerNameFunc fn) {
614 // Try to put the address into a local storage buffer.
615 sockaddr_storage tmp_sock;
616 socklen_t addrLen = sizeof(tmp_sock);
617 if (fn(socket, (sockaddr*)&tmp_sock, &addrLen) != 0) {
618 folly::throwSystemError("setFromSocket() failed");
621 setFromSockaddr((sockaddr*)&tmp_sock, addrLen);
624 std::string SocketAddress::getIpString(int flags) const {
625 char addrString[NI_MAXHOST];
626 getIpString(addrString, sizeof(addrString), flags);
627 return std::string(addrString);
630 void SocketAddress::getIpString(char *buf, size_t buflen, int flags) const {
631 auto family = getFamily();
632 if (family != AF_INET &&
633 family != AF_INET6) {
634 throw std::invalid_argument(
635 "SocketAddress: attempting to get IP address "
636 "for a non-IP address");
639 sockaddr_storage tmp_sock;
640 storage_.addr.toSockaddrStorage(&tmp_sock, port_);
641 int rc = getnameinfo((sockaddr*)&tmp_sock, sizeof(sockaddr_storage),
642 buf, buflen, nullptr, 0, flags);
644 auto os = folly::to<std::string>(
645 "getnameinfo() failed in getIpString() error = ",
647 throw std::system_error(rc, std::generic_category(), os);
651 void SocketAddress::updateUnixAddressLength(socklen_t addrlen) {
652 if (addrlen < offsetof(struct sockaddr_un, sun_path)) {
653 throw std::invalid_argument(
654 "SocketAddress: attempted to set a Unix socket "
655 "with a length too short for a sockaddr_un");
658 storage_.un.len = addrlen;
659 if (storage_.un.pathLength() == 0) {
664 if (storage_.un.addr->sun_path[0] == '\0') {
665 // abstract namespace. honor the specified length
667 // Call strnlen(), just in case the length was overspecified.
668 socklen_t maxLength = addrlen - offsetof(struct sockaddr_un, sun_path);
669 size_t pathLength = strnlen(storage_.un.addr->sun_path, maxLength);
670 storage_.un.len = offsetof(struct sockaddr_un, sun_path) + pathLength;
674 bool SocketAddress::operator<(const SocketAddress& other) const {
675 if (getFamily() != other.getFamily()) {
676 return getFamily() < other.getFamily();
680 // Anonymous addresses can't be compared to anything else.
681 // Return that they are never less than anything.
683 // Note that this still meets the requirements for a strict weak
684 // ordering, so we can use this operator<() with standard C++ containers.
685 size_t thisPathLength = storage_.un.pathLength();
686 if (thisPathLength == 0) {
689 size_t otherPathLength = other.storage_.un.pathLength();
690 if (otherPathLength == 0) {
694 // Compare based on path length first, for efficiency
695 if (thisPathLength != otherPathLength) {
696 return thisPathLength < otherPathLength;
698 int cmp = memcmp(storage_.un.addr->sun_path,
699 other.storage_.un.addr->sun_path,
703 switch (getFamily()) {
706 if (port_ != other.port_) {
707 return port_ < other.port_;
711 storage_.addr < other.storage_.addr;
715 throw std::invalid_argument(
716 "SocketAddress: unsupported address family for comparing");
720 size_t hash_value(const SocketAddress& address) {
721 return address.hash();
724 std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) {
725 os << addr.describe();