1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 */
21
22 #include <assert.h>
23 #include <direct.h>
24 #include <limits.h>
25 #include <malloc.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <time.h>
29 #include <wchar.h>
30
31 #include "uv.h"
32 #include "internal.h"
33
34 #include <winsock2.h>
35 #include <winperf.h>
36 #include <iphlpapi.h>
37 #include <psapi.h>
38 #include <tlhelp32.h>
39
40
41 /*
42 * Max title length; the only thing MSDN tells us about the maximum length
43 * of the console title is that it is smaller than 64K. However in practice
44 * it is much smaller, and there is no way to figure out what the exact length
45 * of the title is or can be, at least not on XP. To make it even more
46 * annoying, GetConsoleTitle failes when the buffer to be read into is bigger
47 * than the actual maximum length. So we make a conservative guess here;
48 * just don't put the novel you're writing in the title, unless the plot
49 * survives truncation.
50 */
51 #define MAX_TITLE_LENGTH 8192
52
53 /* The number of nanoseconds in one second. */
54 #undef NANOSEC
55 #define NANOSEC 1000000000
56
57
58 /* Cached copy of the process title, plus a mutex guarding it. */
59 static char *process_title;
60 static CRITICAL_SECTION process_title_lock;
61
62 /* Frequency (ticks per nanosecond) of the high-resolution clock. */
63 static double hrtime_frequency_ = 0;
64
65
66 /*
67 * One-time intialization code for functionality defined in util.c.
68 */
uv__util_init()69 void uv__util_init() {
70 LARGE_INTEGER perf_frequency;
71
72 /* Initialize process title access mutex. */
73 InitializeCriticalSection(&process_title_lock);
74
75 /* Retrieve high-resolution timer frequency. */
76 if (QueryPerformanceFrequency(&perf_frequency))
77 hrtime_frequency_ = (double) perf_frequency.QuadPart / (double) NANOSEC;
78 else
79 hrtime_frequency_= 0;
80 }
81
82
uv_utf16_to_utf8(const WCHAR * utf16Buffer,size_t utf16Size,char * utf8Buffer,size_t utf8Size)83 int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
84 char* utf8Buffer, size_t utf8Size) {
85 return WideCharToMultiByte(CP_UTF8,
86 0,
87 utf16Buffer,
88 utf16Size,
89 utf8Buffer,
90 utf8Size,
91 NULL,
92 NULL);
93 }
94
95
uv_utf8_to_utf16(const char * utf8Buffer,WCHAR * utf16Buffer,size_t utf16Size)96 int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
97 size_t utf16Size) {
98 return MultiByteToWideChar(CP_UTF8,
99 0,
100 utf8Buffer,
101 -1,
102 utf16Buffer,
103 utf16Size);
104 }
105
106
uv_exepath(char * buffer,size_t * size_ptr)107 int uv_exepath(char* buffer, size_t* size_ptr) {
108 int utf8_len, utf16_buffer_len, utf16_len;
109 WCHAR* utf16_buffer;
110 int err;
111
112 if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
113 return UV_EINVAL;
114 }
115
116 if (*size_ptr > 32768) {
117 /* Windows paths can never be longer than this. */
118 utf16_buffer_len = 32768;
119 } else {
120 utf16_buffer_len = (int) *size_ptr;
121 }
122
123 utf16_buffer = (WCHAR*) malloc(sizeof(WCHAR) * utf16_buffer_len);
124 if (!utf16_buffer) {
125 return UV_ENOMEM;
126 }
127
128 /* Get the path as UTF-16. */
129 utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
130 if (utf16_len <= 0) {
131 err = GetLastError();
132 goto error;
133 }
134
135 /* utf16_len contains the length, *not* including the terminating null. */
136 utf16_buffer[utf16_len] = L'\0';
137
138 /* Convert to UTF-8 */
139 utf8_len = WideCharToMultiByte(CP_UTF8,
140 0,
141 utf16_buffer,
142 -1,
143 buffer,
144 *size_ptr > INT_MAX ? INT_MAX : (int) *size_ptr,
145 NULL,
146 NULL);
147 if (utf8_len == 0) {
148 err = GetLastError();
149 goto error;
150 }
151
152 free(utf16_buffer);
153
154 /* utf8_len *does* include the terminating null at this point, but the */
155 /* returned size shouldn't. */
156 *size_ptr = utf8_len - 1;
157 return 0;
158
159 error:
160 free(utf16_buffer);
161 return uv_translate_sys_error(err);
162 }
163
164
uv_cwd(char * buffer,size_t size)165 int uv_cwd(char* buffer, size_t size) {
166 DWORD utf16_len;
167 WCHAR utf16_buffer[MAX_PATH];
168 int r;
169
170 if (buffer == NULL || size == 0) {
171 return UV_EINVAL;
172 }
173
174 utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
175 if (utf16_len == 0) {
176 return uv_translate_sys_error(GetLastError());
177 } else if (utf16_len > MAX_PATH) {
178 /* This should be impossible; however the CRT has a code path to deal */
179 /* with this scenario, so I added a check anyway. */
180 return UV_EIO;
181 }
182
183 /* utf16_len contains the length, *not* including the terminating null. */
184 utf16_buffer[utf16_len] = L'\0';
185
186 /* The returned directory should not have a trailing slash, unless it */
187 /* points at a drive root, like c:\. Remove it if needed.*/
188 if (utf16_buffer[utf16_len - 1] == L'\\' &&
189 !(utf16_len == 3 && utf16_buffer[1] == L':')) {
190 utf16_len--;
191 utf16_buffer[utf16_len] = L'\0';
192 }
193
194 /* Convert to UTF-8 */
195 r = WideCharToMultiByte(CP_UTF8,
196 0,
197 utf16_buffer,
198 -1,
199 buffer,
200 size > INT_MAX ? INT_MAX : (int) size,
201 NULL,
202 NULL);
203 if (r == 0) {
204 return uv_translate_sys_error(GetLastError());
205 }
206
207 return 0;
208 }
209
210
uv_chdir(const char * dir)211 int uv_chdir(const char* dir) {
212 WCHAR utf16_buffer[MAX_PATH];
213 size_t utf16_len;
214 WCHAR drive_letter, env_var[4];
215
216 if (dir == NULL) {
217 return UV_EINVAL;
218 }
219
220 if (MultiByteToWideChar(CP_UTF8,
221 0,
222 dir,
223 -1,
224 utf16_buffer,
225 MAX_PATH) == 0) {
226 DWORD error = GetLastError();
227 /* The maximum length of the current working directory is 260 chars, */
228 /* including terminating null. If it doesn't fit, the path name must be */
229 /* too long. */
230 if (error == ERROR_INSUFFICIENT_BUFFER) {
231 return UV_ENAMETOOLONG;
232 } else {
233 return uv_translate_sys_error(error);
234 }
235 }
236
237 if (!SetCurrentDirectoryW(utf16_buffer)) {
238 return uv_translate_sys_error(GetLastError());
239 }
240
241 /* Windows stores the drive-local path in an "hidden" environment variable, */
242 /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */
243 /* update this, so we'll have to do it. */
244 utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
245 if (utf16_len == 0) {
246 return uv_translate_sys_error(GetLastError());
247 } else if (utf16_len > MAX_PATH) {
248 return UV_EIO;
249 }
250
251 /* The returned directory should not have a trailing slash, unless it */
252 /* points at a drive root, like c:\. Remove it if needed. */
253 if (utf16_buffer[utf16_len - 1] == L'\\' &&
254 !(utf16_len == 3 && utf16_buffer[1] == L':')) {
255 utf16_len--;
256 utf16_buffer[utf16_len] = L'\0';
257 }
258
259 if (utf16_len < 2 || utf16_buffer[1] != L':') {
260 /* Doesn't look like a drive letter could be there - probably an UNC */
261 /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */
262 drive_letter = 0;
263 } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
264 drive_letter = utf16_buffer[0];
265 } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
266 /* Convert to uppercase. */
267 drive_letter = utf16_buffer[0] - L'a' + L'A';
268 } else {
269 /* Not valid. */
270 drive_letter = 0;
271 }
272
273 if (drive_letter != 0) {
274 /* Construct the environment variable name and set it. */
275 env_var[0] = L'=';
276 env_var[1] = drive_letter;
277 env_var[2] = L':';
278 env_var[3] = L'\0';
279
280 if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
281 return uv_translate_sys_error(GetLastError());
282 }
283 }
284
285 return 0;
286 }
287
288
uv_loadavg(double avg[3])289 void uv_loadavg(double avg[3]) {
290 /* Can't be implemented */
291 avg[0] = avg[1] = avg[2] = 0;
292 }
293
294
uv_get_free_memory(void)295 uint64_t uv_get_free_memory(void) {
296 MEMORYSTATUSEX memory_status;
297 memory_status.dwLength = sizeof(memory_status);
298
299 if(!GlobalMemoryStatusEx(&memory_status))
300 {
301 return -1;
302 }
303
304 return (uint64_t)memory_status.ullAvailPhys;
305 }
306
307
uv_get_total_memory(void)308 uint64_t uv_get_total_memory(void) {
309 MEMORYSTATUSEX memory_status;
310 memory_status.dwLength = sizeof(memory_status);
311
312 if(!GlobalMemoryStatusEx(&memory_status))
313 {
314 return -1;
315 }
316
317 return (uint64_t)memory_status.ullTotalPhys;
318 }
319
320
uv_parent_pid()321 int uv_parent_pid() {
322 int parent_pid = -1;
323 HANDLE handle;
324 PROCESSENTRY32 pe;
325 int current_pid = GetCurrentProcessId();
326
327 pe.dwSize = sizeof(PROCESSENTRY32);
328 handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
329
330 if (Process32First(handle, &pe)) {
331 do {
332 if (pe.th32ProcessID == current_pid) {
333 parent_pid = pe.th32ParentProcessID;
334 break;
335 }
336 } while( Process32Next(handle, &pe));
337 }
338
339 CloseHandle(handle);
340 return parent_pid;
341 }
342
343
uv_setup_args(int argc,char ** argv)344 char** uv_setup_args(int argc, char** argv) {
345 return argv;
346 }
347
348
uv_set_process_title(const char * title)349 int uv_set_process_title(const char* title) {
350 int err;
351 int length;
352 WCHAR* title_w = NULL;
353
354 uv__once_init();
355
356 /* Find out how big the buffer for the wide-char title must be */
357 length = uv_utf8_to_utf16(title, NULL, 0);
358 if (!length) {
359 err = GetLastError();
360 goto done;
361 }
362
363 /* Convert to wide-char string */
364 title_w = (WCHAR*)malloc(sizeof(WCHAR) * length);
365 if (!title_w) {
366 uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
367 }
368
369 length = uv_utf8_to_utf16(title, title_w, length);
370 if (!length) {
371 err = GetLastError();
372 goto done;
373 };
374
375 /* If the title must be truncated insert a \0 terminator there */
376 if (length > MAX_TITLE_LENGTH) {
377 title_w[MAX_TITLE_LENGTH - 1] = L'\0';
378 }
379
380 if (!SetConsoleTitleW(title_w)) {
381 err = GetLastError();
382 goto done;
383 }
384
385 EnterCriticalSection(&process_title_lock);
386 free(process_title);
387 process_title = strdup(title);
388 LeaveCriticalSection(&process_title_lock);
389
390 err = 0;
391
392 done:
393 free(title_w);
394 return uv_translate_sys_error(err);
395 }
396
397
uv__get_process_title()398 static int uv__get_process_title() {
399 WCHAR title_w[MAX_TITLE_LENGTH];
400 int length;
401
402 if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
403 return -1;
404 }
405
406 /* Find out what the size of the buffer is that we need */
407 length = uv_utf16_to_utf8(title_w, -1, NULL, 0);
408 if (!length) {
409 return -1;
410 }
411
412 assert(!process_title);
413 process_title = (char*)malloc(length);
414 if (!process_title) {
415 uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
416 }
417
418 /* Do utf16 -> utf8 conversion here */
419 if (!uv_utf16_to_utf8(title_w, -1, process_title, length)) {
420 free(process_title);
421 return -1;
422 }
423
424 return 0;
425 }
426
427
uv_get_process_title(char * buffer,size_t size)428 int uv_get_process_title(char* buffer, size_t size) {
429 uv__once_init();
430
431 EnterCriticalSection(&process_title_lock);
432 /*
433 * If the process_title was never read before nor explicitly set,
434 * we must query it with getConsoleTitleW
435 */
436 if (!process_title && uv__get_process_title() == -1) {
437 return uv_translate_sys_error(GetLastError());
438 }
439
440 assert(process_title);
441 strncpy(buffer, process_title, size);
442 LeaveCriticalSection(&process_title_lock);
443
444 return 0;
445 }
446
447
uv_hrtime(void)448 uint64_t uv_hrtime(void) {
449 LARGE_INTEGER counter;
450
451 uv__once_init();
452
453 /* If the performance frequency is zero, there's no support. */
454 if (hrtime_frequency_ == 0) {
455 /* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */
456 return 0;
457 }
458
459 if (!QueryPerformanceCounter(&counter)) {
460 /* uv__set_sys_error(loop, GetLastError()); */
461 return 0;
462 }
463
464 /* Because we have no guarantee about the order of magnitude of the
465 * performance counter frequency, integer math could cause this computation
466 * to overflow. Therefore we resort to floating point math.
467 */
468 return (uint64_t) ((double) counter.QuadPart / hrtime_frequency_);
469 }
470
471
uv_resident_set_memory(size_t * rss)472 int uv_resident_set_memory(size_t* rss) {
473 HANDLE current_process;
474 PROCESS_MEMORY_COUNTERS pmc;
475
476 current_process = GetCurrentProcess();
477
478 if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
479 return uv_translate_sys_error(GetLastError());
480 }
481
482 *rss = pmc.WorkingSetSize;
483
484 return 0;
485 }
486
487
uv_uptime(double * uptime)488 int uv_uptime(double* uptime) {
489 BYTE stack_buffer[4096];
490 BYTE* malloced_buffer = NULL;
491 BYTE* buffer = (BYTE*) stack_buffer;
492 size_t buffer_size = sizeof(stack_buffer);
493 DWORD data_size;
494
495 PERF_DATA_BLOCK* data_block;
496 PERF_OBJECT_TYPE* object_type;
497 PERF_COUNTER_DEFINITION* counter_definition;
498
499 DWORD i;
500
501 for (;;) {
502 LONG result;
503
504 data_size = (DWORD) buffer_size;
505 result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
506 L"2",
507 NULL,
508 NULL,
509 buffer,
510 &data_size);
511 if (result == ERROR_SUCCESS) {
512 break;
513 } else if (result != ERROR_MORE_DATA) {
514 *uptime = 0;
515 return uv_translate_sys_error(result);
516 }
517
518 free(malloced_buffer);
519
520 buffer_size *= 2;
521 /* Don't let the buffer grow infinitely. */
522 if (buffer_size > 1 << 20) {
523 goto internalError;
524 }
525
526 buffer = malloced_buffer = (BYTE*) malloc(buffer_size);
527 if (malloced_buffer == NULL) {
528 *uptime = 0;
529 return UV_ENOMEM;
530 }
531 }
532
533 if (data_size < sizeof(*data_block))
534 goto internalError;
535
536 data_block = (PERF_DATA_BLOCK*) buffer;
537
538 if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
539 goto internalError;
540
541 if (data_size < data_block->HeaderLength + sizeof(*object_type))
542 goto internalError;
543
544 object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
545
546 if (object_type->NumInstances != PERF_NO_INSTANCES)
547 goto internalError;
548
549 counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
550 data_block->HeaderLength + object_type->HeaderLength);
551 for (i = 0; i < object_type->NumCounters; i++) {
552 if ((BYTE*) counter_definition + sizeof(*counter_definition) >
553 buffer + data_size) {
554 break;
555 }
556
557 if (counter_definition->CounterNameTitleIndex == 674 &&
558 counter_definition->CounterSize == sizeof(uint64_t)) {
559 if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
560 !(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
561 goto internalError;
562 } else {
563 BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
564 counter_definition->CounterOffset;
565 uint64_t value = *((uint64_t*) address);
566 *uptime = (double) (object_type->PerfTime.QuadPart - value) /
567 (double) object_type->PerfFreq.QuadPart;
568 free(malloced_buffer);
569 return 0;
570 }
571 }
572
573 counter_definition = (PERF_COUNTER_DEFINITION*)
574 ((BYTE*) counter_definition + counter_definition->ByteLength);
575 }
576
577 /* If we get here, the uptime value was not found. */
578 free(malloced_buffer);
579 *uptime = 0;
580 return UV_ENOSYS;
581
582 internalError:
583 free(malloced_buffer);
584 *uptime = 0;
585 return UV_EIO;
586 }
587
588
uv_cpu_info(uv_cpu_info_t ** cpu_infos_ptr,int * cpu_count_ptr)589 int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
590 uv_cpu_info_t* cpu_infos;
591 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
592 DWORD sppi_size;
593 SYSTEM_INFO system_info;
594 DWORD cpu_count, r, i;
595 NTSTATUS status;
596 ULONG result_size;
597 int err;
598 uv_cpu_info_t* cpu_info;
599
600 cpu_infos = NULL;
601 cpu_count = 0;
602 sppi = NULL;
603
604 uv__once_init();
605
606 GetSystemInfo(&system_info);
607 cpu_count = system_info.dwNumberOfProcessors;
608
609 cpu_infos = calloc(cpu_count, sizeof *cpu_infos);
610 if (cpu_infos == NULL) {
611 err = ERROR_OUTOFMEMORY;
612 goto error;
613 }
614
615 sppi_size = cpu_count * sizeof(*sppi);
616 sppi = malloc(sppi_size);
617 if (sppi == NULL) {
618 err = ERROR_OUTOFMEMORY;
619 goto error;
620 }
621
622 status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
623 sppi,
624 sppi_size,
625 &result_size);
626 if (!NT_SUCCESS(status)) {
627 err = pRtlNtStatusToDosError(status);
628 goto error;
629 }
630
631 assert(result_size == sppi_size);
632
633 for (i = 0; i < cpu_count; i++) {
634 WCHAR key_name[128];
635 HKEY processor_key;
636 DWORD cpu_speed;
637 DWORD cpu_speed_size = sizeof(cpu_speed);
638 WCHAR cpu_brand[256];
639 DWORD cpu_brand_size = sizeof(cpu_brand);
640 int len;
641
642 len = _snwprintf(key_name,
643 ARRAY_SIZE(key_name),
644 L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
645 i);
646
647 assert(len > 0 && len < ARRAY_SIZE(key_name));
648
649 r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
650 key_name,
651 0,
652 KEY_QUERY_VALUE,
653 &processor_key);
654 if (r != ERROR_SUCCESS) {
655 err = GetLastError();
656 goto error;
657 }
658
659 if (RegQueryValueExW(processor_key,
660 L"~MHz",
661 NULL,
662 NULL,
663 (BYTE*) &cpu_speed,
664 &cpu_speed_size) != ERROR_SUCCESS) {
665 err = GetLastError();
666 RegCloseKey(processor_key);
667 goto error;
668 }
669
670 if (RegQueryValueExW(processor_key,
671 L"ProcessorNameString",
672 NULL,
673 NULL,
674 (BYTE*) &cpu_brand,
675 &cpu_brand_size) != ERROR_SUCCESS) {
676 err = GetLastError();
677 RegCloseKey(processor_key);
678 goto error;
679 }
680
681 RegCloseKey(processor_key);
682
683 cpu_info = &cpu_infos[i];
684 cpu_info->speed = cpu_speed;
685 cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
686 cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
687 sppi[i].IdleTime.QuadPart) / 10000;
688 cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
689 cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
690 cpu_info->cpu_times.nice = 0;
691
692
693 len = WideCharToMultiByte(CP_UTF8,
694 0,
695 cpu_brand,
696 cpu_brand_size / sizeof(WCHAR),
697 NULL,
698 0,
699 NULL,
700 NULL);
701 if (len == 0) {
702 err = GetLastError();
703 goto error;
704 }
705
706 assert(len > 0);
707
708 /* Allocate 1 extra byte for the null terminator. */
709 cpu_info->model = malloc(len + 1);
710 if (cpu_info->model == NULL) {
711 err = ERROR_OUTOFMEMORY;
712 goto error;
713 }
714
715 if (WideCharToMultiByte(CP_UTF8,
716 0,
717 cpu_brand,
718 cpu_brand_size / sizeof(WCHAR),
719 cpu_info->model,
720 len,
721 NULL,
722 NULL) == 0) {
723 err = GetLastError();
724 goto error;
725 }
726
727 /* Ensure that cpu_info->model is null terminated. */
728 cpu_info->model[len] = '\0';
729 }
730
731 free(sppi);
732
733 *cpu_count_ptr = cpu_count;
734 *cpu_infos_ptr = cpu_infos;
735
736 return 0;
737
738 error:
739 /* This is safe because the cpu_infos array is zeroed on allocation. */
740 for (i = 0; i < cpu_count; i++)
741 free(cpu_infos[i].model);
742
743 free(cpu_infos);
744 free(sppi);
745
746 return uv_translate_sys_error(err);
747 }
748
749
uv_free_cpu_info(uv_cpu_info_t * cpu_infos,int count)750 void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
751 int i;
752
753 for (i = 0; i < count; i++) {
754 free(cpu_infos[i].model);
755 }
756
757 free(cpu_infos);
758 }
759
760
is_windows_version_or_greater(DWORD os_major,DWORD os_minor,WORD service_pack_major,WORD service_pack_minor)761 static int is_windows_version_or_greater(DWORD os_major,
762 DWORD os_minor,
763 WORD service_pack_major,
764 WORD service_pack_minor) {
765 OSVERSIONINFOEX osvi;
766 DWORDLONG condition_mask = 0;
767 int op = VER_GREATER_EQUAL;
768
769 /* Initialize the OSVERSIONINFOEX structure. */
770 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
771 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
772 osvi.dwMajorVersion = os_major;
773 osvi.dwMinorVersion = os_minor;
774 osvi.wServicePackMajor = service_pack_major;
775 osvi.wServicePackMinor = service_pack_minor;
776
777 /* Initialize the condition mask. */
778 VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
779 VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
780 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
781 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
782
783 /* Perform the test. */
784 return (int) VerifyVersionInfo(
785 &osvi,
786 VER_MAJORVERSION | VER_MINORVERSION |
787 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
788 condition_mask);
789 }
790
791
address_prefix_match(int family,struct sockaddr * address,struct sockaddr * prefix_address,int prefix_len)792 static int address_prefix_match(int family,
793 struct sockaddr* address,
794 struct sockaddr* prefix_address,
795 int prefix_len) {
796 uint8_t* address_data;
797 uint8_t* prefix_address_data;
798 int i;
799
800 assert(address->sa_family == family);
801 assert(prefix_address->sa_family == family);
802
803 if (family == AF_INET6) {
804 address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
805 prefix_address_data =
806 (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
807 } else {
808 address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
809 prefix_address_data =
810 (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
811 }
812
813 for (i = 0; i < prefix_len >> 3; i++) {
814 if (address_data[i] != prefix_address_data[i])
815 return 0;
816 }
817
818 if (prefix_len % 8)
819 return prefix_address_data[i] ==
820 (address_data[i] & (0xff << (8 - prefix_len % 8)));
821
822 return 1;
823 }
824
825
uv_interface_addresses(uv_interface_address_t ** addresses_ptr,int * count_ptr)826 int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
827 int* count_ptr) {
828 IP_ADAPTER_ADDRESSES* win_address_buf;
829 ULONG win_address_buf_size;
830 IP_ADAPTER_ADDRESSES* adapter;
831
832 uv_interface_address_t* uv_address_buf;
833 char* name_buf;
834 size_t uv_address_buf_size;
835 uv_interface_address_t* uv_address;
836
837 int count;
838
839 int is_vista_or_greater;
840 ULONG flags;
841
842 is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
843 if (is_vista_or_greater) {
844 flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
845 GAA_FLAG_SKIP_DNS_SERVER;
846 } else {
847 /* We need at least XP SP1. */
848 if (!is_windows_version_or_greater(5, 1, 1, 0))
849 return UV_ENOTSUP;
850
851 flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
852 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
853 }
854
855
856 /* Fetch the size of the adapters reported by windows, and then get the */
857 /* list itself. */
858 win_address_buf_size = 0;
859 win_address_buf = NULL;
860
861 for (;;) {
862 ULONG r;
863
864 /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */
865 /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */
866 /* win_address_buf_size. */
867 r = GetAdaptersAddresses(AF_UNSPEC,
868 flags,
869 NULL,
870 win_address_buf,
871 &win_address_buf_size);
872
873 if (r == ERROR_SUCCESS)
874 break;
875
876 free(win_address_buf);
877
878 switch (r) {
879 case ERROR_BUFFER_OVERFLOW:
880 /* This happens when win_address_buf is NULL or too small to hold */
881 /* all adapters. */
882 win_address_buf = malloc(win_address_buf_size);
883 if (win_address_buf == NULL)
884 return UV_ENOMEM;
885
886 continue;
887
888 case ERROR_NO_DATA: {
889 /* No adapters were found. */
890 uv_address_buf = malloc(1);
891 if (uv_address_buf == NULL)
892 return UV_ENOMEM;
893
894 *count_ptr = 0;
895 *addresses_ptr = uv_address_buf;
896
897 return 0;
898 }
899
900 case ERROR_ADDRESS_NOT_ASSOCIATED:
901 return UV_EAGAIN;
902
903 case ERROR_INVALID_PARAMETER:
904 /* MSDN says:
905 * "This error is returned for any of the following conditions: the
906 * SizePointer parameter is NULL, the Address parameter is not
907 * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
908 * the parameters requested is greater than ULONG_MAX."
909 * Since the first two conditions are not met, it must be that the
910 * adapter data is too big.
911 */
912 return UV_ENOBUFS;
913
914 default:
915 /* Other (unspecified) errors can happen, but we don't have any */
916 /* special meaning for them. */
917 assert(r != ERROR_SUCCESS);
918 return uv_translate_sys_error(r);
919 }
920 }
921
922 /* Count the number of enabled interfaces and compute how much space is */
923 /* needed to store their info. */
924 count = 0;
925 uv_address_buf_size = 0;
926
927 for (adapter = win_address_buf;
928 adapter != NULL;
929 adapter = adapter->Next) {
930 IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
931 int name_size;
932
933 /* Interfaces that are not 'up' should not be reported. Also skip */
934 /* interfaces that have no associated unicast address, as to avoid */
935 /* allocating space for the name for this interface. */
936 if (adapter->OperStatus != IfOperStatusUp ||
937 adapter->FirstUnicastAddress == NULL)
938 continue;
939
940 /* Compute the size of the interface name. */
941 name_size = WideCharToMultiByte(CP_UTF8,
942 0,
943 adapter->FriendlyName,
944 -1,
945 NULL,
946 0,
947 NULL,
948 FALSE);
949 if (name_size <= 0) {
950 free(win_address_buf);
951 return uv_translate_sys_error(GetLastError());
952 }
953 uv_address_buf_size += name_size;
954
955 /* Count the number of addresses associated with this interface, and */
956 /* compute the size. */
957 for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
958 adapter->FirstUnicastAddress;
959 unicast_address != NULL;
960 unicast_address = unicast_address->Next) {
961 count++;
962 uv_address_buf_size += sizeof(uv_interface_address_t);
963 }
964 }
965
966 /* Allocate space to store interface data plus adapter names. */
967 uv_address_buf = malloc(uv_address_buf_size);
968 if (uv_address_buf == NULL) {
969 free(win_address_buf);
970 return UV_ENOMEM;
971 }
972
973 /* Compute the start of the uv_interface_address_t array, and the place in */
974 /* the buffer where the interface names will be stored. */
975 uv_address = uv_address_buf;
976 name_buf = (char*) (uv_address_buf + count);
977
978 /* Fill out the output buffer. */
979 for (adapter = win_address_buf;
980 adapter != NULL;
981 adapter = adapter->Next) {
982 IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
983 int name_size;
984 size_t max_name_size;
985
986 if (adapter->OperStatus != IfOperStatusUp ||
987 adapter->FirstUnicastAddress == NULL)
988 continue;
989
990 /* Convert the interface name to UTF8. */
991 max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
992 if (max_name_size > (size_t) INT_MAX)
993 max_name_size = INT_MAX;
994 name_size = WideCharToMultiByte(CP_UTF8,
995 0,
996 adapter->FriendlyName,
997 -1,
998 name_buf,
999 (int) max_name_size,
1000 NULL,
1001 FALSE);
1002 if (name_size <= 0) {
1003 free(win_address_buf);
1004 free(uv_address_buf);
1005 return uv_translate_sys_error(GetLastError());
1006 }
1007
1008 /* Add an uv_interface_address_t element for every unicast address. */
1009 for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
1010 adapter->FirstUnicastAddress;
1011 unicast_address != NULL;
1012 unicast_address = unicast_address->Next) {
1013 struct sockaddr* sa;
1014 ULONG prefix_len;
1015
1016 sa = unicast_address->Address.lpSockaddr;
1017
1018 /* XP has no OnLinkPrefixLength field. */
1019 if (is_vista_or_greater) {
1020 prefix_len = unicast_address->OnLinkPrefixLength;
1021 } else {
1022 /* Prior to Windows Vista the FirstPrefix pointed to the list with
1023 * single prefix for each IP address assigned to the adapter.
1024 * Order of FirstPrefix does not match order of FirstUnicastAddress,
1025 * so we need to find corresponding prefix.
1026 */
1027 IP_ADAPTER_PREFIX* prefix;
1028 prefix_len = 0;
1029
1030 for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
1031 /* We want the longest matching prefix. */
1032 if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
1033 prefix->PrefixLength <= prefix_len)
1034 continue;
1035
1036 if (address_prefix_match(sa->sa_family, sa,
1037 prefix->Address.lpSockaddr, prefix->PrefixLength)) {
1038 prefix_len = prefix->PrefixLength;
1039 }
1040 }
1041
1042 /* If there is no matching prefix information, return a single-host
1043 * subnet mask (e.g. 255.255.255.255 for IPv4).
1044 */
1045 if (!prefix_len)
1046 prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
1047 }
1048
1049 memset(uv_address, 0, sizeof *uv_address);
1050
1051 uv_address->name = name_buf;
1052
1053 if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
1054 memcpy(uv_address->phys_addr,
1055 adapter->PhysicalAddress,
1056 sizeof(uv_address->phys_addr));
1057 }
1058
1059 uv_address->is_internal =
1060 (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
1061
1062 if (sa->sa_family == AF_INET6) {
1063 uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
1064
1065 uv_address->netmask.netmask6.sin6_family = AF_INET6;
1066 memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
1067 /* This check ensures that we don't write past the size of the data. */
1068 if (prefix_len % 8) {
1069 uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
1070 0xff << (8 - prefix_len % 8);
1071 }
1072
1073 } else {
1074 uv_address->address.address4 = *((struct sockaddr_in *) sa);
1075
1076 uv_address->netmask.netmask4.sin_family = AF_INET;
1077 uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
1078 htonl(0xffffffff << (32 - prefix_len)) : 0;
1079 }
1080
1081 uv_address++;
1082 }
1083
1084 name_buf += name_size;
1085 }
1086
1087 free(win_address_buf);
1088
1089 *addresses_ptr = uv_address_buf;
1090 *count_ptr = count;
1091
1092 return 0;
1093 }
1094
1095
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)1096 void uv_free_interface_addresses(uv_interface_address_t* addresses,
1097 int count) {
1098 free(addresses);
1099 }
1100