123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- #include "precompile.h"
- #include "toolkit.h"
- #include "internal.h"
- #include <winsock2.h>
- #include <winperf.h>
- #include <iphlpapi.h>
- #include <psapi.h>
- #include <tlhelp32.h>
- #include <windows.h>
- #include <userenv.h>
- #include <math.h>
- #include "dbgutil.h"
- #pragma comment(lib, "IPHlpApi.lib")
- /*
- * Converts a UTF-16 string into a UTF-8 one. The resulting string is
- * null-terminated.
- *
- * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
- * be specified.
- */
- int toolkit__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8)
- {
- DWORD bufsize;
- if (utf16 == NULL)
- return TOOLKIT_EINVAL;
- /* Check how much space we need */
- bufsize = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16,
- utf16len,
- NULL,
- 0,
- NULL,
- NULL);
- if (bufsize == 0)
- return toolkit_translate_sys_error(GetLastError());
- /* Allocate the destination buffer adding an extra byte for the terminating
- * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
- * we do it ourselves always, just in case. */
- *utf8 = ZALLOC(bufsize + 1);
- if (*utf8 == NULL)
- return TOOLKIT_ENOMEM;
- /* Convert to UTF-8 */
- bufsize = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16,
- utf16len,
- *utf8,
- bufsize,
- NULL,
- NULL);
- if (bufsize == 0) {
- FREE(*utf8);
- *utf8 = NULL;
- return toolkit_translate_sys_error(GetLastError());
- }
- (*utf8)[bufsize] = '\0';
- return 0;
- }
- /*
- * Converts a UTF-8 string into a UTF-16 one. The resulting string is
- * null-terminated.
- *
- * If utf8 is null terminated, utf8len can be set to -1, otherwise it must
- * be specified.
- */
- int toolkit__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16)
- {
- int bufsize;
- if (utf8 == NULL)
- return TOOLKIT_EINVAL;
- /* Check how much space we need */
- bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
- if (bufsize == 0)
- return toolkit_translate_sys_error(GetLastError());
- /* Allocate the destination buffer adding an extra byte for the terminating
- * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
- * we do it ourselves always, just in case. */
- *utf16 = ZALLOC(sizeof(WCHAR) * (bufsize + 1));
- if (*utf16 == NULL)
- return TOOLKIT_ENOMEM;
- /* Convert to UTF-16 */
- bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
- if (bufsize == 0) {
- FREE(*utf16);
- *utf16 = NULL;
- return toolkit_translate_sys_error(GetLastError());
- }
- (*utf16)[bufsize] = L'\0';
- return 0;
- }
- int toolkit_cpu_info(toolkit_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr)
- {
- toolkit_cpu_info_t* cpu_infos;
- SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
- DWORD sppi_size;
- SYSTEM_INFO system_info;
- DWORD cpu_count, i;
- NTSTATUS status;
- ULONG result_size;
- int err;
- toolkit_cpu_info_t* cpu_info;
- cpu_infos = NULL;
- cpu_count = 0;
- sppi = NULL;
- toolkit__once_init();
- GetSystemInfo(&system_info);
- cpu_count = system_info.dwNumberOfProcessors;
- cpu_infos = toolkit_calloc(cpu_count, sizeof * cpu_infos);
- if (cpu_infos == NULL) {
- err = ERROR_OUTOFMEMORY;
- goto error;
- }
- sppi_size = cpu_count * sizeof(*sppi);
- sppi = toolkit_malloc(sppi_size);
- if (sppi == NULL) {
- err = ERROR_OUTOFMEMORY;
- goto error;
- }
- status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
- sppi,
- sppi_size,
- &result_size);
- if (!NT_SUCCESS(status)) {
- err = pRtlNtStatusToDosError(status);
- goto error;
- }
- TOOLKIT_ASSERT(result_size == sppi_size);
- for (i = 0; i < cpu_count; i++) {
- WCHAR key_name[128];
- HKEY processor_key;
- DWORD cpu_speed;
- DWORD cpu_speed_size = sizeof(cpu_speed);
- WCHAR cpu_brand[256];
- DWORD cpu_brand_size = sizeof(cpu_brand);
- size_t len;
- len = _snwprintf(key_name,
- array_size(key_name),
- L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
- i);
- TOOLKIT_ASSERT(len > 0 && len < array_size(key_name));
- err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
- key_name,
- 0,
- KEY_QUERY_VALUE,
- &processor_key);
- if (err != ERROR_SUCCESS) {
- goto error;
- }
- err = RegQueryValueExW(processor_key,
- L"~MHz",
- NULL,
- NULL,
- (BYTE*)&cpu_speed,
- &cpu_speed_size);
- if (err != ERROR_SUCCESS) {
- RegCloseKey(processor_key);
- goto error;
- }
- err = RegQueryValueExW(processor_key,
- L"ProcessorNameString",
- NULL,
- NULL,
- (BYTE*)&cpu_brand,
- &cpu_brand_size);
- RegCloseKey(processor_key);
- if (err != ERROR_SUCCESS)
- goto error;
- cpu_info = &cpu_infos[i];
- cpu_info->speed = cpu_speed;
- cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
- cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
- sppi[i].IdleTime.QuadPart) / 10000;
- cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
- cpu_info->cpu_times.irq = sppi[i].Reserved1[1].QuadPart / 10000;
- cpu_info->cpu_times.nice = 0;
- toolkit__convert_utf16_to_utf8(cpu_brand,
- cpu_brand_size / sizeof(WCHAR),
- &(cpu_info->model));
- }
- FREE(sppi);
- *cpu_count_ptr = cpu_count;
- *cpu_infos_ptr = cpu_infos;
- return 0;
- error:
- if (cpu_infos != NULL) {
- /* This is safe because the cpu_infos array is zeroed on allocation. */
- for (i = 0; i < cpu_count; i++)
- FREE(cpu_infos[i].model);
- }
- FREE(cpu_infos);
- FREE(sppi);
- return toolkit_translate_sys_error(err);
- }
- int toolkit_interface_addresses(toolkit_interface_address_t** addresses_ptr, int* count_ptr)
- {
- IP_ADAPTER_ADDRESSES* win_address_buf;
- ULONG win_address_buf_size;
- IP_ADAPTER_ADDRESSES* adapter;
- toolkit_interface_address_t* toolkit_address_buf;
- char* name_buf;
- size_t toolkit_address_buf_size;
- toolkit_interface_address_t* toolkit_address;
- int count;
- ULONG flags;
- *addresses_ptr = NULL;
- *count_ptr = 0;
- flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
- GAA_FLAG_SKIP_DNS_SERVER;
- /* Fetch the size of the adapters reported by windows, and then get the list
- * itself. */
- win_address_buf_size = 0;
- win_address_buf = NULL;
- for (;;) {
- ULONG r;
- /* 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,
- flags,
- NULL,
- win_address_buf,
- &win_address_buf_size);
- 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 = toolkit_malloc(win_address_buf_size);
- if (win_address_buf == NULL)
- return TOOLKIT_ENOMEM;
- continue;
- case ERROR_NO_DATA:
- {
- /* No adapters were found. */
- toolkit_address_buf = toolkit_malloc(1);
- if (toolkit_address_buf == NULL)
- return TOOLKIT_ENOMEM;
- *count_ptr = 0;
- *addresses_ptr = toolkit_address_buf;
- return 0;
- }
- case ERROR_ADDRESS_NOT_ASSOCIATED:
- return TOOLKIT_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 TOOLKIT_ENOBUFS;
- default:
- /* Other (unspecified) errors can happen, but we don't have any special
- * meaning for them. */
- TOOLKIT_ASSERT(r != ERROR_SUCCESS);
- return toolkit_translate_sys_error(r);
- }
- }
- /* Count the number of enabled interfaces and compute how much space is
- * needed to store their info. */
- count = 0;
- toolkit_address_buf_size = 0;
- 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 (adapter->OperStatus != IfOperStatusUp ||
- adapter->FirstUnicastAddress == NULL)
- continue;
- /* Compute the size of the interface name. */
- name_size = WideCharToMultiByte(CP_UTF8,
- 0,
- adapter->FriendlyName,
- -1,
- NULL,
- 0,
- NULL,
- FALSE);
- if (name_size <= 0) {
- FREE(win_address_buf);
- return toolkit_translate_sys_error(GetLastError());
- }
- toolkit_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*)
- adapter->FirstUnicastAddress;
- unicast_address != NULL;
- unicast_address = unicast_address->Next) {
- count++;
- toolkit_address_buf_size += sizeof(toolkit_interface_address_t);
- }
- }
- /* Allocate space to store interface data plus adapter names. */
- toolkit_address_buf = toolkit_malloc(toolkit_address_buf_size);
- if (toolkit_address_buf == NULL) {
- FREE(win_address_buf);
- return TOOLKIT_ENOMEM;
- }
- /* Compute the start of the toolkit_interface_address_t array, and the place in
- * the buffer where the interface names will be stored. */
- toolkit_address = toolkit_address_buf;
- name_buf = (char*)(toolkit_address_buf + count);
- /* Fill out the output buffer. */
- 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 (adapter->OperStatus != IfOperStatusUp ||
- adapter->FirstUnicastAddress == NULL)
- continue;
- /* Convert the interface name to UTF8. */
- max_name_size = (char*)toolkit_address_buf + toolkit_address_buf_size - name_buf;
- if (max_name_size > (size_t)INT_MAX)
- max_name_size = INT_MAX;
- name_size = WideCharToMultiByte(CP_UTF8,
- 0,
- adapter->FriendlyName,
- -1,
- name_buf,
- (int)max_name_size,
- NULL,
- FALSE);
- if (name_size <= 0) {
- FREE(win_address_buf);
- FREE(toolkit_address_buf);
- return toolkit_translate_sys_error(GetLastError());
- }
- /* Add an toolkit_interface_address_t element for every unicast address. */
- 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 = ((IP_ADAPTER_UNICAST_ADDRESS_LH*)unicast_address)->OnLinkPrefixLength;
- memset(toolkit_address, 0, sizeof * toolkit_address);
- toolkit_address->name = name_buf;
- if (adapter->PhysicalAddressLength == sizeof(toolkit_address->phys_addr)) {
- memcpy(toolkit_address->phys_addr,
- adapter->PhysicalAddress,
- sizeof(toolkit_address->phys_addr));
- }
- toolkit_address->is_internal =
- (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
- if (sa->sa_family == AF_INET6) {
- toolkit_address->address.address6 = *((struct sockaddr_in6*)sa);
- toolkit_address->netmask.netmask6.sin6_family = AF_INET6;
- memset(toolkit_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
- /* This check ensures that we don't write past the size of the data. */
- if (prefix_len % 8) {
- toolkit_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
- 0xff << (8 - prefix_len % 8);
- }
- } else {
- toolkit_address->address.address4 = *((struct sockaddr_in*)sa);
- toolkit_address->netmask.netmask4.sin_family = AF_INET;
- toolkit_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
- htonl(0xffffffff << (32 - prefix_len)) : 0;
- }
- toolkit_address++;
- }
- name_buf += name_size;
- }
- FREE(win_address_buf);
- *addresses_ptr = toolkit_address_buf;
- *count_ptr = count;
- return 0;
- }
- void toolkit_free_interface_addresses(toolkit_interface_address_t* addresses, int count)
- {
- FREE(addresses);
- }
- #if (!defined(_MSC_VER )) || (_MSC_VER < 1928)
- int snprintf(char* buf, size_t len, const char* fmt, ...)
- {
- int n;
- va_list ap;
- va_start(ap, fmt);
- n = _vscprintf(fmt, ap);
- vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
- va_end(ap);
- return n;
- }
- #endif
|