ext/libuv/src/win/util.c in libuv-1.1.0 vs ext/libuv/src/win/util.c in libuv-1.1.1
- old
+ new
@@ -50,20 +50,19 @@
* survives truncation.
*/
#define MAX_TITLE_LENGTH 8192
/* The number of nanoseconds in one second. */
-#undef NANOSEC
-#define NANOSEC 1000000000
+#define UV__NANOSEC 1000000000
/* Cached copy of the process title, plus a mutex guarding it. */
static char *process_title;
static CRITICAL_SECTION process_title_lock;
-/* Frequency (ticks per nanosecond) of the high-resolution clock. */
-static double hrtime_frequency_ = 0;
+/* Interval (in seconds) of the high-resolution clock. */
+static double hrtime_interval_ = 0;
/*
* One-time intialization code for functionality defined in util.c.
*/
@@ -71,15 +70,18 @@
LARGE_INTEGER perf_frequency;
/* Initialize process title access mutex. */
InitializeCriticalSection(&process_title_lock);
- /* Retrieve high-resolution timer frequency. */
- if (QueryPerformanceFrequency(&perf_frequency))
- hrtime_frequency_ = (double) perf_frequency.QuadPart / (double) NANOSEC;
- else
- hrtime_frequency_= 0;
+ /* Retrieve high-resolution timer frequency
+ * and precompute its reciprocal.
+ */
+ if (QueryPerformanceFrequency(&perf_frequency)) {
+ hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
+ } else {
+ hrtime_interval_= 0;
+ }
}
int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
char* utf8Buffer, size_t utf8Size) {
@@ -202,11 +204,11 @@
NULL,
NULL);
if (r == 0) {
return uv_translate_sys_error(GetLastError());
} else if (r > (int) *size) {
- *size = r;
+ *size = r -1;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
r = WideCharToMultiByte(CP_UTF8,
@@ -219,11 +221,11 @@
NULL);
if (r == 0) {
return uv_translate_sys_error(GetLastError());
}
- *size = r;
+ *size = r - 1;
return 0;
}
int uv_chdir(const char* dir) {
@@ -461,30 +463,31 @@
return 0;
}
uint64_t uv_hrtime(void) {
- LARGE_INTEGER counter;
-
uv__once_init();
+ return uv__hrtime(UV__NANOSEC);
+}
- /* If the performance frequency is zero, there's no support. */
- if (hrtime_frequency_ == 0) {
- /* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */
+uint64_t uv__hrtime(double scale) {
+ LARGE_INTEGER counter;
+
+ /* If the performance interval is zero, there's no support. */
+ if (hrtime_interval_ == 0) {
return 0;
}
if (!QueryPerformanceCounter(&counter)) {
- /* uv__set_sys_error(loop, GetLastError()); */
return 0;
}
/* Because we have no guarantee about the order of magnitude of the
- * performance counter frequency, integer math could cause this computation
+ * performance counter interval, integer math could cause this computation
* to overflow. Therefore we resort to floating point math.
*/
- return (uint64_t) ((double) counter.QuadPart / hrtime_frequency_);
+ return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale);
}
int uv_resident_set_memory(size_t* rss) {
HANDLE current_process;
@@ -773,23 +776,105 @@
free(cpu_infos);
}
+static int is_windows_version_or_greater(DWORD os_major,
+ DWORD os_minor,
+ WORD service_pack_major,
+ WORD service_pack_minor) {
+ OSVERSIONINFOEX osvi;
+ DWORDLONG condition_mask = 0;
+ int op = VER_GREATER_EQUAL;
+
+ /* Initialize the OSVERSIONINFOEX structure. */
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ osvi.dwMajorVersion = os_major;
+ osvi.dwMinorVersion = os_minor;
+ osvi.wServicePackMajor = service_pack_major;
+ osvi.wServicePackMinor = service_pack_minor;
+
+ /* Initialize the condition mask. */
+ VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
+
+ /* Perform the test. */
+ return (int) VerifyVersionInfo(
+ &osvi,
+ VER_MAJORVERSION | VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
+ condition_mask);
+}
+
+
+static int address_prefix_match(int family,
+ struct sockaddr* address,
+ struct sockaddr* prefix_address,
+ int prefix_len) {
+ uint8_t* address_data;
+ uint8_t* prefix_address_data;
+ int i;
+
+ assert(address->sa_family == family);
+ assert(prefix_address->sa_family == family);
+
+ if (family == AF_INET6) {
+ address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
+ } else {
+ address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
+ }
+
+ for (i = 0; i < prefix_len >> 3; i++) {
+ if (address_data[i] != prefix_address_data[i])
+ return 0;
+ }
+
+ if (prefix_len % 8)
+ return prefix_address_data[i] ==
+ (address_data[i] & (0xff << (8 - prefix_len % 8)));
+
+ return 1;
+}
+
+
int 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;
+ IP_ADAPTER_ADDRESSES* adapter;
uv_interface_address_t* uv_address_buf;
char* name_buf;
size_t uv_address_buf_size;
uv_interface_address_t* uv_address;
int count;
+ int is_vista_or_greater;
+ ULONG flags;
+
+ is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
+ if (is_vista_or_greater) {
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER;
+ } else {
+ /* We need at least XP SP1. */
+ if (!is_windows_version_or_greater(5, 1, 1, 0))
+ return UV_ENOTSUP;
+
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
+ }
+
+
/* Fetch the size of the adapters reported by windows, and then get the */
/* list itself. */
win_address_buf_size = 0;
win_address_buf = NULL;
@@ -798,11 +883,11 @@
/* 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,
- GAA_FLAG_INCLUDE_PREFIX,
+ flags,
NULL,
win_address_buf,
&win_address_buf_size);
if (r == ERROR_SUCCESS)
@@ -857,29 +942,27 @@
/* 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;
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* 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)
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
continue;
/* Compute the size of the interface name. */
name_size = WideCharToMultiByte(CP_UTF8,
0,
- win_address->FriendlyName,
+ adapter->FriendlyName,
-1,
NULL,
0,
NULL,
FALSE);
@@ -889,12 +972,12 @@
}
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;
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
unicast_address != NULL;
unicast_address = unicast_address->Next) {
count++;
uv_address_buf_size += sizeof(uv_interface_address_t);
}
@@ -911,29 +994,28 @@
/* the buffer where the interface names will be stored. */
uv_address = uv_address_buf;
name_buf = (char*) (uv_address_buf + count);
/* 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;
- IP_ADAPTER_PREFIX* prefix;
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
int name_size;
size_t max_name_size;
- if (win_address->OperStatus != IfOperStatusUp ||
- win_address->FirstUnicastAddress == NULL)
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
continue;
/* 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,
+ adapter->FriendlyName,
-1,
name_buf,
(int) max_name_size,
NULL,
FALSE);
@@ -941,50 +1023,80 @@
free(win_address_buf);
free(uv_address_buf);
return uv_translate_sys_error(GetLastError());
}
- prefix = win_address->FirstPrefix;
-
/* Add an uv_interface_address_t element for every unicast address. */
- /* Walk the prefix list in tandem with the address list. */
- for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*)
- win_address->FirstUnicastAddress;
- unicast_address != NULL && prefix != NULL;
- unicast_address = unicast_address->Next, prefix = prefix->Next) {
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
+ unicast_address != NULL;
+ unicast_address = unicast_address->Next) {
struct sockaddr* sa;
ULONG prefix_len;
sa = unicast_address->Address.lpSockaddr;
- prefix_len = prefix->PrefixLength;
+ /* XP has no OnLinkPrefixLength field. */
+ if (is_vista_or_greater) {
+ prefix_len = unicast_address->OnLinkPrefixLength;
+ } else {
+ /* Prior to Windows Vista the FirstPrefix pointed to the list with
+ * single prefix for each IP address assigned to the adapter.
+ * Order of FirstPrefix does not match order of FirstUnicastAddress,
+ * so we need to find corresponding prefix.
+ */
+ IP_ADAPTER_PREFIX* prefix;
+ prefix_len = 0;
+
+ for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
+ /* We want the longest matching prefix. */
+ if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
+ prefix->PrefixLength <= prefix_len)
+ continue;
+
+ if (address_prefix_match(sa->sa_family, sa,
+ prefix->Address.lpSockaddr, prefix->PrefixLength)) {
+ prefix_len = prefix->PrefixLength;
+ }
+ }
+
+ /* If there is no matching prefix information, return a single-host
+ * subnet mask (e.g. 255.255.255.255 for IPv4).
+ */
+ if (!prefix_len)
+ prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
+ }
+
memset(uv_address, 0, sizeof *uv_address);
uv_address->name = name_buf;
- if (win_address->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
+ if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
memcpy(uv_address->phys_addr,
- win_address->PhysicalAddress,
+ adapter->PhysicalAddress,
sizeof(uv_address->phys_addr));
}
uv_address->is_internal =
- (win_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
+ (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
if (sa->sa_family == AF_INET6) {
uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
uv_address->netmask.netmask6.sin6_family = AF_INET6;
memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
- uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
- 0xff << (8 - prefix_len % 8);
+ /* This check ensures that we don't write past the size of the data. */
+ if (prefix_len % 8) {
+ uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
+ 0xff << (8 - prefix_len % 8);
+ }
} else {
uv_address->address.address4 = *((struct sockaddr_in *) sa);
uv_address->netmask.netmask4.sin_family = AF_INET;
- uv_address->netmask.netmask4.sin_addr.s_addr =
- htonl(0xffffffff << (32 - prefix_len));
+ uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
+ htonl(0xffffffff << (32 - prefix_len)) : 0;
}
uv_address++;
}