|
@ -31,6 +31,7 @@ |
|
|
#include "uv.h" |
|
|
#include "uv.h" |
|
|
#include "internal.h" |
|
|
#include "internal.h" |
|
|
|
|
|
|
|
|
|
|
|
#include <Winsock2.h> |
|
|
#include <iphlpapi.h> |
|
|
#include <iphlpapi.h> |
|
|
#include <psapi.h> |
|
|
#include <psapi.h> |
|
|
#include <tlhelp32.h> |
|
|
#include <tlhelp32.h> |
|
@ -578,47 +579,50 @@ uv_err_t uv_uptime(double* uptime) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { |
|
|
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { |
|
|
|
|
|
uv_cpu_info_t* cpu_infos; |
|
|
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; |
|
|
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; |
|
|
DWORD sppi_size; |
|
|
DWORD sppi_size; |
|
|
SYSTEM_INFO system_info; |
|
|
SYSTEM_INFO system_info; |
|
|
DWORD cpu_count, i, r; |
|
|
DWORD cpu_count, r, i; |
|
|
|
|
|
NTSTATUS status; |
|
|
ULONG result_size; |
|
|
ULONG result_size; |
|
|
size_t size; |
|
|
|
|
|
uv_err_t err; |
|
|
uv_err_t err; |
|
|
uv_cpu_info_t* cpu_info; |
|
|
uv_cpu_info_t* cpu_info; |
|
|
|
|
|
|
|
|
*cpu_infos = NULL; |
|
|
cpu_infos = NULL; |
|
|
*count = 0; |
|
|
cpu_count = 0; |
|
|
|
|
|
sppi = NULL; |
|
|
|
|
|
|
|
|
uv__once_init(); |
|
|
uv__once_init(); |
|
|
|
|
|
|
|
|
GetSystemInfo(&system_info); |
|
|
GetSystemInfo(&system_info); |
|
|
cpu_count = system_info.dwNumberOfProcessors; |
|
|
cpu_count = system_info.dwNumberOfProcessors; |
|
|
|
|
|
|
|
|
size = cpu_count * sizeof(uv_cpu_info_t); |
|
|
cpu_infos = calloc(cpu_count, sizeof *cpu_infos); |
|
|
*cpu_infos = (uv_cpu_info_t*) malloc(size); |
|
|
if (cpu_infos == NULL) { |
|
|
if (*cpu_infos == NULL) { |
|
|
|
|
|
err = uv__new_artificial_error(UV_ENOMEM); |
|
|
err = uv__new_artificial_error(UV_ENOMEM); |
|
|
goto out; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
memset(*cpu_infos, 0, size); |
|
|
|
|
|
|
|
|
|
|
|
sppi_size = sizeof(*sppi) * cpu_count; |
|
|
sppi_size = cpu_count * sizeof(*sppi); |
|
|
sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*) malloc(sppi_size); |
|
|
sppi = malloc(sppi_size); |
|
|
if (!sppi) { |
|
|
if (sppi == NULL) { |
|
|
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); |
|
|
err = uv__new_artificial_error(UV_ENOMEM); |
|
|
|
|
|
goto error; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
r = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, |
|
|
status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, |
|
|
sppi, |
|
|
sppi, |
|
|
sppi_size, |
|
|
sppi_size, |
|
|
&result_size); |
|
|
&result_size); |
|
|
if (r != ERROR_SUCCESS || result_size != sppi_size) { |
|
|
if (!NT_SUCCESS(status)) { |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
err = uv__new_sys_error(pRtlNtStatusToDosError(status)); |
|
|
goto out; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
assert(result_size == sppi_size); |
|
|
|
|
|
|
|
|
for (i = 0; i < cpu_count; i++) { |
|
|
for (i = 0; i < cpu_count; i++) { |
|
|
WCHAR key_name[128]; |
|
|
WCHAR key_name[128]; |
|
|
HKEY processor_key; |
|
|
HKEY processor_key; |
|
@ -626,11 +630,14 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { |
|
|
DWORD cpu_speed_size = sizeof(cpu_speed); |
|
|
DWORD cpu_speed_size = sizeof(cpu_speed); |
|
|
WCHAR cpu_brand[256]; |
|
|
WCHAR cpu_brand[256]; |
|
|
DWORD cpu_brand_size = sizeof(cpu_brand); |
|
|
DWORD cpu_brand_size = sizeof(cpu_brand); |
|
|
|
|
|
int len; |
|
|
|
|
|
|
|
|
|
|
|
len = _snwprintf(key_name, |
|
|
|
|
|
ARRAY_SIZE(key_name), |
|
|
|
|
|
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", |
|
|
|
|
|
i); |
|
|
|
|
|
|
|
|
_snwprintf(key_name, |
|
|
assert(len > 0 && len < ARRAY_SIZE(key_name)); |
|
|
ARRAY_SIZE(key_name), |
|
|
|
|
|
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", |
|
|
|
|
|
i); |
|
|
|
|
|
|
|
|
|
|
|
r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, |
|
|
r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, |
|
|
key_name, |
|
|
key_name, |
|
@ -639,32 +646,34 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { |
|
|
&processor_key); |
|
|
&processor_key); |
|
|
if (r != ERROR_SUCCESS) { |
|
|
if (r != ERROR_SUCCESS) { |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
goto out; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (RegQueryValueExW(processor_key, |
|
|
if (RegQueryValueExW(processor_key, |
|
|
L"~MHz", |
|
|
L"~MHz", |
|
|
NULL, NULL, |
|
|
NULL, |
|
|
|
|
|
NULL, |
|
|
(BYTE*) &cpu_speed, |
|
|
(BYTE*) &cpu_speed, |
|
|
&cpu_speed_size) != ERROR_SUCCESS) { |
|
|
&cpu_speed_size) != ERROR_SUCCESS) { |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
RegCloseKey(processor_key); |
|
|
RegCloseKey(processor_key); |
|
|
goto out; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (RegQueryValueExW(processor_key, |
|
|
if (RegQueryValueExW(processor_key, |
|
|
L"ProcessorNameString", |
|
|
L"ProcessorNameString", |
|
|
NULL, NULL, |
|
|
NULL, |
|
|
|
|
|
NULL, |
|
|
(BYTE*) &cpu_brand, |
|
|
(BYTE*) &cpu_brand, |
|
|
&cpu_brand_size) != ERROR_SUCCESS) { |
|
|
&cpu_brand_size) != ERROR_SUCCESS) { |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
RegCloseKey(processor_key); |
|
|
RegCloseKey(processor_key); |
|
|
goto out; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
RegCloseKey(processor_key); |
|
|
RegCloseKey(processor_key); |
|
|
|
|
|
|
|
|
cpu_info = &(*cpu_infos)[i]; |
|
|
cpu_info = &cpu_infos[i]; |
|
|
cpu_info->speed = cpu_speed; |
|
|
cpu_info->speed = cpu_speed; |
|
|
cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; |
|
|
cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; |
|
|
cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - |
|
|
cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - |
|
@ -673,57 +682,59 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { |
|
|
cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; |
|
|
cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; |
|
|
cpu_info->cpu_times.nice = 0; |
|
|
cpu_info->cpu_times.nice = 0; |
|
|
|
|
|
|
|
|
size = uv_utf16_to_utf8(cpu_brand, |
|
|
|
|
|
cpu_brand_size / sizeof(WCHAR), |
|
|
len = WideCharToMultiByte(CP_UTF8, |
|
|
NULL, |
|
|
0, |
|
|
0); |
|
|
cpu_brand, |
|
|
if (size == 0) { |
|
|
cpu_brand_size / sizeof(WCHAR), |
|
|
|
|
|
NULL, |
|
|
|
|
|
0, |
|
|
|
|
|
NULL, |
|
|
|
|
|
NULL); |
|
|
|
|
|
if (len == 0) { |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
goto out; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
assert(len > 0); |
|
|
|
|
|
|
|
|
/* Allocate 1 extra byte for the null terminator. */ |
|
|
/* Allocate 1 extra byte for the null terminator. */ |
|
|
cpu_info->model = (char*) malloc(size + 1); |
|
|
cpu_info->model = malloc(len + 1); |
|
|
if (cpu_info->model == NULL) { |
|
|
if (cpu_info->model == NULL) { |
|
|
err = uv__new_artificial_error(UV_ENOMEM); |
|
|
err = uv__new_artificial_error(UV_ENOMEM); |
|
|
goto out; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (uv_utf16_to_utf8(cpu_brand, |
|
|
if (WideCharToMultiByte(CP_UTF8, |
|
|
cpu_brand_size / sizeof(WCHAR), |
|
|
0, |
|
|
cpu_info->model, |
|
|
cpu_brand, |
|
|
size) == 0) { |
|
|
cpu_brand_size / sizeof(WCHAR), |
|
|
|
|
|
cpu_info->model, |
|
|
|
|
|
len, |
|
|
|
|
|
NULL, |
|
|
|
|
|
NULL) == 0) { |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
err = uv__new_sys_error(GetLastError()); |
|
|
goto out; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* Ensure that cpu_info->model is null terminated. */ |
|
|
/* Ensure that cpu_info->model is null terminated. */ |
|
|
cpu_info->model[size] = '\0'; |
|
|
cpu_info->model[len] = '\0'; |
|
|
|
|
|
|
|
|
(*count)++; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
err = uv_ok_; |
|
|
free(sppi); |
|
|
|
|
|
|
|
|
out: |
|
|
*cpu_count_ptr = cpu_count; |
|
|
if (sppi) { |
|
|
*cpu_infos_ptr = cpu_infos; |
|
|
free(sppi); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (err.code != UV_OK && |
|
|
return uv_ok_; |
|
|
*cpu_infos != NULL) { |
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < *count; i++) { |
|
|
error: |
|
|
/* This is safe because the cpu_infos memory area is zeroed out */ |
|
|
/* This is safe because the cpu_infos array is zeroed on allocation. */ |
|
|
/* immediately after allocating it. */ |
|
|
for (i = 0; i < cpu_count; i++) |
|
|
free((*cpu_infos)[i].model); |
|
|
free(cpu_infos[i].model); |
|
|
} |
|
|
|
|
|
free(*cpu_infos); |
|
|
|
|
|
|
|
|
|
|
|
*cpu_infos = NULL; |
|
|
free(cpu_infos); |
|
|
*count = 0; |
|
|
free(sppi); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return err; |
|
|
return err; |
|
|
} |
|
|
} |
|
@ -765,7 +776,7 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses_ptr, |
|
|
/* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ |
|
|
/* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ |
|
|
/* win_address_buf_size. */ |
|
|
/* win_address_buf_size. */ |
|
|
r = GetAdaptersAddresses(AF_UNSPEC, |
|
|
r = GetAdaptersAddresses(AF_UNSPEC, |
|
|
0, |
|
|
GAA_FLAG_INCLUDE_PREFIX, |
|
|
NULL, |
|
|
NULL, |
|
|
win_address_buf, |
|
|
win_address_buf, |
|
|
&win_address_buf_size); |
|
|
&win_address_buf_size); |
|
@ -882,6 +893,7 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses_ptr, |
|
|
win_address != NULL; |
|
|
win_address != NULL; |
|
|
win_address = win_address->Next) { |
|
|
win_address = win_address->Next) { |
|
|
IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address; |
|
|
IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address; |
|
|
|
|
|
IP_ADAPTER_PREFIX* prefix; |
|
|
int name_size; |
|
|
int name_size; |
|
|
size_t max_name_size; |
|
|
size_t max_name_size; |
|
|
|
|
|
|
|
@ -907,23 +919,41 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses_ptr, |
|
|
return uv__new_sys_error(GetLastError()); |
|
|
return uv__new_sys_error(GetLastError()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
prefix = win_address->FirstPrefix; |
|
|
|
|
|
|
|
|
/* Add an uv_interface_address_t element for every unicast address. */ |
|
|
/* 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*) |
|
|
for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*) |
|
|
win_address->FirstUnicastAddress; |
|
|
win_address->FirstUnicastAddress; |
|
|
unicast_address != NULL; |
|
|
unicast_address != NULL && prefix != NULL; |
|
|
unicast_address = unicast_address->Next) { |
|
|
unicast_address = unicast_address->Next, prefix = prefix->Next) { |
|
|
struct sockaddr* sa; |
|
|
struct sockaddr* sa; |
|
|
|
|
|
ULONG prefix_len; |
|
|
|
|
|
|
|
|
|
|
|
sa = unicast_address->Address.lpSockaddr; |
|
|
|
|
|
prefix_len = prefix->PrefixLength; |
|
|
|
|
|
|
|
|
|
|
|
memset(uv_address, 0, sizeof *uv_address); |
|
|
|
|
|
|
|
|
uv_address->name = name_buf; |
|
|
uv_address->name = name_buf; |
|
|
|
|
|
uv_address->is_internal = |
|
|
|
|
|
(win_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK); |
|
|
|
|
|
|
|
|
sa = unicast_address->Address.lpSockaddr; |
|
|
if (sa->sa_family == AF_INET6) { |
|
|
if (sa->sa_family == AF_INET6) |
|
|
|
|
|
uv_address->address.address6 = *((struct sockaddr_in6 *) sa); |
|
|
uv_address->address.address6 = *((struct sockaddr_in6 *) sa); |
|
|
else |
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
uv_address->address.address4 = *((struct sockaddr_in *) sa); |
|
|
uv_address->address.address4 = *((struct sockaddr_in *) sa); |
|
|
|
|
|
|
|
|
uv_address->is_internal = |
|
|
uv_address->netmask.netmask4.sin_family = AF_INET; |
|
|
(win_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK); |
|
|
uv_address->netmask.netmask4.sin_addr.s_addr = |
|
|
|
|
|
htonl(0xffffffff << (32 - prefix_len)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
uv_address++; |
|
|
uv_address++; |
|
|
} |
|
|
} |
|
|