@@ -36,6 +36,7 @@
#include <psapi.h>
#include <tlhelp32.h>
#include <windows.h>
#include <userenv.h>


/*
@@ -72,7 +73,7 @@ void uv__util_init() {
InitializeCriticalSection(&process_title_lock);

/* Retrieve high-resolution timer frequency
* and precompute its reciprocal.
* and precompute its reciprocal.
*/
if (QueryPerformanceFrequency(&perf_frequency)) {
hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
@@ -122,7 +123,7 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
utf16_buffer_len = (int) *size_ptr;
}

utf16_buffer = (WCHAR*) malloc(sizeof(WCHAR) * utf16_buffer_len);
utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
if (!utf16_buffer) {
return UV_ENOMEM;
}
@@ -151,15 +152,15 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
goto error;
}

free(utf16_buffer);
uv__free(utf16_buffer);

/* utf8_len *does* include the terminating null at this point, but the */
/* returned size shouldn't. */
*size_ptr = utf8_len - 1;
return 0;

error:
free(utf16_buffer);
uv__free(utf16_buffer);
return uv_translate_sys_error(err);
}

@@ -378,9 +379,9 @@ int uv_set_process_title(const char* title) {
}

/* Convert to wide-char string */
title_w = (WCHAR*)malloc(sizeof(WCHAR) * length);
title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
if (!title_w) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}

length = uv_utf8_to_utf16(title, title_w, length);
@@ -400,14 +401,14 @@ int uv_set_process_title(const char* title) {
}

EnterCriticalSection(&process_title_lock);
free(process_title);
process_title = strdup(title);
uv__free(process_title);
process_title = uv__strdup(title);
LeaveCriticalSection(&process_title_lock);

err = 0;

done:
free(title_w);
uv__free(title_w);
return uv_translate_sys_error(err);
}

@@ -427,14 +428,14 @@ static int uv__get_process_title() {
}

assert(!process_title);
process_title = (char*)malloc(length);
process_title = (char*)uv__malloc(length);
if (!process_title) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}

/* Do utf16 -> utf8 conversion here */
if (!uv_utf16_to_utf8(title_w, -1, process_title, length)) {
free(process_title);
uv__free(process_title);
return -1;
}

@@ -540,9 +541,9 @@ int uv_uptime(double* uptime) {
goto internalError;
}

free(malloced_buffer);
uv__free(malloced_buffer);

buffer = malloced_buffer = (BYTE*) malloc(buffer_size);
buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
if (malloced_buffer == NULL) {
*uptime = 0;
return UV_ENOMEM;
@@ -584,7 +585,7 @@ int uv_uptime(double* uptime) {
uint64_t value = *((uint64_t*) address);
*uptime = (double) (object_type->PerfTime.QuadPart - value) /
(double) object_type->PerfFreq.QuadPart;
free(malloced_buffer);
uv__free(malloced_buffer);
return 0;
}
}
@@ -594,12 +595,12 @@ int uv_uptime(double* uptime) {
}

/* If we get here, the uptime value was not found. */
free(malloced_buffer);
uv__free(malloced_buffer);
*uptime = 0;
return UV_ENOSYS;

internalError:
free(malloced_buffer);
uv__free(malloced_buffer);
*uptime = 0;
return UV_EIO;
}
@@ -625,14 +626,14 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
GetSystemInfo(&system_info);
cpu_count = system_info.dwNumberOfProcessors;

cpu_infos = calloc(cpu_count, sizeof *cpu_infos);
cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
if (cpu_infos == NULL) {
err = ERROR_OUTOFMEMORY;
goto error;
}

