[dart:io] Remove dependency on FIDL

ListInterfaces copied from Linux; Fuchsia's fdio implements getifaddrs
since https://fuchsia.googlesource.com/fuchsia/+/a8b1df8.

Change-Id: I6fa03dfa8a446551e4fa1ad3c0309ad51bb93310
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/159220
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Zach Anderson <zra@google.com>
diff --git a/build/fuchsia/dart.cmx b/build/fuchsia/dart.cmx
index f8f5750..d57d9ac 100644
--- a/build/fuchsia/dart.cmx
+++ b/build/fuchsia/dart.cmx
@@ -18,7 +18,6 @@
       "fuchsia.intl.PropertyProvider",
       "fuchsia.logger.LogSink",
       "fuchsia.net.NameLookup",
-      "fuchsia.netstack.Netstack",
       "fuchsia.posix.socket.Provider",
       "fuchsia.sysmem.Allocator",
       "fuchsia.timezone.Timezone",
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 2341506..a42626d 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -312,31 +312,18 @@
                  "..:dart_config",
                  "..:dart_precompiler_config",
                ] + extra_configs
-    deps = []
 
     if (is_fuchsia) {
       if (using_fuchsia_gn_sdk) {
-        deps += [
-          "$fuchsia_sdk_root/fidl/fuchsia.netstack",
-          "$fuchsia_sdk_root/pkg/sys_cpp",
-        ]
         public_deps = [ "$fuchsia_sdk_root/pkg/fdio" ]
       } else if (using_fuchsia_sdk) {
-        deps += [
-          "$fuchsia_sdk_root/fidl:fuchsia.netstack",
-          "$fuchsia_sdk_root/pkg:sys_cpp",
-        ]
         public_deps = [ "$fuchsia_sdk_root/pkg:fdio" ]
       } else {
-        deps += [
-          "//sdk/fidl/fuchsia.netstack",
-          "//sdk/lib/sys/cpp",
-        ]
         public_deps = [ "//sdk/lib/fdio" ]
       }
     }
 
-    deps += [ "//third_party/zlib" ]
+    deps = [ "//third_party/zlib" ]
 
     custom_sources_filter = [
       "*_test.cc",
@@ -458,22 +445,10 @@
 
     if (is_fuchsia) {
       if (using_fuchsia_gn_sdk) {
-        deps += [
-          "$fuchsia_sdk_root/fidl/fuchsia.netstack",
-          "$fuchsia_sdk_root/pkg/sys_cpp",
-        ]
         public_deps = [ "$fuchsia_sdk_root/pkg/fdio" ]
       } else if (using_fuchsia_sdk) {
-        deps += [
-          "$fuchsia_sdk_root/fidl:fuchsia.netstack",
-          "$fuchsia_sdk_root/pkg:sys_cpp",
-        ]
         public_deps = [ "$fuchsia_sdk_root/pkg:fdio" ]
       } else {
-        deps += [
-          "//sdk/fidl/fuchsia.netstack",
-          "//sdk/lib/sys/cpp",
-        ]
         public_deps = [ "//sdk/lib/fdio" ]
       }
     }
diff --git a/runtime/bin/socket_base_fuchsia.cc b/runtime/bin/socket_base_fuchsia.cc
index b76b6c6..be1eb256 100644
--- a/runtime/bin/socket_base_fuchsia.cc
+++ b/runtime/bin/socket_base_fuchsia.cc
@@ -8,9 +8,7 @@
 #include "bin/socket_base.h"
 
 #include <errno.h>
-#include <fuchsia/netstack/cpp/fidl.h>
 #include <ifaddrs.h>
-#include <lib/sys/cpp/service_directory.h>
 #include <net/if.h>
 #include <netinet/tcp.h>
 #include <stdio.h>
@@ -68,21 +66,10 @@
   memmove(reinterpret_cast<void*>(&addr_), sa, salen);
 }
 
-static fidl::SynchronousInterfacePtr<fuchsia::netstack::Netstack> netstack;
-static std::once_flag once;
 
 bool SocketBase::Initialize() {
-  static zx_status_t status;
-  std::call_once(once, [&]() {
-    auto directory = sys::ServiceDirectory::CreateFromNamespace();
-    status = directory->Connect(netstack.NewRequest());
-    if (status != ZX_OK) {
-      Syslog::PrintErr(
-          "Initialize: connecting to fuchsia.netstack failed: %s\n",
-          zx_status_get_string(status));
-    }
-  });
-  return status == ZX_OK;
+  // Nothing to do on Fuchsia.
+  return true;
 }
 
 bool SocketBase::FormatNumericAddress(const RawAddr& addr,
@@ -294,6 +281,17 @@
   }
 }
 
