util.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. #include "precompile.h"
  2. #include "toolkit.h"
  3. #include "internal.h"
  4. #include <winsock2.h>
  5. #include <winperf.h>
  6. #include <iphlpapi.h>
  7. #include <psapi.h>
  8. #include <tlhelp32.h>
  9. #include <windows.h>
  10. #include <userenv.h>
  11. #include <math.h>
  12. #include "dbgutil.h"
  13. #pragma comment(lib, "IPHlpApi.lib")
  14. /*
  15. * Converts a UTF-16 string into a UTF-8 one. The resulting string is
  16. * null-terminated.
  17. *
  18. * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
  19. * be specified.
  20. */
  21. int toolkit__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8)
  22. {
  23. DWORD bufsize;
  24. if (utf16 == NULL)
  25. return TOOLKIT_EINVAL;
  26. /* Check how much space we need */
  27. bufsize = WideCharToMultiByte(CP_UTF8,
  28. 0,
  29. utf16,
  30. utf16len,
  31. NULL,
  32. 0,
  33. NULL,
  34. NULL);
  35. if (bufsize == 0)
  36. return toolkit_translate_sys_error(GetLastError());
  37. /* Allocate the destination buffer adding an extra byte for the terminating
  38. * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
  39. * we do it ourselves always, just in case. */
  40. *utf8 = ZALLOC(bufsize + 1);
  41. if (*utf8 == NULL)
  42. return TOOLKIT_ENOMEM;
  43. /* Convert to UTF-8 */
  44. bufsize = WideCharToMultiByte(CP_UTF8,
  45. 0,
  46. utf16,
  47. utf16len,
  48. *utf8,
  49. bufsize,
  50. NULL,
  51. NULL);
  52. if (bufsize == 0) {
  53. FREE(*utf8);
  54. *utf8 = NULL;
  55. return toolkit_translate_sys_error(GetLastError());
  56. }
  57. (*utf8)[bufsize] = '\0';
  58. return 0;
  59. }
  60. /*
  61. * Converts a UTF-8 string into a UTF-16 one. The resulting string is
  62. * null-terminated.
  63. *
  64. * If utf8 is null terminated, utf8len can be set to -1, otherwise it must
  65. * be specified.
  66. */
  67. int toolkit__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16)
  68. {
  69. int bufsize;
  70. if (utf8 == NULL)
  71. return TOOLKIT_EINVAL;
  72. /* Check how much space we need */
  73. bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
  74. if (bufsize == 0)
  75. return toolkit_translate_sys_error(GetLastError());
  76. /* Allocate the destination buffer adding an extra byte for the terminating
  77. * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
  78. * we do it ourselves always, just in case. */
  79. *utf16 = ZALLOC(sizeof(WCHAR) * (bufsize + 1));
  80. if (*utf16 == NULL)
  81. return TOOLKIT_ENOMEM;
  82. /* Convert to UTF-16 */
  83. bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
  84. if (bufsize == 0) {
  85. FREE(*utf16);
  86. *utf16 = NULL;
  87. return toolkit_translate_sys_error(GetLastError());
  88. }
  89. (*utf16)[bufsize] = L'\0';
  90. return 0;
  91. }
  92. int toolkit_cpu_info(toolkit_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr)
  93. {
  94. toolkit_cpu_info_t* cpu_infos;
  95. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
  96. DWORD sppi_size;
  97. SYSTEM_INFO system_info;
  98. DWORD cpu_count, i;
  99. NTSTATUS status;
  100. ULONG result_size;
  101. int err;
  102. toolkit_cpu_info_t* cpu_info;
  103. cpu_infos = NULL;
  104. cpu_count = 0;
  105. sppi = NULL;
  106. toolkit__once_init();
  107. GetSystemInfo(&system_info);
  108. cpu_count = system_info.dwNumberOfProcessors;
  109. cpu_infos = toolkit_calloc(cpu_count, sizeof * cpu_infos);
  110. if (cpu_infos == NULL) {
  111. err = ERROR_OUTOFMEMORY;
  112. goto error;
  113. }
  114. sppi_size = cpu_count * sizeof(*sppi);
  115. sppi = toolkit_malloc(sppi_size);
  116. if (sppi == NULL) {
  117. err = ERROR_OUTOFMEMORY;
  118. goto error;
  119. }
  120. status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
  121. sppi,
  122. sppi_size,
  123. &result_size);
  124. if (!NT_SUCCESS(status)) {
  125. err = pRtlNtStatusToDosError(status);
  126. goto error;
  127. }
  128. TOOLKIT_ASSERT(result_size == sppi_size);
  129. for (i = 0; i < cpu_count; i++) {
  130. WCHAR key_name[128];
  131. HKEY processor_key;
  132. DWORD cpu_speed;
  133. DWORD cpu_speed_size = sizeof(cpu_speed);
  134. WCHAR cpu_brand[256];
  135. DWORD cpu_brand_size = sizeof(cpu_brand);
  136. size_t len;
  137. len = _snwprintf(key_name,
  138. array_size(key_name),
  139. L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
  140. i);
  141. TOOLKIT_ASSERT(len > 0 && len < array_size(key_name));
  142. err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  143. key_name,
  144. 0,
  145. KEY_QUERY_VALUE,
  146. &processor_key);
  147. if (err != ERROR_SUCCESS) {
  148. goto error;
  149. }
  150. err = RegQueryValueExW(processor_key,
  151. L"~MHz",
  152. NULL,
  153. NULL,
  154. (BYTE*)&cpu_speed,
  155. &cpu_speed_size);
  156. if (err != ERROR_SUCCESS) {
  157. RegCloseKey(processor_key);
  158. goto error;
  159. }
  160. err = RegQueryValueExW(processor_key,
  161. L"ProcessorNameString",
  162. NULL,
  163. NULL,
  164. (BYTE*)&cpu_brand,
  165. &cpu_brand_size);
  166. RegCloseKey(processor_key);
  167. if (err != ERROR_SUCCESS)
  168. goto error;
  169. cpu_info = &cpu_infos[i];
  170. cpu_info->speed = cpu_speed;
  171. cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
  172. cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
  173. sppi[i].IdleTime.QuadPart) / 10000;
  174. cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
  175. cpu_info->cpu_times.irq = sppi[i].Reserved1[1].QuadPart / 10000;
  176. cpu_info->cpu_times.nice = 0;
  177. toolkit__convert_utf16_to_utf8(cpu_brand,
  178. cpu_brand_size / sizeof(WCHAR),
  179. &(cpu_info->model));
  180. }
  181. FREE(sppi);
  182. *cpu_count_ptr = cpu_count;
  183. *cpu_infos_ptr = cpu_infos;
  184. return 0;
  185. error:
  186. if (cpu_infos != NULL) {
  187. /* This is safe because the cpu_infos array is zeroed on allocation. */
  188. for (i = 0; i < cpu_count; i++)
  189. FREE(cpu_infos[i].model);
  190. }
  191. FREE(cpu_infos);
  192. FREE(sppi);
  193. return toolkit_translate_sys_error(err);
  194. }
  195. int toolkit_interface_addresses(toolkit_interface_address_t** addresses_ptr, int* count_ptr)
  196. {
  197. IP_ADAPTER_ADDRESSES* win_address_buf;
  198. ULONG win_address_buf_size;
  199. IP_ADAPTER_ADDRESSES* adapter;
  200. toolkit_interface_address_t* toolkit_address_buf;
  201. char* name_buf;
  202. size_t toolkit_address_buf_size;
  203. toolkit_interface_address_t* toolkit_address;
  204. int count;
  205. ULONG flags;
  206. *addresses_ptr = NULL;
  207. *count_ptr = 0;
  208. flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
  209. GAA_FLAG_SKIP_DNS_SERVER;
  210. /* Fetch the size of the adapters reported by windows, and then get the list
  211. * itself. */
  212. win_address_buf_size = 0;
  213. win_address_buf = NULL;
  214. for (;;) {
  215. ULONG r;
  216. /* If win_address_buf is 0, then GetAdaptersAddresses will fail with.
  217. * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in
  218. * win_address_buf_size. */
  219. r = GetAdaptersAddresses(AF_UNSPEC,
  220. flags,
  221. NULL,
  222. win_address_buf,
  223. &win_address_buf_size);
  224. if (r == ERROR_SUCCESS)
  225. break;
  226. FREE(win_address_buf);
  227. switch (r) {
  228. case ERROR_BUFFER_OVERFLOW:
  229. /* This happens when win_address_buf is NULL or too small to hold all
  230. * adapters. */
  231. win_address_buf = toolkit_malloc(win_address_buf_size);
  232. if (win_address_buf == NULL)
  233. return TOOLKIT_ENOMEM;
  234. continue;
  235. case ERROR_NO_DATA:
  236. {
  237. /* No adapters were found. */
  238. toolkit_address_buf = toolkit_malloc(1);
  239. if (toolkit_address_buf == NULL)
  240. return TOOLKIT_ENOMEM;
  241. *count_ptr = 0;
  242. *addresses_ptr = toolkit_address_buf;
  243. return 0;
  244. }
  245. case ERROR_ADDRESS_NOT_ASSOCIATED:
  246. return TOOLKIT_EAGAIN;
  247. case ERROR_INVALID_PARAMETER:
  248. /* MSDN says:
  249. * "This error is returned for any of the following conditions: the
  250. * SizePointer parameter is NULL, the Address parameter is not
  251. * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
  252. * the parameters requested is greater than ULONG_MAX."
  253. * Since the first two conditions are not met, it must be that the
  254. * adapter data is too big.
  255. */
  256. return TOOLKIT_ENOBUFS;
  257. default:
  258. /* Other (unspecified) errors can happen, but we don't have any special
  259. * meaning for them. */
  260. TOOLKIT_ASSERT(r != ERROR_SUCCESS);
  261. return toolkit_translate_sys_error(r);
  262. }
  263. }
  264. /* Count the number of enabled interfaces and compute how much space is
  265. * needed to store their info. */
  266. count = 0;
  267. toolkit_address_buf_size = 0;
  268. for (adapter = win_address_buf;
  269. adapter != NULL;
  270. adapter = adapter->Next) {
  271. IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
  272. int name_size;
  273. /* Interfaces that are not 'up' should not be reported. Also skip
  274. * interfaces that have no associated unicast address, as to avoid
  275. * allocating space for the name for this interface. */
  276. if (adapter->OperStatus != IfOperStatusUp ||
  277. adapter->FirstUnicastAddress == NULL)
  278. continue;
  279. /* Compute the size of the interface name. */
  280. name_size = WideCharToMultiByte(CP_UTF8,
  281. 0,
  282. adapter->FriendlyName,
  283. -1,
  284. NULL,
  285. 0,
  286. NULL,
  287. FALSE);
  288. if (name_size <= 0) {
  289. FREE(win_address_buf);
  290. return toolkit_translate_sys_error(GetLastError());
  291. }
  292. toolkit_address_buf_size += name_size;
  293. /* Count the number of addresses associated with this interface, and
  294. * compute the size. */
  295. for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
  296. adapter->FirstUnicastAddress;
  297. unicast_address != NULL;
  298. unicast_address = unicast_address->Next) {
  299. count++;
  300. toolkit_address_buf_size += sizeof(toolkit_interface_address_t);
  301. }
  302. }
  303. /* Allocate space to store interface data plus adapter names. */
  304. toolkit_address_buf = toolkit_malloc(toolkit_address_buf_size);
  305. if (toolkit_address_buf == NULL) {
  306. FREE(win_address_buf);
  307. return TOOLKIT_ENOMEM;
  308. }
  309. /* Compute the start of the toolkit_interface_address_t array, and the place in
  310. * the buffer where the interface names will be stored. */
  311. toolkit_address = toolkit_address_buf;
  312. name_buf = (char*)(toolkit_address_buf + count);
  313. /* Fill out the output buffer. */
  314. for (adapter = win_address_buf;
  315. adapter != NULL;
  316. adapter = adapter->Next) {
  317. IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
  318. int name_size;
  319. size_t max_name_size;
  320. if (adapter->OperStatus != IfOperStatusUp ||
  321. adapter->FirstUnicastAddress == NULL)
  322. continue;
  323. /* Convert the interface name to UTF8. */
  324. max_name_size = (char*)toolkit_address_buf + toolkit_address_buf_size - name_buf;
  325. if (max_name_size > (size_t)INT_MAX)
  326. max_name_size = INT_MAX;
  327. name_size = WideCharToMultiByte(CP_UTF8,
  328. 0,
  329. adapter->FriendlyName,
  330. -1,
  331. name_buf,
  332. (int)max_name_size,
  333. NULL,
  334. FALSE);
  335. if (name_size <= 0) {
  336. FREE(win_address_buf);
  337. FREE(toolkit_address_buf);
  338. return toolkit_translate_sys_error(GetLastError());
  339. }
  340. /* Add an toolkit_interface_address_t element for every unicast address. */
  341. for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
  342. adapter->FirstUnicastAddress;
  343. unicast_address != NULL;
  344. unicast_address = unicast_address->Next) {
  345. struct sockaddr* sa;
  346. ULONG prefix_len;
  347. sa = unicast_address->Address.lpSockaddr;
  348. prefix_len = ((IP_ADAPTER_UNICAST_ADDRESS_LH*)unicast_address)->OnLinkPrefixLength;
  349. memset(toolkit_address, 0, sizeof * toolkit_address);
  350. toolkit_address->name = name_buf;
  351. if (adapter->PhysicalAddressLength == sizeof(toolkit_address->phys_addr)) {
  352. memcpy(toolkit_address->phys_addr,
  353. adapter->PhysicalAddress,
  354. sizeof(toolkit_address->phys_addr));
  355. }
  356. toolkit_address->is_internal =
  357. (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
  358. if (sa->sa_family == AF_INET6) {
  359. toolkit_address->address.address6 = *((struct sockaddr_in6*)sa);
  360. toolkit_address->netmask.netmask6.sin6_family = AF_INET6;
  361. memset(toolkit_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
  362. /* This check ensures that we don't write past the size of the data. */
  363. if (prefix_len % 8) {
  364. toolkit_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
  365. 0xff << (8 - prefix_len % 8);
  366. }
  367. } else {
  368. toolkit_address->address.address4 = *((struct sockaddr_in*)sa);
  369. toolkit_address->netmask.netmask4.sin_family = AF_INET;
  370. toolkit_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
  371. htonl(0xffffffff << (32 - prefix_len)) : 0;
  372. }
  373. toolkit_address++;
  374. }
  375. name_buf += name_size;
  376. }
  377. FREE(win_address_buf);
  378. *addresses_ptr = toolkit_address_buf;
  379. *count_ptr = count;
  380. return 0;
  381. }
  382. void toolkit_free_interface_addresses(toolkit_interface_address_t* addresses, int count)
  383. {
  384. FREE(addresses);
  385. }
  386. #if (!defined(_MSC_VER )) || (_MSC_VER < 1928)
  387. int snprintf(char* buf, size_t len, const char* fmt, ...)
  388. {
  389. int n;
  390. va_list ap;
  391. va_start(ap, fmt);
  392. n = _vscprintf(fmt, ap);
  393. vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
  394. va_end(ap);
  395. return n;
  396. }
  397. #endif