Support if_indextoname in the socket portability header
[folly.git] / folly / IPAddressV6.cpp
index 29450f4b08ac6c35c5a7ee398343ac1195a75381..3490669dcbdd72db0cf2484c24e3e6708c045970 100644 (file)
 #include <folly/MacAddress.h>
 #include <folly/detail/IPAddressSource.h>
 
 #include <folly/MacAddress.h>
 #include <folly/detail/IPAddressSource.h>
 
+#if !_WIN32
+#include <net/if.h>
+#else
+// Because of the massive pain that is libnl, this can't go into the socket
+// portability header as you can't include <linux/if.h> and <net/if.h> in
+// the same translation unit without getting errors -_-...
+#include <iphlpapi.h>
+#include <ntddndis.h>
+
+// Alias the max size of an interface name to what posix expects.
+#define IFNAMSIZ IF_NAMESIZE
+#endif
+
 using std::ostream;
 using std::string;
 
 using std::ostream;
 using std::string;
 
@@ -403,30 +416,36 @@ IPAddressV6 IPAddressV6::mask(size_t numBits) const {
 
 // public
 string IPAddressV6::str() const {
 
 // public
 string IPAddressV6::str() const {
-  char buffer[INET6_ADDRSTRLEN] = {0};
-  sockaddr_in6 sock = toSockAddr();
-  int error = getnameinfo(
-      (sockaddr*)&sock,
-      sizeof(sock),
-      buffer,
-      INET6_ADDRSTRLEN,
-      nullptr,
-      0,
-      NI_NUMERICHOST);
-  if (!error) {
-    string ip(buffer);
-    return ip;
-  } else {
+  char buffer[INET6_ADDRSTRLEN + IFNAMSIZ + 1];
+
+  if (!inet_ntop(AF_INET6, toAddr().s6_addr, buffer, INET6_ADDRSTRLEN)) {
     throw IPAddressFormatException(to<std::string>(
         "Invalid address with hex ",
         "'",
         detail::Bytes::toHex(bytes(), 16),
     throw IPAddressFormatException(to<std::string>(
         "Invalid address with hex ",
         "'",
         detail::Bytes::toHex(bytes(), 16),
-        "%",
-        sock.sin6_scope_id,
         "'",
         "'",
-        " with error ",
-        gai_strerror(error)));
+        " with error ",
+        strerror(errno)));
   }
   }
+
+  auto scopeId = getScopeId();
+  if (scopeId != 0) {
+    auto len = strlen(buffer);
+    buffer[len] = '%';
+    if (!if_indextoname(scopeId, buffer + len + 1)) {
+      throw IPAddressFormatException(to<std::string>(
+          "Invalid scope for address with hex ",
+          "'",
+          detail::Bytes::toHex(bytes(), 16),
+          "%",
+          scopeId,
+          "'",
+          " with error ",
+          strerror(errno)));
+    }
+  }
+
+  return string(buffer);
 }
 
 // public
 }
 
 // public