sppi_size = cpu_count * sizeof(*sppi);
sppi = malloc(sppi_size);
sppi = uv__malloc(sppi_size);
if (sppi == NULL) {
err = ERROR_OUTOFMEMORY;
goto error;
@@ -725,7 +726,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
assert(len > 0);

/* Allocate 1 extra byte for the null terminator. */
cpu_info->model = malloc(len + 1);
cpu_info->model = uv__malloc(len + 1);
if (cpu_info->model == NULL) {
err = ERROR_OUTOFMEMORY;
goto error;
@@ -747,7 +748,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
cpu_info->model[len] = '\0';
}

free(sppi);
uv__free(sppi);

*cpu_count_ptr = cpu_count;
*cpu_infos_ptr = cpu_infos;
@@ -757,10 +758,10 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
error:
/* This is safe because the cpu_infos array is zeroed on allocation. */
for (i = 0; i < cpu_count; i++)
free(cpu_infos[i].model);
uv__free(cpu_infos[i].model);

free(cpu_infos);
free(sppi);
uv__free(cpu_infos);
uv__free(sppi);

return uv_translate_sys_error(err);
}
@@ -770,10 +771,10 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
int i;

for (i = 0; i < count; i++) {
free(cpu_infos[i].model);
uv__free(cpu_infos[i].model);
}

free(cpu_infos);
uv__free(cpu_infos);
}


@@ -801,8 +802,8 @@ static int is_windows_version_or_greater(DWORD os_major,

/* Perform the test. */
return (int) VerifyVersionInfo(
&osvi,
VER_MAJORVERSION | VER_MINORVERSION |
&osvi,
VER_MAJORVERSION | VER_MINORVERSION |
VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
condition_mask);
}
@@ -870,7 +871,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
}


/* Fetch the size of the adapters reported by windows, and then get the */
/* list itself. */
@@ -892,21 +893,21 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
if (r == ERROR_SUCCESS)
break;

free(win_address_buf);
uv__free(win_address_buf);

switch (r) {
case ERROR_BUFFER_OVERFLOW:
/* This happens when win_address_buf is NULL or too small to hold */
/* all adapters. */
win_address_buf = malloc(win_address_buf_size);
win_address_buf = uv__malloc(win_address_buf_size);
if (win_address_buf == NULL)
return UV_ENOMEM;

continue;

case ERROR_NO_DATA: {
/* No adapters were found. */
uv_address_buf = malloc(1);
uv_address_buf = uv__malloc(1);
if (uv_address_buf == NULL)
return UV_ENOMEM;

@@ -966,7 +967,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
NULL,
FALSE);
if (name_size <= 0) {
free(win_address_buf);
uv__free(win_address_buf);
return uv_translate_sys_error(GetLastError());
}
uv_address_buf_size += name_size;
@@ -983,9 +984,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
}

/* Allocate space to store interface data plus adapter names. */
uv_address_buf = malloc(uv_address_buf_size);
uv_address_buf = uv__malloc(uv_address_buf_size);
if (uv_address_buf == NULL) {
free(win_address_buf);
uv__free(win_address_buf);
return UV_ENOMEM;
}

@@ -1019,8 +1020,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
NULL,
FALSE);
if (name_size <= 0) {
free(win_address_buf);
free(uv_address_buf);
uv__free(win_address_buf);
uv__free(uv_address_buf);
return uv_translate_sys_error(GetLastError());
}

@@ -1053,14 +1054,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
prefix->PrefixLength <= prefix_len)
continue;

if (address_prefix_match(sa->sa_family, sa,
if (address_prefix_match(sa->sa_family, sa,
prefix->Address.lpSockaddr, prefix->PrefixLength)) {
prefix_len = prefix->PrefixLength;
}
}

/* If there is no matching prefix information, return a single-host
* subnet mask (e.g. 255.255.255.255 for IPv4).
* subnet mask (e.g. 255.255.255.255 for IPv4).
*/
if (!prefix_len)
prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
@@ -1104,7 +1105,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
name_buf += name_size;
}

free(win_address_buf);
uv__free(win_address_buf);

*addresses_ptr = uv_address_buf;
*count_ptr = count;
@@ -1115,7 +1116,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,

void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
free(addresses);
uv__free(addresses);
}


@@ -1153,3 +1154,67 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {

return 0;
}


