未验证 提交 1de4a5ca 编写于 作者: S Simon Rozsival 提交者: GitHub

[Android] Port getifaddrs implementation from Xamarin.Android (#71943)

In recent Android versions the data returned by getifaddrs is invalid and doesn't allow us to implement System.Net.NetworkInformation.GetAllNetworkInterfaces(). It's possible to reimplement getifaddrs using Netlink and there's already an existing implementation in Xamarin.Android.

Fixes xamarin/xamarin-android#6973
Ref #62780
Ref #51303
上级 6e33ec9a
......@@ -517,9 +517,6 @@
/* Have getifaddrs */
#cmakedefine HAVE_GETIFADDRS 1
/* Have struct ifaddrs */
#cmakedefine HAVE_IFADDRS 1
/* Have access */
#cmakedefine HAVE_ACCESS 1
......
......@@ -11,7 +11,6 @@
#cmakedefine01 HAVE_F_FULLFSYNC
#cmakedefine01 HAVE_O_CLOEXEC
#cmakedefine01 HAVE_GETIFADDRS
#cmakedefine01 HAVE_IFADDRS
#cmakedefine01 HAVE_UTSNAME_DOMAINNAME
#cmakedefine01 HAVE_STAT64
#cmakedefine01 HAVE_FORK
......
......@@ -83,6 +83,13 @@ include(${CMAKE_CURRENT_LIST_DIR}/extra_libs.cmake)
set(NATIVE_LIBS_EXTRA)
append_extra_system_libs(NATIVE_LIBS_EXTRA)
if (CLR_CMAKE_TARGET_ANDROID)
add_compile_options(-Wno-gnu-zero-variadic-macro-arguments)
list (APPEND NATIVE_LIBS_EXTRA -llog)
list (APPEND NATIVE_SOURCES pal_ifaddrs.c)
endif ()
if (GEN_SHARED_LIB)
add_library(System.Native
SHARED
......
此差异已折叠。
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#pragma once
#ifndef TARGET_ANDROID
#error The pal_ifaddrs.h shim is intended only for Android
#endif
// Android doesn't include the getifaddrs and freeifaddrs functions in older Bionic libc (pre API 24).
// In recent Android versions (Android 11+) the data returned by the getifaddrs function is not valid.
// This shim is a port of Xamarin Android's implementation of getifaddrs using Netlink.
#include "pal_compiler.h"
#include "pal_config.h"
#include "pal_types.h"
#include <sys/cdefs.h>
#include <netinet/in.h>
#include <sys/socket.h>
struct ifaddrs
{
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
union
{
struct sockaddr *ifu_broadaddr;
struct sockaddr *ifu_dstaddr;
} ifa_ifu;
void *ifa_data;
};
// Synonym for `ifa_ifu.ifu_broadaddr` in `struct ifaddrs`.
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
// Synonym for `ifa_ifu.ifu_dstaddr` in `struct ifaddrs`.
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
int getifaddrs (struct ifaddrs **ifap);
void freeifaddrs (struct ifaddrs *ifap);
......@@ -11,12 +11,11 @@
#include <stdlib.h>
#include <sys/types.h>
#include <assert.h>
#if HAVE_IFADDRS || HAVE_GETIFADDRS
#if HAVE_GETIFADDRS && !defined(TARGET_ANDROID)
#include <ifaddrs.h>
#endif
#if !HAVE_GETIFADDRS && TARGET_ANDROID
#include <dlfcn.h>
#include <pthread.h>
#ifdef TARGET_ANDROID
#include "pal_ifaddrs.h"
#endif
#include <net/if.h>
#include <netinet/in.h>
......@@ -101,66 +100,12 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length)
return len;
}
#if !HAVE_IFADDRS && TARGET_ANDROID
// This structure is exactly the same as struct ifaddrs defined in ifaddrs.h but since the header
// might not be available (e.g., in bionics used in Android before API 24) we need to mirror it here
// so that we can dynamically load the getifaddrs function and use it.
struct ifaddrs
{
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
union
{
struct sockaddr *ifu_broadaddr;
struct sockaddr *ifu_dstaddr;
} ifa_ifu;
void *ifa_data;
};
#endif
#if !HAVE_GETIFADDRS && TARGET_ANDROID
// Try to load the getifaddrs and freeifaddrs functions manually.
// This workaround is necessary on Android prior to API 24 and it can be removed once
// we drop support for earlier Android versions.
static int (*getifaddrs)(struct ifaddrs**) = NULL;
static void (*freeifaddrs)(struct ifaddrs*) = NULL;
static void try_loading_getifaddrs()
{
void *libc = dlopen("libc.so", RTLD_NOW);
if (libc)
{
getifaddrs = (int (*)(struct ifaddrs**)) dlsym(libc, "getifaddrs");
freeifaddrs = (void (*)(struct ifaddrs*)) dlsym(libc, "freeifaddrs");
}
}
static bool ensure_getifaddrs_is_loaded()
{
static pthread_once_t getifaddrs_is_loaded = PTHREAD_ONCE_INIT;
pthread_once(&getifaddrs_is_loaded, try_loading_getifaddrs);
return getifaddrs != NULL && freeifaddrs != NULL;
}
#endif
int32_t SystemNative_EnumerateInterfaceAddresses(void* context,
IPv4AddressFound onIpv4Found,
IPv6AddressFound onIpv6Found,
LinkLayerAddressFound onLinkLayerFound)
{
#if !HAVE_GETIFADDRS && TARGET_ANDROID
// Workaround for Android API < 24
if (!ensure_getifaddrs_is_loaded())
{
errno = ENOTSUP;
return -1;
}
#endif
#if HAVE_GETIFADDRS || TARGET_ANDROID
#if HAVE_GETIFADDRS || defined(TARGET_ANDROID)
struct ifaddrs* headAddr;
if (getifaddrs(&headAddr) == -1)
{
......@@ -305,16 +250,7 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context,
int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInterfaceInfo **interfaceList, int32_t * addressCount, IpAddressInfo **addressList )
{
#if !HAVE_GETIFADDRS && TARGET_ANDROID
// Workaround for Android API < 24
if (!ensure_getifaddrs_is_loaded())
{
errno = ENOTSUP;
return -1;
}
#endif
#if HAVE_GETIFADDRS || TARGET_ANDROID
#if HAVE_GETIFADDRS || defined(TARGET_ANDROID)
struct ifaddrs* head; // Pointer to block allocated by getifaddrs().
struct ifaddrs* ifaddrsEntry;
IpAddressInfo *ai;
......
......@@ -121,18 +121,6 @@ check_c_source_compiles(
"
HAVE_FLOCK64)
check_c_source_compiles(
"
#include <sys/types.h>
#include <ifaddrs.h>
int main(void)
{
struct ifaddrs ia;
return 0;
}
"
HAVE_IFADDRS)
check_symbol_exists(
O_CLOEXEC
fcntl.h
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册