|
|
@ -740,109 +740,201 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses, |
|
|
|
int* count) { |
|
|
|
unsigned long size = 0; |
|
|
|
IP_ADAPTER_ADDRESSES* adapter_addresses; |
|
|
|
IP_ADAPTER_ADDRESSES* adapter_address; |
|
|
|
uv_interface_address_t* address; |
|
|
|
struct sockaddr* sock_addr; |
|
|
|
int length; |
|
|
|
char* name; |
|
|
|
/* Use IP_ADAPTER_UNICAST_ADDRESS_XP to retain backwards compatibility */ |
|
|
|
/* with Windows XP */ |
|
|
|
IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address; |
|
|
|
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses_ptr, |
|
|
|
int* count_ptr) { |
|
|
|
IP_ADAPTER_ADDRESSES* win_address_buf; |
|
|
|
ULONG win_address_buf_size; |
|
|
|
IP_ADAPTER_ADDRESSES* win_address; |
|
|
|
|
|
|
|
if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size) |
|
|
|
!= ERROR_BUFFER_OVERFLOW) { |
|
|
|
return uv__new_sys_error(GetLastError()); |
|
|
|
} |
|
|
|
uv_interface_address_t* uv_address_buf; |
|
|
|
char* name_buf; |
|
|
|
size_t uv_address_buf_size; |
|
|
|
uv_interface_address_t* uv_address; |
|
|
|
|
|
|
|
adapter_addresses = (IP_ADAPTER_ADDRESSES*)malloc(size); |
|
|
|
if (!adapter_addresses) { |
|
|
|
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); |
|
|
|
} |
|
|
|
int count; |
|
|
|
|
|
|
|
if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapter_addresses, &size) |
|
|
|
!= ERROR_SUCCESS) { |
|
|
|
return uv__new_sys_error(GetLastError()); |
|
|
|
} |
|
|
|
/* Fetch the size of the adapters reported by windows, and then get the */ |
|
|
|
/* list itself. */ |
|
|
|
win_address_buf_size = 0; |
|
|
|
win_address_buf = NULL; |
|
|
|
|
|
|
|
/* Count the number of interfaces */ |
|
|
|
*count = 0; |
|
|
|
for (;;) { |
|
|
|
ULONG r; |
|
|
|
|
|
|
|
for (adapter_address = adapter_addresses; |
|
|
|
adapter_address != NULL; |
|
|
|
adapter_address = adapter_address->Next) { |
|
|
|
/* If win_address_buf is 0, then GetAdaptersAddresses will fail with */ |
|
|
|
/* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ |
|
|
|
/* win_address_buf_size. */ |
|
|
|
r = GetAdaptersAddresses(AF_UNSPEC, |
|
|
|
0, |
|
|
|
NULL, |
|
|
|
win_address_buf, |
|
|
|
&win_address_buf_size); |
|
|
|
|
|
|
|
if (adapter_address->OperStatus != IfOperStatusUp) |
|
|
|
continue; |
|
|
|
if (r == ERROR_SUCCESS) |
|
|
|
break; |
|
|
|
|
|
|
|
free(win_address_buf); |
|
|
|
|
|
|
|
switch (r) { |
|
|
|
case ERROR_BUFFER_OVERFLOW: |
|
|
|
/* This happens when win_address_buf is NULL or too small to hold */ |
|
|
|
/* all adapters. */ |
|
|
|
win_address_buf = malloc(win_address_buf_size); |
|
|
|
if (win_address_buf == NULL) |
|
|
|
return uv__new_artificial_error(UV_ENOMEM); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*) |
|
|
|
adapter_address->FirstUnicastAddress; |
|
|
|
case ERROR_NO_DATA: { |
|
|
|
/* No adapters were found. */ |
|
|
|
uv_address_buf = malloc(1); |
|
|
|
if (uv_address_buf == NULL) |
|
|
|
return uv__new_artificial_error(UV_ENOMEM); |
|
|
|
|
|
|
|
while (unicast_address) { |
|
|
|
(*count)++; |
|
|
|
unicast_address = unicast_address->Next; |
|
|
|
*count_ptr = 0; |
|
|
|
*addresses_ptr = uv_address_buf; |
|
|
|
|
|
|
|
return uv_ok_; |
|
|
|
} |
|
|
|
|
|
|
|
case ERROR_ADDRESS_NOT_ASSOCIATED: |
|
|
|
return uv__new_artificial_error(UV_EAGAIN); |
|
|
|
|
|
|
|
case ERROR_INVALID_PARAMETER: |
|
|
|
/* MSDN says:
|
|
|
|
* "This error is returned for any of the following conditions: the |
|
|
|
* SizePointer parameter is NULL, the Address parameter is not |
|
|
|
* AF_INET, AF_INET6, or AF_UNSPEC, or the address information for |
|
|
|
* the parameters requested is greater than ULONG_MAX." |
|
|
|
* Since the first two conditions are not met, it must be that the |
|
|
|
* adapter data is too big. |
|
|
|
*/ |
|
|
|
return uv__new_artificial_error(UV_ENOBUFS); |
|
|
|
|
|
|
|
default: |
|
|
|
/* Other (unspecified) errors can happen, but we don't have any */ |
|
|
|
/* special meaning for them. */ |
|
|
|
assert(r != ERROR_SUCCESS); |
|
|
|
return uv__new_sys_error(r); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
*addresses = (uv_interface_address_t*) |
|
|
|
malloc(*count * sizeof(uv_interface_address_t)); |
|
|
|
if (!(*addresses)) { |
|
|
|
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); |
|
|
|
/* Count the number of enabled interfaces and compute how much space is */ |
|
|
|
/* needed to store their info. */ |
|
|
|
count = 0; |
|
|
|
uv_address_buf_size = 0; |
|
|
|
|
|
|
|
for (win_address = win_address_buf; |
|
|
|
win_address != NULL; |
|
|
|
win_address = win_address->Next) { |
|
|
|
/* Use IP_ADAPTER_UNICAST_ADDRESS_XP to retain backwards compatibility */ |
|
|
|
/* with Windows XP */ |
|
|
|
IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address; |
|
|
|
int name_size; |
|
|
|
|
|
|
|
/* Interfaces that are not 'up' should not be reported. Also skip */ |
|
|
|
/* interfaces that have no associated unicast address, as to avoid */ |
|
|
|
/* allocating space for the name for this interface. */ |
|
|
|
if (win_address->OperStatus != IfOperStatusUp || |
|
|
|
win_address->FirstUnicastAddress == NULL) |
|
|
|
continue; |
|
|
|
|
|
|
|
/* Compute the size of the interface name. */ |
|
|
|
name_size = WideCharToMultiByte(CP_UTF8, |
|
|
|
0, |
|
|
|
win_address->FriendlyName, |
|
|
|
-1, |
|
|
|
NULL, |
|
|
|
0, |
|
|
|
NULL, |
|
|
|
FALSE); |
|
|
|
if (name_size <= 0) { |
|
|
|
free(win_address_buf); |
|
|
|
return uv__new_sys_error(GetLastError()); |
|
|
|
} |
|
|
|
uv_address_buf_size += name_size; |
|
|
|
|
|
|
|
/* Count the number of addresses associated with this interface, and */ |
|
|
|
/* compute the size. */ |
|
|
|
for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*) |
|
|
|
win_address->FirstUnicastAddress; |
|
|
|
unicast_address != NULL; |
|
|
|
unicast_address = unicast_address->Next) { |
|
|
|
count++; |
|
|
|
uv_address_buf_size += sizeof(uv_interface_address_t); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
address = *addresses; |
|
|
|
/* Allocate space to store interface data plus adapter names. */ |
|
|
|
uv_address_buf = malloc(uv_address_buf_size); |
|
|
|
if (uv_address_buf == NULL) { |
|
|
|
free(win_address_buf); |
|
|
|
return uv__new_artificial_error(UV_ENOMEM); |
|
|
|
} |
|
|
|
|
|
|
|
for (adapter_address = adapter_addresses; |
|
|
|
adapter_address != NULL; |
|
|
|
adapter_address = adapter_address->Next) { |
|
|
|
/* Compute the start of the uv_interface_address_t array, and the place in */ |
|
|
|
/* the buffer where the interface names will be stored. */ |
|
|
|
uv_address = uv_address_buf; |
|
|
|
name_buf = (char*) (uv_address_buf + count); |
|
|
|
|
|
|
|
if (adapter_address->OperStatus != IfOperStatusUp) |
|
|
|
/* Fill out the output buffer. */ |
|
|
|
for (win_address = win_address_buf; |
|
|
|
win_address != NULL; |
|
|
|
win_address = win_address->Next) { |
|
|
|
IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address; |
|
|
|
int name_size; |
|
|
|
size_t max_name_size; |
|
|
|
|
|
|
|
if (win_address->OperStatus != IfOperStatusUp || |
|
|
|
win_address->FirstUnicastAddress == NULL) |
|
|
|
continue; |
|
|
|
|
|
|
|
name = NULL; |
|
|
|
unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*) |
|
|
|
adapter_address->FirstUnicastAddress; |
|
|
|
/* Convert the interface name to UTF8. */ |
|
|
|
max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; |
|
|
|
if (max_name_size > (size_t) INT_MAX) |
|
|
|
max_name_size = INT_MAX; |
|
|
|
name_size = WideCharToMultiByte(CP_UTF8, |
|
|
|
0, |
|
|
|
win_address->FriendlyName, |
|
|
|
-1, |
|
|
|
name_buf, |
|
|
|
(int) max_name_size, |
|
|
|
NULL, |
|
|
|
FALSE); |
|
|
|
if (name_size <= 0) { |
|
|
|
free(win_address_buf); |
|
|
|
free(uv_address_buf); |
|
|
|
return uv__new_sys_error(GetLastError()); |
|
|
|
} |
|
|
|
|
|
|
|
while (unicast_address) { |
|
|
|
sock_addr = unicast_address->Address.lpSockaddr; |
|
|
|
if (sock_addr->sa_family == AF_INET6) { |
|
|
|
address->address.address6 = *((struct sockaddr_in6 *)sock_addr); |
|
|
|
} else { |
|
|
|
address->address.address4 = *((struct sockaddr_in *)sock_addr); |
|
|
|
} |
|
|
|
/* Add an uv_interface_address_t element for every unicast address. */ |
|
|
|
for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*) |
|
|
|
win_address->FirstUnicastAddress; |
|
|
|
unicast_address != NULL; |
|
|
|
unicast_address = unicast_address->Next) { |
|
|
|
struct sockaddr* sa; |
|
|
|
|
|
|
|
address->is_internal = |
|
|
|
adapter_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK ? 1 : 0; |
|
|
|
|
|
|
|
if (!name) { |
|
|
|
/* Convert FriendlyName to utf8 */ |
|
|
|
length = uv_utf16_to_utf8(adapter_address->FriendlyName, -1, NULL, 0); |
|
|
|
if (length) { |
|
|
|
name = (char*)malloc(length); |
|
|
|
if (!name) { |
|
|
|
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); |
|
|
|
} |
|
|
|
|
|
|
|
if (!uv_utf16_to_utf8(adapter_address->FriendlyName, -1, name, |
|
|
|
length)) { |
|
|
|
free(name); |
|
|
|
name = NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
uv_address->name = name_buf; |
|
|
|
|
|
|
|
sa = unicast_address->Address.lpSockaddr; |
|
|
|
if (sa->sa_family == AF_INET6) |
|
|
|
uv_address->address.address6 = *((struct sockaddr_in6 *) sa); |
|
|
|
else |
|
|
|
uv_address->address.address4 = *((struct sockaddr_in *) sa); |
|
|
|
|
|
|
|
assert(name); |
|
|
|
address->name = name; |
|
|
|
uv_address->is_internal = |
|
|
|
(win_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK); |
|
|
|
|
|
|
|
unicast_address = unicast_address->Next; |
|
|
|
address++; |
|
|
|
uv_address++; |
|
|
|
} |
|
|
|
|
|
|
|
name_buf += name_size; |
|
|
|
} |
|
|
|
|
|
|
|
free(adapter_addresses); |
|
|
|
free(win_address_buf); |
|
|
|
|
|
|
|
*addresses_ptr = uv_address_buf; |
|
|
|
*count_ptr = count; |
|
|
|
|
|
|
|
return uv_ok_; |
|
|
|
} |
|
|
@ -850,15 +942,5 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses, |
|
|
|
|
|
|
|
void uv_free_interface_addresses(uv_interface_address_t* addresses, |
|
|
|
int count) { |
|
|
|
int i; |
|
|
|
char* freed_name = NULL; |
|
|
|
|
|
|
|
for (i = 0; i < count; i++) { |
|
|
|
if (freed_name != addresses[i].name) { |
|
|
|
freed_name = addresses[i].name; |
|
|
|
free(freed_name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
free(addresses); |
|
|
|
} |
|
|
|