int uv_os_homedir(char* buffer, size_t* size) {
HANDLE token;
wchar_t path[MAX_PATH];
DWORD bufsize;
size_t len;
int r;

if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;

/* Check if the USERPROFILE environment variable is set first */
len = GetEnvironmentVariableW(L"USERPROFILE", path, MAX_PATH);

if (len == 0) {
r = GetLastError();
/* Don't return an error if USERPROFILE was not found */
if (r != ERROR_ENVVAR_NOT_FOUND)
return uv_translate_sys_error(r);
} else if (len > MAX_PATH) {
/* This should not be possible */
return UV_EIO;
} else {
goto convert_buffer;
}

/* USERPROFILE is not set, so call GetUserProfileDirectoryW() */
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
return uv_translate_sys_error(GetLastError());

bufsize = MAX_PATH;
if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
r = GetLastError();
CloseHandle(token);

/* This should not be possible */
if (r == ERROR_INSUFFICIENT_BUFFER)
return UV_EIO;

return uv_translate_sys_error(r);
}

CloseHandle(token);

convert_buffer:

/* Check how much space we need */
bufsize = uv_utf16_to_utf8(path, -1, NULL, 0);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
*size = bufsize - 1;
return UV_ENOBUFS;
}

/* Convert to UTF-8 */
bufsize = uv_utf16_to_utf8(path, -1, buffer, *size);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());

*size = bufsize - 1;
return 0;
}
@@ -184,7 +184,8 @@ enum test_status {
# define inline __inline
# endif

/* Emulate snprintf() on Windows, _snprintf() doesn't zero-terminate the buffer
# if defined(_MSC_VER) && _MSC_VER < 1900
/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
* on overflow...
*/
inline int snprintf(char* buf, size_t len, const char* fmt, ...) {
@@ -205,6 +206,7 @@ inline int snprintf(char* buf, size_t len, const char* fmt, ...) {

return n;
}
# endif

#endif

@@ -0,0 +1,49 @@
#include "uv.h"
#include "task.h"
#include <string.h>

#define PATHMAX 1024
#define SMALLPATH 1

TEST_IMPL(homedir) {
char homedir[PATHMAX];
size_t len;
char last;
int r;

/* Test the normal case */
len = sizeof homedir;
homedir[0] = '\0';
ASSERT(strlen(homedir) == 0);
r = uv_os_homedir(homedir, &len);
ASSERT(r == 0);
ASSERT(strlen(homedir) == len);
ASSERT(len > 0);
ASSERT(homedir[len] == '\0');

if (len > 1) {
last = homedir[len - 1];
#ifdef _WIN32
ASSERT(last != '\\');
#else
ASSERT(last != '/');
#endif
}

/* Test the case where the buffer is too small */
len = SMALLPATH;
r = uv_os_homedir(homedir, &len);
ASSERT(r == UV_ENOBUFS);
ASSERT(len > SMALLPATH);

/* Test invalid inputs */
r = uv_os_homedir(NULL, &len);
ASSERT(r == UV_EINVAL);
r = uv_os_homedir(homedir, NULL);
ASSERT(r == UV_EINVAL);
len = 0;
r = uv_os_homedir(homedir, &len);
ASSERT(r == UV_EINVAL);

return 0;
}
@@ -117,6 +117,7 @@ TEST_DECLARE (pipe_bind_error_inval)
TEST_DECLARE (pipe_listen_without_bind)
TEST_DECLARE (pipe_connect_bad_name)
TEST_DECLARE (pipe_connect_to_file)
TEST_DECLARE (pipe_connect_on_prepare)
TEST_DECLARE (pipe_getsockname)
TEST_DECLARE (pipe_getsockname_abstract)
TEST_DECLARE (pipe_getsockname_blocking)
@@ -182,6 +183,7 @@ TEST_DECLARE (process_title)
TEST_DECLARE (cwd_and_chdir)
TEST_DECLARE (get_memory)
TEST_DECLARE (handle_fileno)
TEST_DECLARE (homedir)
TEST_DECLARE (hrtime)
TEST_DECLARE (getaddrinfo_fail)
TEST_DECLARE (getaddrinfo_fail_sync)
@@ -344,6 +346,7 @@ TASK_LIST_START

TEST_ENTRY (pipe_connect_bad_name)
TEST_ENTRY (pipe_connect_to_file)
TEST_ENTRY (pipe_connect_on_prepare)

TEST_ENTRY (pipe_server_close)
#ifndef _WIN32
@@ -540,6 +543,8 @@ TASK_LIST_START

TEST_ENTRY (handle_fileno)

TEST_ENTRY (homedir)

TEST_ENTRY (hrtime)

TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000)
@@ -0,0 +1,83 @@
/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

#include "uv.h"
#include "task.h"
#include <stdio.h>
#include <stdlib.h>


#ifdef _WIN32
# define BAD_PIPENAME "bad-pipe"
#else
# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
#endif


static int close_cb_called = 0;
static int connect_cb_called = 0;

static uv_pipe_t pipe_handle;
static uv_prepare_t prepare_handle;
static uv_connect_t conn_req;


static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
close_cb_called++;
}


