1111#include <stdlib.h>
1212#include <sys/types.h>
1313#include <assert.h>
14+ #if HAVE_IFADDRS || HAVE_GETIFADDRS
1415#include <ifaddrs.h>
16+ #endif
17+ #if !HAVE_GETIFADDRS && TARGET_ANDROID
18+ #include <dlfcn.h>
19+ #include <pthread.h>
20+ #endif
1521#include <net/if.h>
1622#include <netinet/in.h>
1723#include <string.h>
5561#endif
5662#endif
5763
58- #if HAVE_GETIFADDRS
5964// Convert mask to prefix length e.g. 255.255.255.0 -> 24
6065// mask parameter is pointer to buffer where address starts and length is
6166// buffer length e.g. 4 for IPv4 and 16 for IPv6.
@@ -95,14 +100,67 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length)
95100
96101 return len ;
97102}
103+
104+ #if !HAVE_IFADDRS && TARGET_ANDROID
105+ // This structure is exactly the same as struct ifaddrs defined in ifaddrs.h but since the header
106+ // might not be available (e.g., in bionics used in Android before API 24) we need to mirror it here
107+ // so that we can dynamically load the getifaddrs function and use it.
108+ struct ifaddrs
109+ {
110+ struct ifaddrs * ifa_next ;
111+ char * ifa_name ;
112+ unsigned int ifa_flags ;
113+ struct sockaddr * ifa_addr ;
114+ struct sockaddr * ifa_netmask ;
115+ union
116+ {
117+ struct sockaddr * ifu_broadaddr ;
118+ struct sockaddr * ifu_dstaddr ;
119+ } ifa_ifu ;
120+ void * ifa_data ;
121+ };
122+ #endif
123+
124+ #if !HAVE_GETIFADDRS && TARGET_ANDROID
125+ // Try to load the getifaddrs and freeifaddrs functions manually.
126+ // This workaround is necessary on Android prior to API 24 and it can be removed once
127+ // we drop support for earlier Android versions.
128+ static int (* getifaddrs )(struct ifaddrs * * ) = NULL ;
129+ static void (* freeifaddrs )(struct ifaddrs * ) = NULL ;
130+
131+ static void try_loading_getifaddrs ()
132+ {
133+ void * libc = dlopen ("libc.so" , RTLD_NOW );
134+ if (libc )
135+ {
136+ getifaddrs = (int (* )(struct ifaddrs * * )) dlsym (libc , "getifaddrs" );
137+ freeifaddrs = (void (* )(struct ifaddrs * )) dlsym (libc , "freeifaddrs" );
138+ }
139+ }
140+
141+ static bool ensure_getifaddrs_is_loaded ()
142+ {
143+ static pthread_once_t getifaddrs_is_loaded = PTHREAD_ONCE_INIT ;
144+ pthread_once (& getifaddrs_is_loaded , try_loading_getifaddrs );
145+ return getifaddrs != NULL && freeifaddrs != NULL ;
146+ }
98147#endif
99148
100149int32_t SystemNative_EnumerateInterfaceAddresses (void * context ,
101150 IPv4AddressFound onIpv4Found ,
102151 IPv6AddressFound onIpv6Found ,
103152 LinkLayerAddressFound onLinkLayerFound )
104153{
105- #if HAVE_GETIFADDRS
154+ #if !HAVE_GETIFADDRS && TARGET_ANDROID
155+ // Workaround for Android API < 24
156+ if (!ensure_getifaddrs_is_loaded ())
157+ {
158+ errno = ENOTSUP ;
159+ return -1 ;
160+ }
161+ #endif
162+
163+ #if HAVE_GETIFADDRS || TARGET_ANDROID
106164 struct ifaddrs * headAddr ;
107165 if (getifaddrs (& headAddr ) == -1 )
108166 {
@@ -235,7 +293,7 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context,
235293 freeifaddrs (headAddr );
236294 return 0 ;
237295#else
238- // Not supported on e.g. Android . Also, prevent a compiler error because parameters are unused
296+ // Not supported. Also, prevent a compiler error because parameters are unused
239297 (void )context ;
240298 (void )onIpv4Found ;
241299 (void )onIpv6Found ;
@@ -247,7 +305,16 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context,
247305
248306int32_t SystemNative_GetNetworkInterfaces (int32_t * interfaceCount , NetworkInterfaceInfo * * interfaceList , int32_t * addressCount , IpAddressInfo * * addressList )
249307{
250- #if HAVE_GETIFADDRS
308+ #if !HAVE_GETIFADDRS && TARGET_ANDROID
309+ // Workaround for Android API < 24
310+ if (!ensure_getifaddrs_is_loaded ())
311+ {
312+ errno = ENOTSUP ;
313+ return -1 ;
314+ }
315+ #endif
316+
317+ #if HAVE_GETIFADDRS || TARGET_ANDROID
251318 struct ifaddrs * head ; // Pointer to block allocated by getifaddrs().
252319 struct ifaddrs * ifaddrsEntry ;
253320 IpAddressInfo * ai ;
@@ -453,7 +520,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter
453520
454521 return 0 ;
455522#else
456- // Not supported on e.g. Android . Also, prevent a compiler error because parameters are unused
523+ // Not supported. Also, prevent a compiler error because parameters are unused
457524 (void )interfaceCount ;
458525 (void )interfaceList ;
459526 (void )addressCount ;
0 commit comments