|
7 | 7 |
|
8 | 8 | #include "bin/socket_base.h"
|
9 | 9 |
|
10 |
| -// TODO(ZX-766): If/when Fuchsia adds getifaddrs(), use that instead of the |
11 |
| -// ioctl in netconfig.h. |
12 |
| -#include <errno.h> // NOLINT |
13 |
| -#include <fcntl.h> // NOLINT |
14 |
| -#include <ifaddrs.h> // NOLINT |
15 |
| -#include <lib/netstack/c/netconfig.h> |
16 |
| -#include <net/if.h> // NOLINT |
17 |
| -#include <netinet/tcp.h> // NOLINT |
18 |
| -#include <stdio.h> // NOLINT |
19 |
| -#include <stdlib.h> // NOLINT |
20 |
| -#include <string.h> // NOLINT |
21 |
| -#include <sys/ioctl.h> // NOLINT |
22 |
| -#include <sys/stat.h> // NOLINT |
23 |
| -#include <unistd.h> // NOLINT |
| 10 | +#include <errno.h> |
| 11 | +#include <fuchsia/netstack/cpp/fidl.h> |
| 12 | +#include <ifaddrs.h> |
| 13 | +#include <lib/sys/cpp/service_directory.h> |
| 14 | +#include <net/if.h> |
| 15 | +#include <netinet/tcp.h> |
| 16 | +#include <stdio.h> |
| 17 | +#include <stdlib.h> |
| 18 | +#include <string.h> |
| 19 | +#include <sys/stat.h> |
| 20 | +#include <unistd.h> |
| 21 | +#include <vector> |
24 | 22 |
|
25 | 23 | #include "bin/eventhandler.h"
|
26 | 24 | #include "bin/fdutils.h"
|
@@ -66,9 +64,20 @@ SocketAddress::SocketAddress(struct sockaddr* sa) {
|
66 | 64 | memmove(reinterpret_cast<void*>(&addr_), sa, salen);
|
67 | 65 | }
|
68 | 66 |
|
| 67 | +static fidl::SynchronousInterfacePtr<fuchsia::netstack::Netstack> netstack; |
| 68 | +static zx_status_t status; |
| 69 | +static std::once_flag once; |
| 70 | + |
69 | 71 | bool SocketBase::Initialize() {
|
70 |
| - // Nothing to do on Fuchsia. |
71 |
| - return true; |
| 72 | + std::call_once(once, [&]() { |
| 73 | + auto directory = sys::ServiceDirectory::CreateFromNamespace(); |
| 74 | + status = directory->Connect(netstack.NewRequest()); |
| 75 | + if (status != ZX_OK) { |
| 76 | + LOG_ERR("Initialize: connecting to fuchsia.netstack failed: %s\n", |
| 77 | + zx_status_get_string(status)); |
| 78 | + } |
| 79 | + }); |
| 80 | + return status == ZX_OK; |
72 | 81 | }
|
73 | 82 |
|
74 | 83 | bool SocketBase::FormatNumericAddress(const RawAddr& addr,
|
@@ -264,68 +273,66 @@ bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) {
|
264 | 273 | return (result == 1);
|
265 | 274 | }
|
266 | 275 |
|
267 |
| -static bool ShouldIncludeIfaAddrs(netc_if_info_t* if_info, int lookup_family) { |
268 |
| - const int family = if_info->addr.ss_family; |
269 |
| - return ((lookup_family == family) || |
270 |
| - (((lookup_family == AF_UNSPEC) && |
271 |
| - ((family == AF_INET) || (family == AF_INET6))))); |
272 |
| -} |
273 |
| - |
274 | 276 | bool SocketBase::ListInterfacesSupported() {
|
275 | 277 | return true;
|
276 | 278 | }
|
277 | 279 |
|
278 | 280 | AddressList<InterfaceSocketAddress>* SocketBase::ListInterfaces(
|
279 | 281 | int type,
|
280 | 282 | OSError** os_error) {
|
281 |
| - // We need a dummy socket. |
282 |
| - const int fd = socket(AF_INET6, SOCK_STREAM, 0); |
283 |
| - if (fd < 0) { |
284 |
| - LOG_ERR("ListInterfaces: socket(AF_INET, SOCK_DGRAM, 0) failed\n"); |
| 283 | + std::vector<fuchsia::netstack::NetInterface2> interfaces; |
| 284 | + zx_status_t status = netstack->GetInterfaces2(&interfaces); |
| 285 | + if (status != ZX_OK) { |
| 286 | + LOG_ERR("ListInterfaces: fuchsia.netstack.GetInterfaces2 failed: %s\n", |
| 287 | + zx_status_get_string(status)); |
| 288 | + errno = EIO; |
285 | 289 | return NULL;
|
286 | 290 | }
|
287 | 291 |
|
288 |
| - // Call the ioctls. |
289 |
| - netc_get_if_info_t get_if_info; |
290 |
| - const ssize_t size = ioctl_netc_get_num_ifs(fd, &get_if_info.n_info); |
291 |
| - if (size < 0) { |
292 |
| - LOG_ERR("ListInterfaces: ioctl_netc_get_num_ifs() failed"); |
293 |
| - close(fd); |
294 |
| - return NULL; |
295 |
| - } |
296 |
| - for (uint32_t i = 0; i < get_if_info.n_info; i++) { |
297 |
| - const ssize_t size = |
298 |
| - ioctl_netc_get_if_info_at(fd, &i, &get_if_info.info[i]); |
299 |
| - if (size < 0) { |
300 |
| - LOG_ERR("ListInterfaces: ioctl_netc_get_if_info_at() failed"); |
301 |
| - close(fd); |
302 |
| - return NULL; |
303 |
| - } |
304 |
| - } |
305 |
| - |
306 | 292 | // Process the results.
|
307 | 293 | const int lookup_family = SocketAddress::FromType(type);
|
308 |
| - intptr_t count = 0; |
309 |
| - for (intptr_t i = 0; i < get_if_info.n_info; i++) { |
310 |
| - if (ShouldIncludeIfaAddrs(&get_if_info.info[i], lookup_family)) { |
311 |
| - count++; |
312 |
| - } |
313 |
| - } |
314 | 294 |
|
315 |
| - AddressList<InterfaceSocketAddress>* addresses = |
316 |
| - new AddressList<InterfaceSocketAddress>(count); |
| 295 | + std::remove_if( |
| 296 | + interfaces.begin(), interfaces.end(), |
| 297 | + [lookup_family](const auto& interface) { |
| 298 | + switch (interface.addr.Which()) { |
| 299 | + case fuchsia::net::IpAddress::Tag::kIpv4: |
| 300 | + return !(lookup_family == AF_UNSPEC || lookup_family == AF_INET); |
| 301 | + case fuchsia::net::IpAddress::Tag::kIpv6: |
| 302 | + return !(lookup_family == AF_UNSPEC || lookup_family == AF_INET6); |
| 303 | + case fuchsia::net::IpAddress::Tag::Invalid: |
| 304 | + return true; |
| 305 | + } |
| 306 | + }); |
| 307 | + |
| 308 | + auto addresses = new AddressList<InterfaceSocketAddress>(interfaces.size()); |
317 | 309 | int addresses_idx = 0;
|
318 |
| - for (intptr_t i = 0; i < get_if_info.n_info; i++) { |
319 |
| - if (ShouldIncludeIfaAddrs(&get_if_info.info[i], lookup_family)) { |
320 |
| - char* ifa_name = DartUtils::ScopedCopyCString(get_if_info.info[i].name); |
321 |
| - InterfaceSocketAddress* isa = new InterfaceSocketAddress( |
322 |
| - reinterpret_cast<struct sockaddr*>(&get_if_info.info[i].addr), |
323 |
| - ifa_name, if_nametoindex(get_if_info.info[i].name)); |
324 |
| - addresses->SetAt(addresses_idx, isa); |
325 |
| - addresses_idx++; |
| 310 | + for (const auto& interface : interfaces) { |
| 311 | + struct sockaddr_storage addr = {}; |
| 312 | + auto addr_in = reinterpret_cast<struct sockaddr_in*>(&addr); |
| 313 | + auto addr_in6 = reinterpret_cast<struct sockaddr_in6*>(&addr); |
| 314 | + switch (interface.addr.Which()) { |
| 315 | + case fuchsia::net::IpAddress::Tag::kIpv4: |
| 316 | + addr_in->sin_family = AF_INET; |
| 317 | + memmove(&addr_in->sin_addr, interface.addr.ipv4().addr.data(), |
| 318 | + sizeof(addr_in->sin_addr)); |
| 319 | + break; |
| 320 | + case fuchsia::net::IpAddress::Tag::kIpv6: |
| 321 | + addr_in6->sin6_family = AF_INET6; |
| 322 | + memmove(&addr_in6->sin6_addr, interface.addr.ipv6().addr.data(), |
| 323 | + sizeof(addr_in6->sin6_addr)); |
| 324 | + break; |
| 325 | + case fuchsia::net::IpAddress::Tag::Invalid: |
| 326 | + // Should have been filtered out above. |
| 327 | + UNREACHABLE(); |
326 | 328 | }
|
| 329 | + addresses->SetAt(addresses_idx, |
| 330 | + new InterfaceSocketAddress( |
| 331 | + reinterpret_cast<sockaddr*>(&addr), |
| 332 | + DartUtils::ScopedCopyCString(interface.name.c_str()), |
| 333 | + if_nametoindex(interface.name.c_str()))); |
| 334 | + addresses_idx++; |
327 | 335 | }
|
328 |
| - close(fd); |
329 | 336 | return addresses;
|
330 | 337 | }
|
331 | 338 |
|
|
0 commit comments