static void connect_cb(uv_connect_t* connect_req, int status) {
ASSERT(status == UV_ENOENT);
connect_cb_called++;
uv_close((uv_handle_t*)&prepare_handle, close_cb);
uv_close((uv_handle_t*)&pipe_handle, close_cb);
}


static void prepare_cb(uv_prepare_t* handle) {
ASSERT(handle == &prepare_handle);
uv_pipe_connect(&conn_req, &pipe_handle, BAD_PIPENAME, connect_cb);
}


TEST_IMPL(pipe_connect_on_prepare) {
int r;

r = uv_pipe_init(uv_default_loop(), &pipe_handle, 0);
ASSERT(r == 0);

r = uv_prepare_init(uv_default_loop(), &prepare_handle);
ASSERT(r == 0);
r = uv_prepare_start(&prepare_handle, prepare_cb);
ASSERT(r == 0);

r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);

ASSERT(close_cb_called == 2);
ASSERT(connect_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}
@@ -112,11 +112,13 @@ TEST_IMPL(platform_output) {

if (interfaces[i].netmask.netmask4.sin_family == AF_INET) {
uv_ip4_name(&interfaces[i].netmask.netmask4, buffer, sizeof(buffer));
printf(" netmask: %s\n", buffer);
} else if (interfaces[i].netmask.netmask4.sin_family == AF_INET6) {
uv_ip6_name(&interfaces[i].netmask.netmask6, buffer, sizeof(buffer));
printf(" netmask: %s\n", buffer);
} else {
printf(" netmask: none\n");
}

printf(" netmask: %s\n", buffer);
}
uv_free_interface_addresses(interfaces, count);

@@ -116,6 +116,7 @@
'-liphlpapi',
'-lpsapi',
'-lshell32',
'-luserenv',
'-lws2_32'
],
},
@@ -310,6 +311,7 @@
'test/test-getnameinfo.c',
'test/test-getsockname.c',
'test/test-handle-fileno.c',
'test/test-homedir.c',
'test/test-hrtime.c',
'test/test-idle.c',
'test/test-ip6-addr.c',
@@ -330,6 +332,7 @@
'test/test-ping-pong.c',
'test/test-pipe-bind-error.c',
'test/test-pipe-connect-error.c',
'test/test-pipe-connect-prepare.c',
'test/test-pipe-getsockname.c',
'test/test-pipe-sendmsg.c',
'test/test-pipe-server-close.c',
@@ -44,6 +44,14 @@ goto next-arg
if defined WindowsSDKDir goto select-target
if defined VCINSTALLDIR goto select-target

@rem Look for Visual Studio 2015
if not defined VS140COMNTOOLS goto vc-set-2013
if not exist "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2013
call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
set GYP_MSVS_VERSION=2015
goto select-target

:vc-set-2013
@rem Look for Visual Studio 2013
if not defined VS120COMNTOOLS goto vc-set-2012
if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012