+static bool ShouldIncludeIfaAddrs(struct ifaddrs* ifa, int lookup_family) {
+  if (ifa->ifa_addr == NULL) {
+    // OpenVPN's virtual device tun0.
+    return false;
+  }
+  int family = ifa->ifa_addr->sa_family;
+  return ((lookup_family == family) ||
+          (((lookup_family == AF_UNSPEC) &&
+            ((family == AF_INET) || (family == AF_INET6)))));
+}
+
 bool SocketBase::ListInterfacesSupported() {
   return true;
 }
@@ -301,59 +299,38 @@
 AddressList<InterfaceSocketAddress>* SocketBase::ListInterfaces(
     int type,
     OSError** os_error) {
-  std::vector<fuchsia::netstack::NetInterface2> interfaces;
-  zx_status_t status = netstack->GetInterfaces2(&interfaces);
-  if (status != ZX_OK) {
-    LOG_ERR("ListInterfaces: fuchsia.netstack.GetInterfaces2 failed: %s\n",
-            zx_status_get_string(status));
-    errno = EIO;
+  struct ifaddrs* ifaddr;
+
+  int status = NO_RETRY_EXPECTED(getifaddrs(&ifaddr));
+  if (status != 0) {
+    ASSERT(*os_error == NULL);
+    *os_error =
+        new OSError(status, gai_strerror(status), OSError::kGetAddressInfo);
     return NULL;
   }
 
-  // Process the results.
-  const int lookup_family = SocketAddress::FromType(type);
+  int lookup_family = SocketAddress::FromType(type);
 
-  std::remove_if(
-      interfaces.begin(), interfaces.end(),
-      [lookup_family](const auto& interface) {
-        switch (interface.addr.Which()) {
-          case fuchsia::net::IpAddress::Tag::kIpv4:
-            return !(lookup_family == AF_UNSPEC || lookup_family == AF_INET);
-          case fuchsia::net::IpAddress::Tag::kIpv6:
-            return !(lookup_family == AF_UNSPEC || lookup_family == AF_INET6);
-          case fuchsia::net::IpAddress::Tag::Invalid:
-            return true;
-        }
-      });
-
-  auto addresses = new AddressList<InterfaceSocketAddress>(interfaces.size());
-  int addresses_idx = 0;
-  for (const auto& interface : interfaces) {
-    struct sockaddr_storage addr = {};
-    auto addr_in = reinterpret_cast<struct sockaddr_in*>(&addr);
-    auto addr_in6 = reinterpret_cast<struct sockaddr_in6*>(&addr);
-    switch (interface.addr.Which()) {
-      case fuchsia::net::IpAddress::Tag::kIpv4:
-        addr_in->sin_family = AF_INET;
-        memmove(&addr_in->sin_addr, interface.addr.ipv4().addr.data(),
-                sizeof(addr_in->sin_addr));
-        break;
-      case fuchsia::net::IpAddress::Tag::kIpv6:
-        addr_in6->sin6_family = AF_INET6;
-        memmove(&addr_in6->sin6_addr, interface.addr.ipv6().addr.data(),
-                sizeof(addr_in6->sin6_addr));
-        break;
-      case fuchsia::net::IpAddress::Tag::Invalid:
-        // Should have been filtered out above.
-        UNREACHABLE();
+  intptr_t count = 0;
+  for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+    if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
+      count++;
     }
-    addresses->SetAt(addresses_idx,
-                     new InterfaceSocketAddress(
-                         reinterpret_cast<sockaddr*>(&addr),
-                         DartUtils::ScopedCopyCString(interface.name.c_str()),
-                         if_nametoindex(interface.name.c_str())));
-    addresses_idx++;
   }
+
+  AddressList<InterfaceSocketAddress>* addresses =
+      new AddressList<InterfaceSocketAddress>(count);
+  int i = 0;
+  for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+    if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
+      char* ifa_name = DartUtils::ScopedCopyCString(ifa->ifa_name);
+      addresses->SetAt(
+          i, new InterfaceSocketAddress(ifa->ifa_addr, ifa_name,
+                                        if_nametoindex(ifa->ifa_name)));
+      i++;
+    }
+  }
+  freeifaddrs(ifaddr);
   return addresses;
 }