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