diff options
| author | Eli Zaretskii <eliz@gnu.org> | 2019-11-26 19:13:12 +0200 |
|---|---|---|
| committer | Eli Zaretskii <eliz@gnu.org> | 2019-11-26 19:13:12 +0200 |
| commit | 094eb04ce5d8c1ccef78113c8cc6791d1d3b6bf8 (patch) | |
| tree | c9eaab424dacf2b29f3942541bc800c686d04e8d /src/w32.c | |
| parent | 52eca2d3bdef293e9f5d64aa2b9ca36f1e00e817 (diff) | |
| download | emacs-094eb04ce5d8c1ccef78113c8cc6791d1d3b6bf8.tar.gz | |
Fix MS-Windows build with mingw.org's MinGW
mingw.org's MinGW by default targets Windows 9X, so
_WIN32_WINNT is set to a value that bypasses declarations
in system headers we need to compile network_interface_list.
Also, the code needed a workaround for Windows XP, where
some functionality is missing from the GetAdaptersAddresses
API.
* src/w32.c (_WIN32_WINNT): Define to 0x0501, if the value is
lower, temporarily while processing iphlpapi.h.
(address_prefix_match): New helper function.
(network_interface_list): Work around the fact that the
OnLinkPrefixLength member of IP_ADAPTER_UNICAST_ADDRESS is not
available when _WIN32_WINNT < 0x0600. On Windows XP use
special code that calls address_prefix_match to compute the
network prefix length.
Diffstat (limited to 'src/w32.c')
| -rw-r--r-- | src/w32.c | 80 |
1 files changed, 79 insertions, 1 deletions
diff --git a/src/w32.c b/src/w32.c index 76c226892a4..cb82d51fb92 100644 --- a/src/w32.c +++ b/src/w32.c @@ -242,8 +242,22 @@ typedef struct _REPARSE_DATA_BUFFER { #undef recvfrom #undef sendto +/* We need at least XP level for GetAdaptersAddresses stuff. */ +#if _WIN32_WINNT < 0x0501 +# undef ORIG_WIN32_WINNT +# define ORIG_WIN32_WINNT _WIN32_WINNT +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0501 +#endif + #include <iphlpapi.h> /* should be after winsock2.h */ +#ifdef ORIG_WIN32_WINNT +# undef _WIN32_WINNT +# define _WIN32_WINNT ORIG_WIN32_WINNT +# undef ORIG_WIN32_WINNT +#endif + #include <wincrypt.h> #include <c-strcase.h> @@ -9432,6 +9446,40 @@ network_interface_get_info (Lisp_Object ifname) return res; } +static bool +address_prefix_match (int family, struct sockaddr *address, + struct sockaddr *prefix_address, ULONG prefix_len) +{ + UINT8 *address_data; + UINT8 *prefix_address_data; + int i; + + if (family == AF_INET6) + { + address_data = (UINT8 *) &(((struct sockaddr_in6 *) address)->sin6_addr); + prefix_address_data = + (UINT8 *) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr); + } + else + { + address_data = (UINT8 *) &(((struct sockaddr_in *) address)->sin_addr); + prefix_address_data = + (UINT8 *) &(((struct sockaddr_in *) prefix_address)->sin_addr); + } + + for (i = 0; i < prefix_len >> 3; i++) + { + if (address_data[i] != prefix_address_data[i]) + return false; + } + + if (prefix_len % 8) + return (prefix_address_data[i] == + (address_data[i] & (0xff << (8 - prefix_len % 8)))); + + return true; +} + Lisp_Object network_interface_list (bool full, unsigned short match) { @@ -9586,7 +9634,37 @@ network_interface_list (bool full, unsigned short match) byte order, so convert from host to network order when generating the netmask. */ int i; - ULONG numbits = address->OnLinkPrefixLength; + ULONG numbits; + if (w32_major_version >= 6) /* Vista or later */ + { +#if _WIN32_WINNT >= 0x0600 + numbits = address->OnLinkPrefixLength; +#else + /* Kludge alert! OnLinkPrefixLength is only defined + when compiling for Vista and later. */ + numbits = *(UINT8 *) (address->LeaseLifetime + + sizeof (address->LeaseLifetime)); +#endif + } + else /* Windows XP */ + { + IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix; + numbits = 0; + for ( ; prefix; prefix = prefix->Next) + { + /* We want the longest matching prefix. */ + if (prefix->Address.lpSockaddr->sa_family + != ifa_addr->sa_family + || prefix->PrefixLength <= numbits) + continue; + if (address_prefix_match (ifa_addr->sa_family, ifa_addr, + prefix->Address.lpSockaddr, + prefix->PrefixLength)) + numbits = prefix->PrefixLength; + } + if (!numbits) + numbits = (ifa_addr->sa_family == AF_INET6) ? 128 : 32; + } for (i = 0; i < addr_len; i++) { if (numbits >= 32) |
