11
11
#include <stdlib.h>
12
12
#include <sys/types.h>
13
13
#include <assert.h>
14
- #if HAVE_GETIFADDRS && ! defined(TARGET_ANDROID )
14
+ #if HAVE_GETIFADDRS || defined(ANDROID_GETIFADDRS_WORKAROUND )
15
15
#include <ifaddrs.h>
16
16
#endif
17
- #ifdef TARGET_ANDROID
18
- #include "pal_ifaddrs.h"
17
+ #ifdef ANDROID_GETIFADDRS_WORKAROUND
18
+ #include <dlfcn.h>
19
+ #include <pthread.h>
19
20
#endif
20
21
#include <net/if.h>
21
22
#include <netinet/in.h>
@@ -100,12 +101,45 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length)
100
101
return len ;
101
102
}
102
103
104
+ #ifdef ANDROID_GETIFADDRS_WORKAROUND
105
+ // Try to load the getifaddrs and freeifaddrs functions manually.
106
+ // This workaround is necessary on Android prior to API 24 and it can be removed once
107
+ // we drop support for earlier Android versions.
108
+ static int (* getifaddrs )(struct ifaddrs * * ) = NULL ;
109
+ static void (* freeifaddrs )(struct ifaddrs * ) = NULL ;
110
+
111
+ static void try_loading_getifaddrs ()
112
+ {
113
+ void * libc = dlopen ("libc.so" , RTLD_NOW );
114
+ if (libc )
115
+ {
116
+ getifaddrs = (int (* )(struct ifaddrs * * )) dlsym (libc , "getifaddrs" );
117
+ freeifaddrs = (void (* )(struct ifaddrs * )) dlsym (libc , "freeifaddrs" );
118
+ }
119
+ }
120
+
121
+ static bool ensure_getifaddrs_is_loaded ()
122
+ {
123
+ static pthread_once_t getifaddrs_is_loaded = PTHREAD_ONCE_INIT ;
124
+ pthread_once (& getifaddrs_is_loaded , try_loading_getifaddrs );
125
+ return getifaddrs != NULL && freeifaddrs != NULL ;
126
+ }
127
+ #endif
128
+
103
129
int32_t SystemNative_EnumerateInterfaceAddresses (void * context ,
104
130
IPv4AddressFound onIpv4Found ,
105
131
IPv6AddressFound onIpv6Found ,
106
132
LinkLayerAddressFound onLinkLayerFound )
107
133
{
108
- #if HAVE_GETIFADDRS || defined(TARGET_ANDROID )
134
+ #ifdef ANDROID_GETIFADDRS_WORKAROUND
135
+ if (!ensure_getifaddrs_is_loaded ())
136
+ {
137
+ errno = ENOTSUP ;
138
+ return -1 ;
139
+ }
140
+ #endif
141
+
142
+ #if HAVE_GETIFADDRS || defined(ANDROID_GETIFADDRS_WORKAROUND )
109
143
struct ifaddrs * headAddr ;
110
144
if (getifaddrs (& headAddr ) == -1 )
111
145
{
@@ -250,7 +284,15 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context,
250
284
251
285
int32_t SystemNative_GetNetworkInterfaces (int32_t * interfaceCount , NetworkInterfaceInfo * * interfaceList , int32_t * addressCount , IpAddressInfo * * addressList )
252
286
{
253
- #if HAVE_GETIFADDRS || defined(TARGET_ANDROID )
287
+ #ifdef ANDROID_GETIFADDRS_WORKAROUND
288
+ if (!ensure_getifaddrs_is_loaded ())
289
+ {
290
+ errno = ENOTSUP ;
291
+ return -1 ;
292
+ }
293
+ #endif
294
+
295
+ #if HAVE_GETIFADDRS || defined(ANDROID_GETIFADDRS_WORKAROUND )
254
296
struct ifaddrs * head ; // Pointer to block allocated by getifaddrs().
255
297
struct ifaddrs * ifaddrsEntry ;
256
298
IpAddressInfo * ai ;
@@ -289,7 +331,16 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter
289
331
// To save allocation need for separate free() we will allocate one memory chunk
290
332
// where we first write out NetworkInterfaceInfo entries immediately followed by
291
333
// IpAddressInfo list.
292
- void * memoryBlock = calloc ((size_t )count , sizeof (NetworkInterfaceInfo ));
334
+ #ifdef TARGET_ANDROID
335
+ // Since Android API 30, getifaddrs returns only AF_INET and AF_INET6 addresses and we do not
336
+ // get any AF_PACKET addresses and so count == ip4count + ip6count. We need to make sure that
337
+ // the memoryBlock is large enough to hold all interfaces (up to `count` entries) and all
338
+ // addresses (ip4count + ip6count) without any overlap between interfaceList and addressList.
339
+ int entriesCount = count + ip4count + ip6count ;
340
+ #else
341
+ int entriesCount = count ;
342
+ #endif
343
+ void * memoryBlock = calloc ((size_t )entriesCount , sizeof (NetworkInterfaceInfo ));
293
344
if (memoryBlock == NULL )
294
345
{
295
346
errno = ENOMEM ;
@@ -300,7 +351,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter
300
351
ifaddrsEntry = head ;
301
352
* interfaceList = nii = (NetworkInterfaceInfo * )memoryBlock ;
302
353
// address of first IpAddressInfo after all NetworkInterfaceInfo entries.
303
- * addressList = ai = (IpAddressInfo * )(nii + (count - ip4count - ip6count ));
354
+ * addressList = ai = (IpAddressInfo * )(nii + (entriesCount - ip4count - ip6count ));
304
355
305
356
while (ifaddrsEntry != NULL )
306
357
{
@@ -324,7 +375,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter
324
375
memcpy (nii -> Name , ifaddrsEntry -> ifa_name , sizeof (nii -> Name ));
325
376
nii -> InterfaceIndex = if_nametoindex (ifaddrsEntry -> ifa_name );
326
377
nii -> Speed = -1 ;
327
- nii -> HardwareType = NetworkInterfaceType_Unknown ;
378
+ nii -> HardwareType = (( ifaddrsEntry -> ifa_flags & IFF_LOOPBACK ) == IFF_LOOPBACK ) ? NetworkInterfaceType_Loopback : NetworkInterfaceType_Unknown ;
328
379
329
380
// Get operational state and multicast support.
330
381
if ((ifaddrsEntry -> ifa_flags & (IFF_MULTICAST |IFF_ALLMULTI )) != 0 )
0 commit comments