1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
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:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
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
33 /* clang-format off */
45 * Max title length; the only thing MSDN tells us about the maximum length
46 * of the console title is that it is smaller than 64K. However in practice
47 * it is much smaller, and there is no way to figure out what the exact length
48 * of the title is or can be, at least not on XP. To make it even more
49 * annoying, GetConsoleTitle fails when the buffer to be read into is bigger
50 * than the actual maximum length. So we make a conservative guess here;
51 * just don't put the novel you're writing in the title, unless the plot
52 * survives truncation.
54 #define MAX_TITLE_LENGTH 8192
56 /* The number of nanoseconds in one second. */
57 #define UV__NANOSEC 1000000000
59 /* Max user name length, from iphlpapi.h */
65 /* A RtlGenRandom() by any other name... */
66 extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
68 /* Cached copy of the process title, plus a mutex guarding it. */
69 static char *process_title;
70 static CRITICAL_SECTION process_title_lock;
72 /* Frequency of the high-resolution clock. */
73 static uint64_t hrtime_frequency_ = 0;
77 * One-time initialization code for functionality defined in util.c.
79 void uv__util_init(void) {
80 LARGE_INTEGER perf_frequency;
82 /* Initialize process title access mutex. */
83 InitializeCriticalSection(&process_title_lock);
85 /* Retrieve high-resolution timer frequency
86 * and precompute its reciprocal.
88 if (QueryPerformanceFrequency(&perf_frequency)) {
89 hrtime_frequency_ = perf_frequency.QuadPart;
91 uv_fatal_error(GetLastError(), "QueryPerformanceFrequency");
96 int uv_exepath(char* buffer, size_t* size_ptr) {
97 int utf8_len, utf16_buffer_len, utf16_len;
101 if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
105 if (*size_ptr > 32768) {
106 /* Windows paths can never be longer than this. */
107 utf16_buffer_len = 32768;
109 utf16_buffer_len = (int) *size_ptr;
112 utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
117 /* Get the path as UTF-16. */
118 utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
119 if (utf16_len <= 0) {
120 err = GetLastError();
124 /* utf16_len contains the length, *not* including the terminating null. */
125 utf16_buffer[utf16_len] = L'\0';
127 /* Convert to UTF-8 */
128 utf8_len = WideCharToMultiByte(CP_UTF8,
137 err = GetLastError();
141 uv__free(utf16_buffer);
143 /* utf8_len *does* include the terminating null at this point, but the
144 * returned size shouldn't. */
145 *size_ptr = utf8_len - 1;
149 uv__free(utf16_buffer);
150 return uv_translate_sys_error(err);
154 int uv_cwd(char* buffer, size_t* size) {
159 if (buffer == NULL || size == NULL) {
163 utf16_len = GetCurrentDirectoryW(0, NULL);
164 if (utf16_len == 0) {
165 return uv_translate_sys_error(GetLastError());
167 utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
168 if (utf16_buffer == NULL) {
172 utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
173 if (utf16_len == 0) {
174 uv__free(utf16_buffer);
175 return uv_translate_sys_error(GetLastError());
178 /* utf16_len contains the length, *not* including the terminating null. */
179 utf16_buffer[utf16_len] = L'\0';
181 /* The returned directory should not have a trailing slash, unless it points
182 * at a drive root, like c:\. Remove it if needed. */
183 if (utf16_buffer[utf16_len - 1] == L'\\' &&
184 !(utf16_len == 3 && utf16_buffer[1] == L':')) {
186 utf16_buffer[utf16_len] = L'\0';
189 /* Check how much space we need */
190 r = WideCharToMultiByte(CP_UTF8,
199 uv__free(utf16_buffer);
200 return uv_translate_sys_error(GetLastError());
201 } else if (r > (int) *size) {
202 uv__free(utf16_buffer);
207 /* Convert to UTF-8 */
208 r = WideCharToMultiByte(CP_UTF8,
213 *size > INT_MAX ? INT_MAX : (int) *size,
216 uv__free(utf16_buffer);
219 return uv_translate_sys_error(GetLastError());
227 int uv_chdir(const char* dir) {
229 size_t utf16_len, new_utf16_len;
230 WCHAR drive_letter, env_var[4];
236 utf16_len = MultiByteToWideChar(CP_UTF8,
242 if (utf16_len == 0) {
243 return uv_translate_sys_error(GetLastError());
245 utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
246 if (utf16_buffer == NULL) {
250 if (MultiByteToWideChar(CP_UTF8,
256 uv__free(utf16_buffer);
257 return uv_translate_sys_error(GetLastError());
260 if (!SetCurrentDirectoryW(utf16_buffer)) {
261 uv__free(utf16_buffer);
262 return uv_translate_sys_error(GetLastError());
265 /* Windows stores the drive-local path in an "hidden" environment variable,
266 * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
267 * this, so we'll have to do it. */
268 new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
269 if (new_utf16_len > utf16_len ) {
270 uv__free(utf16_buffer);
271 utf16_buffer = uv__malloc(new_utf16_len * sizeof(WCHAR));
272 if (utf16_buffer == NULL) {
273 /* When updating the environment variable fails, return UV_OK anyway.
274 * We did successfully change current working directory, only updating
275 * hidden env variable failed. */
278 new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer);
280 if (utf16_len == 0) {
281 uv__free(utf16_buffer);
285 /* The returned directory should not have a trailing slash, unless it points
286 * at a drive root, like c:\. Remove it if needed. */
287 if (utf16_buffer[utf16_len - 1] == L'\\' &&
288 !(utf16_len == 3 && utf16_buffer[1] == L':')) {
290 utf16_buffer[utf16_len] = L'\0';
293 if (utf16_len < 2 || utf16_buffer[1] != L':') {
294 /* Doesn't look like a drive letter could be there - probably an UNC path.
295 * TODO: Need to handle win32 namespaces like \\?\C:\ ? */
297 } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
298 drive_letter = utf16_buffer[0];
299 } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
300 /* Convert to uppercase. */
301 drive_letter = utf16_buffer[0] - L'a' + L'A';
307 if (drive_letter != 0) {
308 /* Construct the environment variable name and set it. */
310 env_var[1] = drive_letter;
314 SetEnvironmentVariableW(env_var, utf16_buffer);
317 uv__free(utf16_buffer);
322 void uv_loadavg(double avg[3]) {
323 /* Can't be implemented */
324 avg[0] = avg[1] = avg[2] = 0;
328 uint64_t uv_get_free_memory(void) {
329 MEMORYSTATUSEX memory_status;
330 memory_status.dwLength = sizeof(memory_status);
332 if (!GlobalMemoryStatusEx(&memory_status)) {
336 return (uint64_t)memory_status.ullAvailPhys;
340 uint64_t uv_get_total_memory(void) {
341 MEMORYSTATUSEX memory_status;
342 memory_status.dwLength = sizeof(memory_status);
344 if (!GlobalMemoryStatusEx(&memory_status)) {
348 return (uint64_t)memory_status.ullTotalPhys;
352 uint64_t uv_get_constrained_memory(void) {
353 return 0; /* Memory constraints are unknown. */
357 uv_pid_t uv_os_getpid(void) {
358 return GetCurrentProcessId();
362 uv_pid_t uv_os_getppid(void) {
366 DWORD current_pid = GetCurrentProcessId();
368 pe.dwSize = sizeof(PROCESSENTRY32);
369 handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
371 if (Process32First(handle, &pe)) {
373 if (pe.th32ProcessID == current_pid) {
374 parent_pid = pe.th32ParentProcessID;
377 } while( Process32Next(handle, &pe));
385 char** uv_setup_args(int argc, char** argv) {
390 void uv__process_title_cleanup(void) {
394 int uv_set_process_title(const char* title) {
397 WCHAR* title_w = NULL;
401 /* Find out how big the buffer for the wide-char title must be */
402 length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
404 err = GetLastError();
408 /* Convert to wide-char string */
409 title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
411 uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
414 length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length);
416 err = GetLastError();
420 /* If the title must be truncated insert a \0 terminator there */
421 if (length > MAX_TITLE_LENGTH) {
422 title_w[MAX_TITLE_LENGTH - 1] = L'\0';
425 if (!SetConsoleTitleW(title_w)) {
426 err = GetLastError();
430 EnterCriticalSection(&process_title_lock);
431 uv__free(process_title);
432 process_title = uv__strdup(title);
433 LeaveCriticalSection(&process_title_lock);
439 return uv_translate_sys_error(err);
443 static int uv__get_process_title(void) {
444 WCHAR title_w[MAX_TITLE_LENGTH];
446 if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
450 if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0)
457 int uv_get_process_title(char* buffer, size_t size) {
460 if (buffer == NULL || size == 0)
465 EnterCriticalSection(&process_title_lock);
467 * If the process_title was never read before nor explicitly set,
468 * we must query it with getConsoleTitleW
470 if (!process_title && uv__get_process_title() == -1) {
471 LeaveCriticalSection(&process_title_lock);
472 return uv_translate_sys_error(GetLastError());
475 assert(process_title);
476 len = strlen(process_title) + 1;
479 LeaveCriticalSection(&process_title_lock);
483 memcpy(buffer, process_title, len);
484 LeaveCriticalSection(&process_title_lock);
490 uint64_t uv_hrtime(void) {
492 return uv__hrtime(UV__NANOSEC);
495 uint64_t uv__hrtime(unsigned int scale) {
496 LARGE_INTEGER counter;
500 assert(hrtime_frequency_ != 0);
502 if (!QueryPerformanceCounter(&counter)) {
503 uv_fatal_error(GetLastError(), "QueryPerformanceCounter");
505 assert(counter.QuadPart != 0);
507 /* Because we have no guarantee about the order of magnitude of the
508 * performance counter interval, integer math could cause this computation
509 * to overflow. Therefore we resort to floating point math.
511 scaled_freq = (double) hrtime_frequency_ / scale;
512 result = (double) counter.QuadPart / scaled_freq;
513 return (uint64_t) result;
517 int uv_resident_set_memory(size_t* rss) {
518 HANDLE current_process;
519 PROCESS_MEMORY_COUNTERS pmc;
521 current_process = GetCurrentProcess();
523 if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
524 return uv_translate_sys_error(GetLastError());
527 *rss = pmc.WorkingSetSize;
533 int uv_uptime(double* uptime) {
534 *uptime = GetTickCount64() / 1000.0;
539 unsigned int uv_available_parallelism(void) {
543 /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
544 * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
546 GetSystemInfo(&info);
548 rc = info.dwNumberOfProcessors;
556 int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
557 uv_cpu_info_t* cpu_infos;
558 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
560 SYSTEM_INFO system_info;
565 uv_cpu_info_t* cpu_info;
573 GetSystemInfo(&system_info);
574 cpu_count = system_info.dwNumberOfProcessors;
576 cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
577 if (cpu_infos == NULL) {
578 err = ERROR_OUTOFMEMORY;
582 sppi_size = cpu_count * sizeof(*sppi);
583 sppi = uv__malloc(sppi_size);
585 err = ERROR_OUTOFMEMORY;
589 status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
593 if (!NT_SUCCESS(status)) {
594 err = pRtlNtStatusToDosError(status);
598 assert(result_size == sppi_size);
600 for (i = 0; i < cpu_count; i++) {
604 DWORD cpu_speed_size = sizeof(cpu_speed);
605 WCHAR cpu_brand[256];
606 DWORD cpu_brand_size = sizeof(cpu_brand);
609 len = _snwprintf(key_name,
610 ARRAY_SIZE(key_name),
611 L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
614 assert(len > 0 && len < ARRAY_SIZE(key_name));
616 err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
621 if (err != ERROR_SUCCESS) {
625 err = RegQueryValueExW(processor_key,
631 if (err != ERROR_SUCCESS) {
632 RegCloseKey(processor_key);
636 err = RegQueryValueExW(processor_key,
637 L"ProcessorNameString",
642 RegCloseKey(processor_key);
643 if (err != ERROR_SUCCESS)
646 cpu_info = &cpu_infos[i];
647 cpu_info->speed = cpu_speed;
648 cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
649 cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
650 sppi[i].IdleTime.QuadPart) / 10000;
651 cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
652 cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
653 cpu_info->cpu_times.nice = 0;
655 uv__convert_utf16_to_utf8(cpu_brand,
656 cpu_brand_size / sizeof(WCHAR),
662 *cpu_count_ptr = cpu_count;
663 *cpu_infos_ptr = cpu_infos;
668 if (cpu_infos != NULL) {
669 /* This is safe because the cpu_infos array is zeroed on allocation. */
670 for (i = 0; i < cpu_count; i++)
671 uv__free(cpu_infos[i].model);
677 return uv_translate_sys_error(err);
681 static int is_windows_version_or_greater(DWORD os_major,
683 WORD service_pack_major,
684 WORD service_pack_minor) {
685 OSVERSIONINFOEX osvi;
686 DWORDLONG condition_mask = 0;
687 int op = VER_GREATER_EQUAL;
689 /* Initialize the OSVERSIONINFOEX structure. */
690 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
691 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
692 osvi.dwMajorVersion = os_major;
693 osvi.dwMinorVersion = os_minor;
694 osvi.wServicePackMajor = service_pack_major;
695 osvi.wServicePackMinor = service_pack_minor;
697 /* Initialize the condition mask. */
698 VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
699 VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
700 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
701 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
703 /* Perform the test. */
704 return (int) VerifyVersionInfo(
706 VER_MAJORVERSION | VER_MINORVERSION |
707 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
712 static int address_prefix_match(int family,
713 struct sockaddr* address,
714 struct sockaddr* prefix_address,
716 uint8_t* address_data;
717 uint8_t* prefix_address_data;
720 assert(address->sa_family == family);
721 assert(prefix_address->sa_family == family);
723 if (family == AF_INET6) {
724 address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
725 prefix_address_data =
726 (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
728 address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
729 prefix_address_data =
730 (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
733 for (i = 0; i < prefix_len >> 3; i++) {
734 if (address_data[i] != prefix_address_data[i])
739 return prefix_address_data[i] ==
740 (address_data[i] & (0xff << (8 - prefix_len % 8)));
746 int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
748 IP_ADAPTER_ADDRESSES* win_address_buf;
749 ULONG win_address_buf_size;
750 IP_ADAPTER_ADDRESSES* adapter;
752 uv_interface_address_t* uv_address_buf;
754 size_t uv_address_buf_size;
755 uv_interface_address_t* uv_address;
759 int is_vista_or_greater;
762 *addresses_ptr = NULL;
765 is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
766 if (is_vista_or_greater) {
767 flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
768 GAA_FLAG_SKIP_DNS_SERVER;
770 /* We need at least XP SP1. */
771 if (!is_windows_version_or_greater(5, 1, 1, 0))
774 flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
775 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
779 /* Fetch the size of the adapters reported by windows, and then get the list
781 win_address_buf_size = 0;
782 win_address_buf = NULL;
787 /* If win_address_buf is 0, then GetAdaptersAddresses will fail with.
788 * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in
789 * win_address_buf_size. */
790 r = GetAdaptersAddresses(AF_UNSPEC,
794 &win_address_buf_size);
796 if (r == ERROR_SUCCESS)
799 uv__free(win_address_buf);
802 case ERROR_BUFFER_OVERFLOW:
803 /* This happens when win_address_buf is NULL or too small to hold all
805 win_address_buf = uv__malloc(win_address_buf_size);
806 if (win_address_buf == NULL)
811 case ERROR_NO_DATA: {
812 /* No adapters were found. */
813 uv_address_buf = uv__malloc(1);
814 if (uv_address_buf == NULL)
818 *addresses_ptr = uv_address_buf;
823 case ERROR_ADDRESS_NOT_ASSOCIATED:
826 case ERROR_INVALID_PARAMETER:
828 * "This error is returned for any of the following conditions: the
829 * SizePointer parameter is NULL, the Address parameter is not
830 * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
831 * the parameters requested is greater than ULONG_MAX."
832 * Since the first two conditions are not met, it must be that the
833 * adapter data is too big.
838 /* Other (unspecified) errors can happen, but we don't have any special
839 * meaning for them. */
840 assert(r != ERROR_SUCCESS);
841 return uv_translate_sys_error(r);
845 /* Count the number of enabled interfaces and compute how much space is
846 * needed to store their info. */
848 uv_address_buf_size = 0;
850 for (adapter = win_address_buf;
852 adapter = adapter->Next) {
853 IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
856 /* Interfaces that are not 'up' should not be reported. Also skip
857 * interfaces that have no associated unicast address, as to avoid
858 * allocating space for the name for this interface. */
859 if (adapter->OperStatus != IfOperStatusUp ||
860 adapter->FirstUnicastAddress == NULL)
863 /* Compute the size of the interface name. */
864 name_size = WideCharToMultiByte(CP_UTF8,
866 adapter->FriendlyName,
872 if (name_size <= 0) {
873 uv__free(win_address_buf);
874 return uv_translate_sys_error(GetLastError());
876 uv_address_buf_size += name_size;
878 /* Count the number of addresses associated with this interface, and
879 * compute the size. */
880 for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
881 adapter->FirstUnicastAddress;
882 unicast_address != NULL;
883 unicast_address = unicast_address->Next) {
885 uv_address_buf_size += sizeof(uv_interface_address_t);
889 /* Allocate space to store interface data plus adapter names. */
890 uv_address_buf = uv__malloc(uv_address_buf_size);
891 if (uv_address_buf == NULL) {
892 uv__free(win_address_buf);
896 /* Compute the start of the uv_interface_address_t array, and the place in
897 * the buffer where the interface names will be stored. */
898 uv_address = uv_address_buf;
899 name_buf = (char*) (uv_address_buf + count);
901 /* Fill out the output buffer. */
902 for (adapter = win_address_buf;
904 adapter = adapter->Next) {
905 IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
907 size_t max_name_size;
909 if (adapter->OperStatus != IfOperStatusUp ||
910 adapter->FirstUnicastAddress == NULL)
913 /* Convert the interface name to UTF8. */
914 max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
915 if (max_name_size > (size_t) INT_MAX)
916 max_name_size = INT_MAX;
917 name_size = WideCharToMultiByte(CP_UTF8,
919 adapter->FriendlyName,
925 if (name_size <= 0) {
926 uv__free(win_address_buf);
927 uv__free(uv_address_buf);
928 return uv_translate_sys_error(GetLastError());
931 /* Add an uv_interface_address_t element for every unicast address. */
932 for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
933 adapter->FirstUnicastAddress;
934 unicast_address != NULL;
935 unicast_address = unicast_address->Next) {
939 sa = unicast_address->Address.lpSockaddr;
941 /* XP has no OnLinkPrefixLength field. */
942 if (is_vista_or_greater) {
944 ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
946 /* Prior to Windows Vista the FirstPrefix pointed to the list with
947 * single prefix for each IP address assigned to the adapter.
948 * Order of FirstPrefix does not match order of FirstUnicastAddress,
949 * so we need to find corresponding prefix.
951 IP_ADAPTER_PREFIX* prefix;
954 for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
955 /* We want the longest matching prefix. */
956 if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
957 prefix->PrefixLength <= prefix_len)
960 if (address_prefix_match(sa->sa_family, sa,
961 prefix->Address.lpSockaddr, prefix->PrefixLength)) {
962 prefix_len = prefix->PrefixLength;
966 /* If there is no matching prefix information, return a single-host
967 * subnet mask (e.g. 255.255.255.255 for IPv4).
970 prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
973 memset(uv_address, 0, sizeof *uv_address);
975 uv_address->name = name_buf;
977 if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
978 memcpy(uv_address->phys_addr,
979 adapter->PhysicalAddress,
980 sizeof(uv_address->phys_addr));
983 uv_address->is_internal =
984 (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
986 if (sa->sa_family == AF_INET6) {
987 uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
989 uv_address->netmask.netmask6.sin6_family = AF_INET6;
990 memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
991 /* This check ensures that we don't write past the size of the data. */
992 if (prefix_len % 8) {
993 uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
994 0xff << (8 - prefix_len % 8);
998 uv_address->address.address4 = *((struct sockaddr_in *) sa);
1000 uv_address->netmask.netmask4.sin_family = AF_INET;
1001 uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
1002 htonl(0xffffffff << (32 - prefix_len)) : 0;
1008 name_buf += name_size;
1011 uv__free(win_address_buf);
1013 *addresses_ptr = uv_address_buf;
1020 void uv_free_interface_addresses(uv_interface_address_t* addresses,
1022 uv__free(addresses);
1026 int uv_getrusage(uv_rusage_t *uv_rusage) {
1027 FILETIME createTime, exitTime, kernelTime, userTime;
1028 SYSTEMTIME kernelSystemTime, userSystemTime;
1029 PROCESS_MEMORY_COUNTERS memCounters;
1030 IO_COUNTERS ioCounters;
1033 ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
1035 return uv_translate_sys_error(GetLastError());
1038 ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
1040 return uv_translate_sys_error(GetLastError());
1043 ret = FileTimeToSystemTime(&userTime, &userSystemTime);
1045 return uv_translate_sys_error(GetLastError());
1048 ret = GetProcessMemoryInfo(GetCurrentProcess(),
1050 sizeof(memCounters));
1052 return uv_translate_sys_error(GetLastError());
1055 ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
1057 return uv_translate_sys_error(GetLastError());
1060 memset(uv_rusage, 0, sizeof(*uv_rusage));
1062 uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
1063 userSystemTime.wMinute * 60 +
1064 userSystemTime.wSecond;
1065 uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
1067 uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
1068 kernelSystemTime.wMinute * 60 +
1069 kernelSystemTime.wSecond;
1070 uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
1072 uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
1073 uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
1075 uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
1076 uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
1082 int uv_os_homedir(char* buffer, size_t* size) {
1087 /* Check if the USERPROFILE environment variable is set first. The task of
1088 performing input validation on buffer and size is taken care of by
1090 r = uv_os_getenv("USERPROFILE", buffer, size);
1092 /* Don't return an error if USERPROFILE was not found. */
1096 /* USERPROFILE is not set, so call uv__getpwuid_r() */
1097 r = uv__getpwuid_r(&pwd);
1103 len = strlen(pwd.homedir);
1107 uv_os_free_passwd(&pwd);
1111 memcpy(buffer, pwd.homedir, len + 1);
1113 uv_os_free_passwd(&pwd);
1119 int uv_os_tmpdir(char* buffer, size_t* size) {
1124 if (buffer == NULL || size == NULL || *size == 0)
1128 len = GetTempPathW(0, NULL);
1130 return uv_translate_sys_error(GetLastError());
1132 /* Include space for terminating null char. */
1134 path = uv__malloc(len * sizeof(wchar_t));
1138 len = GetTempPathW(len, path);
1142 return uv_translate_sys_error(GetLastError());
1145 /* The returned directory should not have a trailing slash, unless it points
1146 * at a drive root, like c:\. Remove it if needed. */
1147 if (path[len - 1] == L'\\' &&
1148 !(len == 3 && path[1] == L':')) {
1153 /* Check how much space we need */
1154 bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
1158 return uv_translate_sys_error(GetLastError());
1159 } else if (bufsize > *size) {
1165 /* Convert to UTF-8 */
1166 bufsize = WideCharToMultiByte(CP_UTF8,
1177 return uv_translate_sys_error(GetLastError());
1179 *size = bufsize - 1;
1184 void uv_os_free_passwd(uv_passwd_t* pwd) {
1188 uv__free(pwd->username);
1189 uv__free(pwd->homedir);
1190 pwd->username = NULL;
1191 pwd->homedir = NULL;
1196 * Converts a UTF-16 string into a UTF-8 one. The resulting string is
1199 * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
1202 int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) {
1208 /* Check how much space we need */
1209 bufsize = WideCharToMultiByte(CP_UTF8,
1219 return uv_translate_sys_error(GetLastError());
1221 /* Allocate the destination buffer adding an extra byte for the terminating
1222 * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
1223 * we do it ourselves always, just in case. */
1224 *utf8 = uv__malloc(bufsize + 1);
1229 /* Convert to UTF-8 */
1230 bufsize = WideCharToMultiByte(CP_UTF8,
1242 return uv_translate_sys_error(GetLastError());
1245 (*utf8)[bufsize] = '\0';
1251 * Converts a UTF-8 string into a UTF-16 one. The resulting string is
1254 * If utf8 is null terminated, utf8len can be set to -1, otherwise it must
1257 int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
1263 /* Check how much space we need */
1264 bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
1267 return uv_translate_sys_error(GetLastError());
1269 /* Allocate the destination buffer adding an extra byte for the terminating
1270 * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
1271 * we do it ourselves always, just in case. */
1272 *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1));
1277 /* Convert to UTF-16 */
1278 bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
1283 return uv_translate_sys_error(GetLastError());
1286 (*utf16)[bufsize] = L'\0';
1291 int uv__getpwuid_r(uv_passwd_t* pwd) {
1293 wchar_t username[UNLEN + 1];
1301 /* Get the home directory using GetUserProfileDirectoryW() */
1302 if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
1303 return uv_translate_sys_error(GetLastError());
1306 GetUserProfileDirectoryW(token, NULL, &bufsize);
1307 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1310 return uv_translate_sys_error(r);
1313 path = uv__malloc(bufsize * sizeof(wchar_t));
1319 if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
1323 return uv_translate_sys_error(r);
1328 /* Get the username using GetUserNameW() */
1329 bufsize = ARRAY_SIZE(username);
1330 if (!GetUserNameW(username, &bufsize)) {
1334 /* This should not be possible */
1335 if (r == ERROR_INSUFFICIENT_BUFFER)
1338 return uv_translate_sys_error(r);
1341 pwd->homedir = NULL;
1342 r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
1348 pwd->username = NULL;
1349 r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
1352 uv__free(pwd->homedir);
1364 int uv_os_get_passwd(uv_passwd_t* pwd) {
1365 return uv__getpwuid_r(pwd);
1369 int uv_os_environ(uv_env_item_t** envitems, int* count) {
1373 uv_env_item_t* envitem;
1378 env = GetEnvironmentStringsW();
1382 for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
1384 *envitems = uv__calloc(i, sizeof(**envitems));
1385 if (*envitems == NULL) {
1386 FreeEnvironmentStringsW(env);
1393 while (*penv != L'\0' && cnt < i) {
1397 if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
1400 /* Using buf + 1 here because we know that `buf` has length at least 1,
1401 * and some special environment variables on Windows start with a = sign. */
1402 ptr = strchr(buf + 1, '=');
1410 envitem = &(*envitems)[cnt];
1411 envitem->name = buf;
1412 envitem->value = ptr + 1;
1417 penv += wcslen(penv) + 1;
1420 FreeEnvironmentStringsW(env);
1426 FreeEnvironmentStringsW(env);
1428 for (i = 0; i < cnt; i++) {
1429 envitem = &(*envitems)[cnt];
1430 uv__free(envitem->name);
1432 uv__free(*envitems);
1440 int uv_os_getenv(const char* name, char* buffer, size_t* size) {
1441 wchar_t fastvar[512];
1449 if (name == NULL || buffer == NULL || size == NULL || *size == 0)
1452 r = uv__convert_utf8_to_utf16(name, -1, &name_w);
1458 varlen = ARRAY_SIZE(fastvar);
1461 SetLastError(ERROR_SUCCESS);
1462 len = GetEnvironmentVariableW(name_w, var, varlen);
1467 /* Try repeatedly because we might have been preempted by another thread
1468 * modifying the environment variable just as we're trying to read it.
1474 var = uv__malloc(varlen * sizeof(*var));
1487 if (r != ERROR_SUCCESS) {
1488 r = uv_translate_sys_error(r);
1493 /* Check how much space we need */
1494 bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
1497 r = uv_translate_sys_error(GetLastError());
1499 } else if (bufsize > *size) {
1505 /* Convert to UTF-8 */
1506 bufsize = WideCharToMultiByte(CP_UTF8,
1516 r = uv_translate_sys_error(GetLastError());
1520 *size = bufsize - 1;
1535 int uv_os_setenv(const char* name, const char* value) {
1540 if (name == NULL || value == NULL)
1543 r = uv__convert_utf8_to_utf16(name, -1, &name_w);
1548 r = uv__convert_utf8_to_utf16(value, -1, &value_w);
1555 r = SetEnvironmentVariableW(name_w, value_w);
1560 return uv_translate_sys_error(GetLastError());
1566 int uv_os_unsetenv(const char* name) {
1573 r = uv__convert_utf8_to_utf16(name, -1, &name_w);
1578 r = SetEnvironmentVariableW(name_w, NULL);
1582 return uv_translate_sys_error(GetLastError());
1588 int uv_os_gethostname(char* buffer, size_t* size) {
1589 WCHAR buf[UV_MAXHOSTNAMESIZE];
1594 if (buffer == NULL || size == NULL || *size == 0)
1597 uv__once_init(); /* Initialize winsock */
1599 if (pGetHostNameW == NULL)
1602 if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
1603 return uv_translate_sys_error(WSAGetLastError());
1605 convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
1607 if (convert_result != 0)
1608 return convert_result;
1610 len = strlen(utf8_str);
1617 memcpy(buffer, utf8_str, len + 1);
1624 static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
1628 *handle = GetCurrentProcess();
1630 *handle = OpenProcess(access, FALSE, pid);
1632 if (*handle == NULL) {
1635 if (r == ERROR_INVALID_PARAMETER)
1638 return uv_translate_sys_error(r);
1645 int uv_os_getpriority(uv_pid_t pid, int* priority) {
1649 if (priority == NULL)
1652 r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
1657 r = GetPriorityClass(handle);
1660 r = uv_translate_sys_error(GetLastError());
1662 /* Map Windows priority classes to Unix nice values. */
1663 if (r == REALTIME_PRIORITY_CLASS)
1664 *priority = UV_PRIORITY_HIGHEST;
1665 else if (r == HIGH_PRIORITY_CLASS)
1666 *priority = UV_PRIORITY_HIGH;
1667 else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
1668 *priority = UV_PRIORITY_ABOVE_NORMAL;
1669 else if (r == NORMAL_PRIORITY_CLASS)
1670 *priority = UV_PRIORITY_NORMAL;
1671 else if (r == BELOW_NORMAL_PRIORITY_CLASS)
1672 *priority = UV_PRIORITY_BELOW_NORMAL;
1673 else /* IDLE_PRIORITY_CLASS */
1674 *priority = UV_PRIORITY_LOW;
1679 CloseHandle(handle);
1684 int uv_os_setpriority(uv_pid_t pid, int priority) {
1689 /* Map Unix nice values to Windows priority classes. */
1690 if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
1692 else if (priority < UV_PRIORITY_HIGH)
1693 priority_class = REALTIME_PRIORITY_CLASS;
1694 else if (priority < UV_PRIORITY_ABOVE_NORMAL)
1695 priority_class = HIGH_PRIORITY_CLASS;
1696 else if (priority < UV_PRIORITY_NORMAL)
1697 priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
1698 else if (priority < UV_PRIORITY_BELOW_NORMAL)
1699 priority_class = NORMAL_PRIORITY_CLASS;
1700 else if (priority < UV_PRIORITY_LOW)
1701 priority_class = BELOW_NORMAL_PRIORITY_CLASS;
1703 priority_class = IDLE_PRIORITY_CLASS;
1705 r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
1710 if (SetPriorityClass(handle, priority_class) == 0)
1711 r = uv_translate_sys_error(GetLastError());
1713 CloseHandle(handle);
1718 int uv_os_uname(uv_utsname_t* buffer) {
1719 /* Implementation loosely based on
1720 https://github.com/gagern/gnulib/blob/master/lib/uname.c */
1721 OSVERSIONINFOW os_info;
1722 SYSTEM_INFO system_info;
1724 WCHAR product_name_w[256];
1725 DWORD product_name_w_size;
1727 int processor_level;
1734 os_info.dwOSVersionInfoSize = sizeof(os_info);
1735 os_info.szCSDVersion[0] = L'\0';
1737 /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
1738 if RtlGetVersion() is not available. */
1739 if (pRtlGetVersion) {
1740 pRtlGetVersion(&os_info);
1742 /* Silence GetVersionEx() deprecation warning. */
1744 #pragma warning(suppress : 4996)
1746 if (GetVersionExW(&os_info) == 0) {
1747 r = uv_translate_sys_error(GetLastError());
1752 /* Populate the version field. */
1754 r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1755 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
1760 if (r == ERROR_SUCCESS) {
1761 product_name_w_size = sizeof(product_name_w);
1762 r = RegGetValueW(registry_key,
1767 (PVOID) product_name_w,
1768 &product_name_w_size);
1769 RegCloseKey(registry_key);
1771 if (r == ERROR_SUCCESS) {
1772 version_size = WideCharToMultiByte(CP_UTF8,
1777 sizeof(buffer->version),
1780 if (version_size == 0) {
1781 r = uv_translate_sys_error(GetLastError());
1787 /* Append service pack information to the version if present. */
1788 if (os_info.szCSDVersion[0] != L'\0') {
1789 if (version_size > 0)
1790 buffer->version[version_size - 1] = ' ';
1792 if (WideCharToMultiByte(CP_UTF8,
1794 os_info.szCSDVersion,
1796 buffer->version + version_size,
1797 sizeof(buffer->version) - version_size,
1800 r = uv_translate_sys_error(GetLastError());
1805 /* Populate the sysname field. */
1807 r = snprintf(buffer->sysname,
1808 sizeof(buffer->sysname),
1810 (unsigned int) os_info.dwMajorVersion,
1811 (unsigned int) os_info.dwMinorVersion);
1812 assert((size_t)r < sizeof(buffer->sysname));
1814 uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
1817 /* Populate the release field. */
1818 r = snprintf(buffer->release,
1819 sizeof(buffer->release),
1821 (unsigned int) os_info.dwMajorVersion,
1822 (unsigned int) os_info.dwMinorVersion,
1823 (unsigned int) os_info.dwBuildNumber);
1824 assert((size_t)r < sizeof(buffer->release));
1826 /* Populate the machine field. */
1827 GetSystemInfo(&system_info);
1829 switch (system_info.wProcessorArchitecture) {
1830 case PROCESSOR_ARCHITECTURE_AMD64:
1831 uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
1833 case PROCESSOR_ARCHITECTURE_IA64:
1834 uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
1836 case PROCESSOR_ARCHITECTURE_INTEL:
1837 uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
1839 if (system_info.wProcessorLevel > 3) {
1840 processor_level = system_info.wProcessorLevel < 6 ?
1841 system_info.wProcessorLevel : 6;
1842 buffer->machine[1] = '0' + processor_level;
1846 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1847 uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
1849 case PROCESSOR_ARCHITECTURE_MIPS:
1850 uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
1852 case PROCESSOR_ARCHITECTURE_ALPHA:
1853 case PROCESSOR_ARCHITECTURE_ALPHA64:
1854 uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
1856 case PROCESSOR_ARCHITECTURE_PPC:
1857 uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
1859 case PROCESSOR_ARCHITECTURE_SHX:
1860 uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
1862 case PROCESSOR_ARCHITECTURE_ARM:
1863 uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
1866 uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
1873 buffer->sysname[0] = '\0';
1874 buffer->release[0] = '\0';
1875 buffer->version[0] = '\0';
1876 buffer->machine[0] = '\0';
1880 int uv_gettimeofday(uv_timeval64_t* tv) {
1881 /* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */
1882 const uint64_t epoch = (uint64_t) 116444736000000000ULL;
1884 ULARGE_INTEGER ularge;
1889 GetSystemTimeAsFileTime(&file_time);
1890 ularge.LowPart = file_time.dwLowDateTime;
1891 ularge.HighPart = file_time.dwHighDateTime;
1892 tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L);
1893 tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
1897 int uv__random_rtlgenrandom(void* buf, size_t buflen) {
1901 if (SystemFunction036(buf, buflen) == FALSE)
1907 void uv_sleep(unsigned int msec) {