Showing with 173 additions and 89 deletions.
  1. +2 −0 src/win/error.c
  2. +171 −89 src/win/util.c
@@ -108,6 +108,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case WSAECONNRESET: return UV_ECONNRESET;
case ERROR_ALREADY_EXISTS: return UV_EEXIST;
case ERROR_FILE_EXISTS: return UV_EEXIST;
case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
case WSAEFAULT: return UV_EFAULT;
case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
@@ -124,6 +125,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
case WSAENETUNREACH: return UV_ENETUNREACH;
case WSAENOBUFS: return UV_ENOBUFS;
case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM;
case ERROR_OUTOFMEMORY: return UV_ENOMEM;
case ERROR_CANNOT_MAKE: return UV_ENOSPC;
case ERROR_DISK_FULL: return UV_ENOSPC;
@@ -740,125 +740,207 @@ 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_;
}


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);
}