@@ -1347,7 +1347,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
}

/* Request queued by the kernel. */
req->queued_bytes = uv__count_bufs(bufs, nbufs);
req->queued_bytes = bufs[0].len;
handle->write_queue_size += req->queued_bytes;
} else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
/* Using overlapped IO, but wait for completion before returning */
@@ -1372,12 +1372,13 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
/* Request completed immediately. */
req->queued_bytes = 0;
} else {
assert(ipc_header_req != NULL);
/* Request queued by the kernel. */
if (WaitForSingleObject(ipc_header_req->overlapped.hEvent, INFINITE) !=
req->queued_bytes = bufs[0].len;
handle->write_queue_size += req->queued_bytes;
if (WaitForSingleObject(req->overlapped.hEvent, INFINITE) !=
WAIT_OBJECT_0) {
err = GetLastError();
CloseHandle(ipc_header_req->overlapped.hEvent);
CloseHandle(req->overlapped.hEvent);
return uv_translate_sys_error(err);
}
}
@@ -1386,7 +1387,6 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
REGISTER_HANDLE_REQ(loop, handle, req);
handle->reqs_pending++;
handle->write_reqs_pending++;
POST_COMPLETION_FOR_REQ(loop, req);
return 0;
} else {
result = WriteFile(handle->handle,
@@ -1404,7 +1404,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
req->queued_bytes = 0;
} else {
/* Request queued by the kernel. */
req->queued_bytes = uv__count_bufs(bufs, nbufs);
req->queued_bytes = bufs[0].len;
handle->write_queue_size += req->queued_bytes;
}

@@ -1848,7 +1848,7 @@ static void eof_timer_cb(uv_timer_t* timer) {


static void eof_timer_destroy(uv_pipe_t* pipe) {
assert(pipe->flags && UV_HANDLE_CONNECTION);
assert(pipe->flags & UV_HANDLE_CONNECTION);

if (pipe->eof_timer) {
uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb);
@@ -1910,7 +1910,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
}


int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) {
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
FILE_NAME_INFORMATION tmp_name_info;
@@ -1924,7 +1924,7 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
name_info = NULL;

if (handle->handle == INVALID_HANDLE_VALUE) {
*len = 0;
*size = 0;
return UV_EINVAL;
}

@@ -1939,7 +1939,7 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
name_size = sizeof(*name_info) + tmp_name_info.FileNameLength;
name_info = malloc(name_size);
if (!name_info) {
*len = 0;
*size = 0;
err = UV_ENOMEM;
goto cleanup;
}
@@ -1952,7 +1952,7 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
}

if (nt_status != STATUS_SUCCESS) {
*len = 0;
*size = 0;
err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status));
goto error;
}
@@ -1967,7 +1967,7 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
}

if (name_len == 0) {
*len = 0;
*size = 0;
err = 0;
goto error;
}
@@ -1984,34 +1984,33 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
NULL,
NULL);
if (!addrlen) {
*len = 0;
*size = 0;
err = uv_translate_sys_error(GetLastError());
goto error;
} else if (pipe_prefix_len + addrlen + 1 > *len) {
/* "\\\\.\\pipe" + name + '\0' */
*len = pipe_prefix_len + addrlen + 1;
} else if (pipe_prefix_len + addrlen > *size) {
/* "\\\\.\\pipe" + name */
*size = pipe_prefix_len + addrlen;
err = UV_ENOBUFS;
goto error;
}

memcpy(buf, pipe_prefix, pipe_prefix_len);
memcpy(buffer, pipe_prefix, pipe_prefix_len);
addrlen = WideCharToMultiByte(CP_UTF8,
0,
name_buf,
name_len,
buf+pipe_prefix_len,
*len-pipe_prefix_len,
buffer+pipe_prefix_len,
*size-pipe_prefix_len,
NULL,
NULL);
if (!addrlen) {
*len = 0;
*size = 0;
err = uv_translate_sys_error(GetLastError());
goto error;
}

addrlen += pipe_prefix_len;
buf[addrlen++] = '\0';
*len = addrlen;
*size = addrlen;

err = 0;
goto cleanup;
@@ -2032,6 +2031,32 @@ int uv_pipe_pending_count(uv_pipe_t* handle) {
}


int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
if (handle->flags & UV_HANDLE_BOUND)
return uv__pipe_getname(handle, buffer, size);

if (handle->flags & UV_HANDLE_CONNECTION ||
handle->handle != INVALID_HANDLE_VALUE) {
*size = 0;
return 0;
}

return UV_EBADF;
}


int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
/* emulate unix behaviour */
if (handle->flags & UV_HANDLE_BOUND)
return UV_ENOTCONN;

if (handle->handle != INVALID_HANDLE_VALUE)
return uv__pipe_getname(handle, buffer, size);

return UV_EBADF;
}


uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
if (!handle->ipc)
return UV_UNKNOWN_HANDLE;
@@ -46,6 +46,8 @@ typedef struct uv_single_fd_set_s {
static OVERLAPPED overlapped_dummy_;
static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;

static AFD_POLL_INFO afd_poll_info_dummy_;


static void uv__init_overlapped_dummy(void) {
HANDLE event;
@@ -65,6 +67,11 @@ static OVERLAPPED* uv__get_overlapped_dummy() {
}


static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() {
return &afd_poll_info_dummy_;
}


static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
uv_req_t* req;
AFD_POLL_INFO* afd_poll_info;
@@ -79,7 +86,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
handle->mask_events_2 = handle->events;
} else if (handle->submitted_events_2 == 0) {
req = &handle->poll_req_2;
afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[0];
afd_poll_info = &handle->afd_poll_info_2;
handle->submitted_events_2 = handle->events;
handle->mask_events_1 = handle->events;
handle->mask_events_2 = 0;
@@ -108,6 +115,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
memset(&req->overlapped, 0, sizeof req->overlapped);

result = uv_msafd_poll((SOCKET) handle->peer_socket,
afd_poll_info,
afd_poll_info,
&req->overlapped);
if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
@@ -119,26 +127,25 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {


static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
AFD_POLL_INFO* afd_poll_info;
AFD_POLL_INFO afd_poll_info;
DWORD result;

afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[1];
afd_poll_info->Exclusive = TRUE;
afd_poll_info->NumberOfHandles = 1;
afd_poll_info->Timeout.QuadPart = INT64_MAX;
afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info->Handles[0].Status = 0;
afd_poll_info->Handles[0].Events = AFD_POLL_ALL;
afd_poll_info.Exclusive = TRUE;
afd_poll_info.NumberOfHandles = 1;
afd_poll_info.Timeout.QuadPart = INT64_MAX;
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info.Handles[0].Status = 0;
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;

result = uv_msafd_poll(handle->socket,
afd_poll_info,
&afd_poll_info,
uv__get_afd_poll_info_dummy(),
uv__get_overlapped_dummy());

if (result == SOCKET_ERROR) {
DWORD error = WSAGetLastError();
if (error != WSA_IO_PENDING) {
return WSAGetLastError();
}
if (error != WSA_IO_PENDING)
return error;
}

return 0;
@@ -155,7 +162,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
handle->submitted_events_1 = 0;
mask_events = handle->mask_events_1;
} else if (req == &handle->poll_req_2) {
afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[0];
afd_poll_info = &handle->afd_poll_info_2;
handle->submitted_events_2 = 0;
mask_events = handle->mask_events_2;
} else {
@@ -498,6 +505,11 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
int len;
SOCKET peer_socket, base_socket;
DWORD bytes;
DWORD yes = 1;

/* Set the socket to nonblocking mode */
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
return uv_translate_sys_error(WSAGetLastError());

/* Try to obtain a base handle for the socket. This increases this chances */
/* that we find an AFD handle and are able to use the fast poll mechanism. */
@@ -558,11 +570,6 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
handle->poll_req_2.type = UV_POLL_REQ;
handle->poll_req_2.data = handle;

handle->afd_poll_info_2.afd_poll_info_ptr = malloc(sizeof(*handle->afd_poll_info_2.afd_poll_info_ptr) * 2);
if (handle->afd_poll_info_2.afd_poll_info_ptr == NULL) {
return UV_ENOMEM;
}

return 0;
}

@@ -624,9 +631,5 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
assert(handle->submitted_events_1 == 0);
assert(handle->submitted_events_2 == 0);

if (handle->afd_poll_info_2.afd_poll_info_ptr) {
free(handle->afd_poll_info_2.afd_poll_info_ptr);
handle->afd_poll_info_2.afd_poll_info_ptr = NULL;
}
uv__handle_close(handle);
}
@@ -93,6 +93,17 @@ INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
req->next_req = NULL;
if (loop->pending_reqs_tail) {
#ifdef _DEBUG
/* Ensure the request is not already in the queue, or the queue
* will get corrupted.
*/
uv_req_t* current = loop->pending_reqs_tail;
do {
assert(req != current);
current = current->next_req;
} while(current != loop->pending_reqs_tail);
#endif

req->next_req = loop->pending_reqs_tail->next_req;
loop->pending_reqs_tail->next_req = req;
loop->pending_reqs_tail = req;
@@ -130,14 +141,13 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
} while (0)


INLINE static void uv_process_reqs(uv_loop_t* loop) {
INLINE static int uv_process_reqs(uv_loop_t* loop) {
uv_req_t* req;
uv_req_t* first;
uv_req_t* next;

if (loop->pending_reqs_tail == NULL) {
return;
}
if (loop->pending_reqs_tail == NULL)
return 0;

first = loop->pending_reqs_tail->next_req;
next = first;
@@ -207,6 +217,8 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) {
assert(0);
}
}

return 1;
}

#endif /* UV_WIN_REQ_INL_H_ */
@@ -184,8 +184,22 @@ int uv_write2(uv_write_t* req,
int uv_try_write(uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs) {
/* NOTE: Won't work with overlapped writes */
return UV_ENOSYS;
if (stream->flags & UV__HANDLE_CLOSING)
return UV_EBADF;
if (!(stream->flags & UV_HANDLE_WRITABLE))
return UV_EPIPE;

switch (stream->type) {
case UV_TCP:
return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs);
case UV_TTY:
return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs);
case UV_NAMED_PIPE:
return UV_EAGAIN;
default:
assert(0);
return UV_ENOSYS;
}
}


@@ -876,6 +876,30 @@ int uv_tcp_write(uv_loop_t* loop,
}


int uv__tcp_try_write(uv_tcp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs) {
int result;
DWORD bytes;

if (handle->write_reqs_pending > 0)
return UV_EAGAIN;

result = WSASend(handle->socket,
(WSABUF*) bufs,
nbufs,
&bytes,
0,
NULL,
NULL);

if (result == SOCKET_ERROR)
return uv_translate_sys_error(WSAGetLastError());
else
return bytes;
}


void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_req_t* req) {
DWORD bytes, flags, err;
@@ -117,7 +117,19 @@ void uv_once(uv_once_t* guard, void (*callback)(void)) {
uv__once_inner(guard, callback);
}

static UV_THREAD_LOCAL uv_thread_t uv__current_thread = NULL;

/* Verify that uv_thread_t can be stored in a TLS slot. */
STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));

static uv_key_t uv__current_thread_key;
static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;


static void uv__init_current_thread_key(void) {
if (uv_key_create(&uv__current_thread_key))
abort();
}


struct thread_ctx {
void (*entry)(void* arg);
@@ -126,16 +138,17 @@ struct thread_ctx {
};


static UINT __stdcall uv__thread_start(void* arg)
{
static UINT __stdcall uv__thread_start(void* arg) {
struct thread_ctx *ctx_p;
struct thread_ctx ctx;

ctx_p = arg;
ctx = *ctx_p;
free(ctx_p);

uv__current_thread = ctx.self;
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
uv_key_set(&uv__current_thread_key, (void*) ctx.self);

ctx.entry(ctx.arg);

return 0;
@@ -177,9 +190,10 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {


uv_thread_t uv_thread_self(void) {
return uv__current_thread;
return (uv_thread_t) uv_key_get(&uv__current_thread_key);
}


int uv_thread_join(uv_thread_t *tid) {
if (WaitForSingleObject(*tid, INFINITE))
return uv_translate_sys_error(GetLastError());
@@ -170,7 +170,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
}


int uv_tty_set_mode(uv_tty_t* tty, int mode) {
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
DWORD flags;
unsigned char was_reading;
uv_alloc_cb alloc_cb;
@@ -185,12 +185,15 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
return 0;
}

if (mode) {
/* Raw input */
flags = ENABLE_WINDOW_INPUT;
} else {
/* Line-buffered mode. */
flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
switch (mode) {
case UV_TTY_MODE_NORMAL:
flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
break;
case UV_TTY_MODE_RAW:
flags = ENABLE_WINDOW_INPUT;
break;
case UV_TTY_MODE_IO:
return UV_ENOTSUP;
}

if (!SetConsoleMode(tty->handle, flags)) {
@@ -1875,6 +1878,21 @@ int uv_tty_write(uv_loop_t* loop,
}


int uv__tty_try_write(uv_tty_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs) {
DWORD error;

if (handle->write_reqs_pending > 0)
return UV_EAGAIN;

if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
return uv_translate_sys_error(error);

return uv__count_bufs(bufs, nbufs);
}


void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
uv_write_t* req) {
int err;
@@ -31,6 +31,7 @@ sNtDeviceIoControlFile pNtDeviceIoControlFile;
sNtQueryInformationFile pNtQueryInformationFile;
sNtSetInformationFile pNtSetInformationFile;
sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
sNtQueryDirectoryFile pNtQueryDirectoryFile;
sNtQuerySystemInformation pNtQuerySystemInformation;


@@ -97,6 +98,12 @@ void uv_winapi_init() {
uv_fatal_error(GetLastError(), "GetProcAddress");
}

pNtQueryDirectoryFile = (sNtQueryDirectoryFile)
GetProcAddress(ntdll_module, "NtQueryDirectoryFile");
if (pNtQueryVolumeInformationFile == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}

pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
ntdll_module,
"NtQuerySystemInformation");
@@ -4104,12 +4104,23 @@
# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
#endif

/* from winternl.h */
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef const UNICODE_STRING *PCUNICODE_STRING;

/* from ntifs.h */
#ifndef DEVICE_TYPE
# define DEVICE_TYPE DWORD
#endif

/* from ntifs.h */
/* MinGW already has it, mingw-w64 does not. */
/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
* not.
*/
#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
@@ -4205,6 +4216,37 @@ typedef enum _FILE_INFORMATION_CLASS {
FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

typedef struct _FILE_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;

typedef struct _FILE_BOTH_DIR_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaSize;
CCHAR ShortNameLength;
WCHAR ShortName[12];
WCHAR FileName[1];
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;

typedef struct _FILE_BASIC_INFORMATION {
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
@@ -4512,6 +4554,19 @@ typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
ULONG SystemInformationLength,
PULONG ReturnLength);

typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry,
PUNICODE_STRING FileName,
BOOLEAN RestartScan
);

/*
* Kernel32 headers
@@ -4555,6 +4610,30 @@ typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
# define ERROR_SYMLINK_NOT_SUPPORTED 1464
#endif

#ifndef ERROR_MUI_FILE_NOT_FOUND
# define ERROR_MUI_FILE_NOT_FOUND 15100
#endif

#ifndef ERROR_MUI_INVALID_FILE
# define ERROR_MUI_INVALID_FILE 15101
#endif

#ifndef ERROR_MUI_INVALID_RC_CONFIG
# define ERROR_MUI_INVALID_RC_CONFIG 15102
#endif

#ifndef ERROR_MUI_INVALID_LOCALE_NAME
# define ERROR_MUI_INVALID_LOCALE_NAME 15103
#endif

#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME
# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104
#endif

#ifndef ERROR_MUI_FILE_NOT_LOADED
# define ERROR_MUI_FILE_NOT_LOADED 15105
#endif

typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
(HANDLE CompletionPort,
LPOVERLAPPED_ENTRY lpCompletionPortEntries,
@@ -4626,6 +4705,7 @@ extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
extern sNtQueryInformationFile pNtQueryInformationFile;
extern sNtSetInformationFile pNtSetInformationFile;
extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
extern sNtQuerySystemInformation pNtQuerySystemInformation;


@@ -474,8 +474,8 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
}


int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info,
OVERLAPPED* overlapped) {
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
IO_STATUS_BLOCK iosb;
IO_STATUS_BLOCK* iosb_ptr;
HANDLE event = NULL;
@@ -513,10 +513,10 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info,
apc_context,
iosb_ptr,
IOCTL_AFD_POLL,
info,
sizeof *info,
info,
sizeof *info);
info_in,
sizeof *info_in,
info_out,
sizeof *info_out);

if (overlapped == NULL) {
/* If this is a blocking operation, wait for the event to become */
@@ -68,6 +68,7 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) {
const char* arg;
char* args[16];
int n;
pid_t pid;

stdout_file = tmpfile();
if (!stdout_file) {
@@ -78,7 +79,7 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) {
p->terminated = 0;
p->status = 0;

pid_t pid = fork();
pid = fork();

if (pid < 0) {
perror("fork");
@@ -167,8 +168,14 @@ static void* dowait(void* data) {
/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
int process_wait(process_info_t* vec, int n, int timeout) {
int i;
int r;
int retval;
process_info_t* p;
dowait_args args;
pthread_t tid;
struct timeval tv;
fd_set fds;

args.vec = vec;
args.n = n;
args.pipe[0] = -1;
@@ -186,10 +193,7 @@ int process_wait(process_info_t* vec, int n, int timeout) {
* we'd need to lock vec.
*/

pthread_t tid;
int retval;

int r = pipe((int*)&(args.pipe));
r = pipe((int*)&(args.pipe));
if (r) {
perror("pipe()");
return -1;
@@ -202,11 +206,9 @@ int process_wait(process_info_t* vec, int n, int timeout) {
goto terminate;
}

struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = 0;

fd_set fds;
FD_ZERO(&fds);
FD_SET(args.pipe[0], &fds);

@@ -259,15 +261,16 @@ long int process_output_size(process_info_t *p) {

/* Copy the contents of the stdio output buffer to `fd`. */
int process_copy_output(process_info_t *p, int fd) {
int r = fseek(p->stdout_file, 0, SEEK_SET);
ssize_t nwritten;
char buf[1024];
int r;

r = fseek(p->stdout_file, 0, SEEK_SET);
if (r < 0) {
perror("fseek");
return -1;
}

ssize_t nwritten;
char buf[1024];

/* TODO: what if the line is longer than buf */
while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) {
/* TODO: what if write doesn't write the whole buffer... */
@@ -39,6 +39,11 @@
# include <sys/resource.h> /* setrlimit() */
#endif

#ifdef __clang__
# pragma clang diagnostic ignored "-Wvariadic-macros"
# pragma clang diagnostic ignored "-Wc99-extensions"
#endif

#define TEST_PORT 9123
#define TEST_PORT_2 9124

@@ -229,4 +234,21 @@ UNUSED static void close_loop(uv_loop_t* loop) {
uv_run(loop, UV_RUN_DEFAULT);
}

UNUSED static int can_ipv6(void) {
uv_interface_address_t* addr;
int supported;
int count;
int i;

if (uv_interface_addresses(&addr, &count))
return 1; /* Assume IPv6 support on failure. */

supported = 0;
for (i = 0; supported == 0 && i < count; i += 1)
supported = (AF_INET6 == addr[i].address.address6.sin6_family);

uv_free_interface_addresses(addr, count);
return supported;
}

#endif /* TASK_H_ */
@@ -54,7 +54,6 @@ TEST_IMPL(close_fd) {
int fd[2];

ASSERT(0 == pipe(fd));
ASSERT(0 == fcntl(fd[0], F_SETFL, O_NONBLOCK));
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
fd[0] = -1; /* uv_pipe_open() takes ownership of the file descriptor. */
@@ -29,35 +29,22 @@ extern char executable_path[];
TEST_IMPL(cwd_and_chdir) {
char buffer_orig[PATHMAX];
char buffer_new[PATHMAX];
size_t size;
char* last_slash;
size_t size1;
size_t size2;
int err;

size = sizeof(buffer_orig);
err = uv_cwd(buffer_orig, &size);
size1 = sizeof buffer_orig;
err = uv_cwd(buffer_orig, &size1);
ASSERT(err == 0);

/* Remove trailing slash unless at a root directory. */
#ifdef _WIN32
last_slash = strrchr(buffer_orig, '\\');
ASSERT(last_slash);
if (last_slash > buffer_orig && *(last_slash - 1) != ':') {
*last_slash = '\0';
}
#else /* Unix */
last_slash = strrchr(buffer_orig, '/');
ASSERT(last_slash);
if (last_slash != buffer_orig) {
*last_slash = '\0';
}
#endif

err = uv_chdir(buffer_orig);
ASSERT(err == 0);

err = uv_cwd(buffer_new, &size);
size2 = sizeof buffer_new;
err = uv_cwd(buffer_new, &size2);
ASSERT(err == 0);

ASSERT(size1 == size2);
ASSERT(strcmp(buffer_orig, buffer_new) == 0);

return 0;
@@ -26,31 +26,28 @@

TEST_IMPL(dlerror) {
const char* path = "test/fixtures/load_error.node";
const char* dlerror_no_error = "no error";
const char* msg;
uv_lib_t lib;
int r;

#ifdef __linux__
const char* dlerror_desc = "file too short";
#elif defined (__sun__)
const char* dlerror_desc = "unknown file type";
#elif defined (_WIN32)
const char* dlerror_desc = "%1 is not a valid Win32 application";
#else
const char* dlerror_desc = "";
#endif
lib.errmsg = NULL;
lib.handle = NULL;
msg = uv_dlerror(&lib);
ASSERT(msg != NULL);
ASSERT(strstr(msg, dlerror_no_error) != NULL);

r = uv_dlopen(path, &lib);
ASSERT(r == -1);

msg = uv_dlerror(&lib);
ASSERT(msg != NULL);
ASSERT(strstr(msg, dlerror_desc) != NULL);
ASSERT(strstr(msg, dlerror_no_error) == NULL);

/* Should return the same error twice in a row. */
msg = uv_dlerror(&lib);
ASSERT(msg != NULL);
ASSERT(strstr(msg, dlerror_desc) != NULL);
ASSERT(strstr(msg, dlerror_no_error) == NULL);

uv_dlclose(&lib);

@@ -642,6 +642,7 @@ TEST_IMPL(fs_event_getpath) {
len = sizeof buf;
r = uv_fs_event_getpath(&fs_event, buf, &len);
ASSERT(r == 0);
ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, "watch_dir", len) == 0);
r = uv_fs_event_stop(&fs_event);
ASSERT(r == 0);
@@ -172,6 +172,7 @@ TEST_IMPL(fs_poll_getpath) {
ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100));
len = sizeof buf;
ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len));
ASSERT(buf[len - 1] != 0);
ASSERT(0 == memcmp(buf, FIXTURE, len));

uv_close((uv_handle_t*) &poll_handle, close_cb);
@@ -568,7 +568,17 @@ TEST_IMPL(fs_file_loop) {
loop = uv_default_loop();

unlink("test_symlink");
uv_fs_symlink(loop, &req, "test_symlink", "test_symlink", 0, NULL);
r = uv_fs_symlink(loop, &req, "test_symlink", "test_symlink", 0, NULL);
#ifdef _WIN32
/*
* Windows XP and Server 2003 don't support symlinks; we'll get UV_ENOTSUP.
* Starting with vista they are supported, but only when elevated, otherwise
* we'll see UV_EPERM.
*/
if (r == UV_ENOTSUP || r == UV_EPERM)
return 0;
#endif
ASSERT(r == 0);
uv_fs_req_cleanup(&req);

r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, NULL);
@@ -61,5 +61,26 @@ TEST_IMPL(get_currentexe) {
r = uv_exepath(buffer, NULL);
ASSERT(r == UV_EINVAL);

size = 0;
r = uv_exepath(buffer, &size);
ASSERT(r == UV_EINVAL);

memset(buffer, -1, sizeof(buffer));

size = 1;
r = uv_exepath(buffer, &size);
ASSERT(r == 0);
ASSERT(size == 0);
ASSERT(buffer[0] == '\0');

memset(buffer, -1, sizeof(buffer));

size = 2;
r = uv_exepath(buffer, &size);
ASSERT(r == 0);
ASSERT(size == 1);
ASSERT(buffer[0] != '\0');
ASSERT(buffer[1] == '\0');

return 0;
}
@@ -97,6 +97,22 @@ TEST_IMPL(getaddrinfo_fail) {
}


TEST_IMPL(getaddrinfo_fail_sync) {
uv_getaddrinfo_t req;

ASSERT(0 > uv_getaddrinfo(uv_default_loop(),
&req,
NULL,
"xyzzy.xyzzy.xyzzy",
NULL,
NULL));
uv_freeaddrinfo(req.addrinfo);

MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(getaddrinfo_basic) {
int r;
getaddrinfo_handle = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t));
@@ -118,6 +134,22 @@ TEST_IMPL(getaddrinfo_basic) {
}


TEST_IMPL(getaddrinfo_basic_sync) {
uv_getaddrinfo_t req;

ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
&req,
NULL,
name,
NULL,
NULL));
uv_freeaddrinfo(req.addrinfo);

MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(getaddrinfo_concurrent) {
int i, r;
int* data;
@@ -44,6 +44,7 @@ static void getnameinfo_req(uv_getnameinfo_t* handle,
ASSERT(service != NULL);
}


TEST_IMPL(getnameinfo_basic_ip4) {
int r;

@@ -63,6 +64,23 @@ TEST_IMPL(getnameinfo_basic_ip4) {
return 0;
}


TEST_IMPL(getnameinfo_basic_ip4_sync) {
ASSERT(0 == uv_ip4_addr(address_ip4, port, &addr4));

ASSERT(0 == uv_getnameinfo(uv_default_loop(),
&req,
NULL,
(const struct sockaddr*)&addr4,
0));
ASSERT(req.host != NULL);
ASSERT(req.service != NULL);

MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(getnameinfo_basic_ip6) {
int r;

@@ -29,6 +29,7 @@ TEST_DECLARE (loop_close)
TEST_DECLARE (loop_stop)
TEST_DECLARE (loop_update_time)
TEST_DECLARE (loop_backend_timeout)
TEST_DECLARE (loop_configure)
TEST_DECLARE (default_loop_close)
TEST_DECLARE (barrier_1)
TEST_DECLARE (barrier_2)
@@ -103,6 +104,7 @@ TEST_DECLARE (udp_dgram_too_big)
TEST_DECLARE (udp_dual_stack)
TEST_DECLARE (udp_ipv6_only)
TEST_DECLARE (udp_options)
TEST_DECLARE (udp_options6)
TEST_DECLARE (udp_no_autobind)
TEST_DECLARE (udp_open)
TEST_DECLARE (udp_try_send)
@@ -165,6 +167,7 @@ TEST_DECLARE (pipe_ref4)
#ifndef _WIN32
TEST_DECLARE (pipe_close_stdout_read_stdin)
#endif
TEST_DECLARE (pipe_set_non_blocking)
TEST_DECLARE (process_ref)
TEST_DECLARE (has_ref)
TEST_DECLARE (active)
@@ -178,9 +181,12 @@ TEST_DECLARE (get_memory)
TEST_DECLARE (handle_fileno)
TEST_DECLARE (hrtime)
TEST_DECLARE (getaddrinfo_fail)
TEST_DECLARE (getaddrinfo_fail_sync)
TEST_DECLARE (getaddrinfo_basic)
TEST_DECLARE (getaddrinfo_basic_sync)
TEST_DECLARE (getaddrinfo_concurrent)
TEST_DECLARE (getnameinfo_basic_ip4)
TEST_DECLARE (getnameinfo_basic_ip4_sync)
TEST_DECLARE (getnameinfo_basic_ip6)
TEST_DECLARE (getsockname_tcp)
TEST_DECLARE (getsockname_udp)
@@ -269,6 +275,7 @@ TEST_DECLARE (ip4_addr)
TEST_DECLARE (ip6_addr_link_local)

#ifdef _WIN32
TEST_DECLARE (poll_close_doesnt_corrupt_stack)
TEST_DECLARE (poll_closesocket)
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
TEST_DECLARE (argument_escaping)
@@ -312,6 +319,7 @@ TASK_LIST_START
TEST_ENTRY (loop_stop)
TEST_ENTRY (loop_update_time)
TEST_ENTRY (loop_backend_timeout)
TEST_ENTRY (loop_configure)
TEST_ENTRY (default_loop_close)
TEST_ENTRY (barrier_1)
TEST_ENTRY (barrier_2)
@@ -332,6 +340,7 @@ TASK_LIST_START
#ifndef _WIN32
TEST_ENTRY (pipe_close_stdout_read_stdin)
#endif
TEST_ENTRY (pipe_set_non_blocking)
TEST_ENTRY (tty)
TEST_ENTRY (stdio_over_pipes)
TEST_ENTRY (ip6_pton)
@@ -410,6 +419,7 @@ TASK_LIST_START
TEST_ENTRY (udp_dual_stack)
TEST_ENTRY (udp_ipv6_only)
TEST_ENTRY (udp_options)
TEST_ENTRY (udp_options6)
TEST_ENTRY (udp_no_autobind)
TEST_ENTRY (udp_multicast_interface)
TEST_ENTRY (udp_multicast_interface6)
@@ -519,11 +529,14 @@ TASK_LIST_START
TEST_ENTRY (hrtime)

TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000)
TEST_ENTRY (getaddrinfo_fail_sync)

TEST_ENTRY (getaddrinfo_basic)
TEST_ENTRY (getaddrinfo_basic_sync)
TEST_ENTRY (getaddrinfo_concurrent)

TEST_ENTRY (getnameinfo_basic_ip4)
TEST_ENTRY (getnameinfo_basic_ip4_sync)
TEST_ENTRY (getnameinfo_basic_ip6)

TEST_ENTRY (getsockname_tcp)
@@ -558,6 +571,7 @@ TASK_LIST_START
TEST_ENTRY (kill)

#ifdef _WIN32
TEST_ENTRY (poll_close_doesnt_corrupt_stack)
TEST_ENTRY (poll_closesocket)
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
TEST_ENTRY (argument_escaping)
@@ -0,0 +1,38 @@
/* Copyright (c) 2014, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "uv.h"
#include "task.h"

static void timer_cb(uv_timer_t* handle) {
uv_close((uv_handle_t*) handle, NULL);
}


TEST_IMPL(loop_configure) {
uv_timer_t timer_handle;
uv_loop_t loop;
ASSERT(0 == uv_loop_init(&loop));
#ifdef _WIN32
ASSERT(UV_ENOSYS == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, 0));
#else
ASSERT(0 == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, SIGPROF));
#endif
ASSERT(0 == uv_timer_init(&loop, &timer_handle));
ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 10, 0));
ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
ASSERT(0 == uv_loop_close(&loop));
return 0;
}
@@ -54,8 +54,10 @@ TEST_IMPL(osx_select) {
uv_tty_t tty;

fd = open("/dev/tty", O_RDONLY);

ASSERT(fd >= 0);
if (fd < 0) {
LOGF("Cannot open /dev/tty as read-only: %s\n", strerror(errno));
return TEST_SKIP;
}

r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
ASSERT(r == 0);
@@ -90,7 +92,7 @@ TEST_IMPL(osx_select_many_fds) {
uv_tty_t tty;
uv_tcp_t tcps[1500];

TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 2);
TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 100);

r = uv_ip4_addr("127.0.0.1", 0, &addr);
ASSERT(r == 0);
@@ -104,7 +106,10 @@ TEST_IMPL(osx_select_many_fds) {
}

fd = open("/dev/tty", O_RDONLY);
ASSERT(fd >= 0);
if (fd < 0) {
LOGF("Cannot open /dev/tty as read-only: %s\n", strerror(errno));
return TEST_SKIP;
}

r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
ASSERT(r == 0);
@@ -246,6 +246,9 @@ TEST_IMPL(tcp_ping_pong) {


TEST_IMPL(tcp_ping_pong_v6) {
if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

tcp_pinger_v6_new();
uv_run(uv_default_loop(), UV_RUN_DEFAULT);

@@ -53,6 +53,7 @@ TEST_IMPL(pipe_close_stdout_read_stdin) {
int pid;
int fd[2];
int status;
uv_pipe_t stdin_pipe;

r = pipe(fd);
ASSERT(r == 0);
@@ -68,8 +69,6 @@ TEST_IMPL(pipe_close_stdout_read_stdin) {
ASSERT(r != -1);

/* Create a stream that reads from the pipe. */
uv_pipe_t stdin_pipe;

r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0);
ASSERT(r == 0);

@@ -36,38 +36,121 @@
# include <fcntl.h>
#endif

static uv_pipe_t pipe_client;
static uv_pipe_t pipe_server;
static uv_connect_t connect_req;

static int close_cb_called = 0;
static int pipe_close_cb_called = 0;
static int pipe_client_connect_cb_called = 0;


static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
close_cb_called++;
static void pipe_close_cb(uv_handle_t* handle) {
ASSERT(handle == (uv_handle_t*) &pipe_client ||
handle == (uv_handle_t*) &pipe_server);
pipe_close_cb_called++;
}


static void pipe_client_connect_cb(uv_connect_t* req, int status) {
char buf[1024];
size_t len;
int r;

ASSERT(req == &connect_req);
ASSERT(status == 0);

len = sizeof buf;
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == 0);

ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
ASSERT(r == 0 && len == 0);

pipe_client_connect_cb_called++;


uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
}


static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
/* This function *may* be called, depending on whether accept or the
* connection callback is called first.
*/
ASSERT(status == 0);
}


TEST_IMPL(pipe_getsockname) {
uv_pipe_t server;
uv_loop_t* loop;
char buf[1024];
size_t len;
int r;

r = uv_pipe_init(uv_default_loop(), &server, 0);
loop = uv_default_loop();
ASSERT(loop != NULL);

r = uv_pipe_init(loop, &pipe_server, 0);
ASSERT(r == 0);
r = uv_pipe_bind(&server, TEST_PIPENAME);

len = sizeof buf;
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == UV_EBADF);

len = sizeof buf;
r = uv_pipe_getpeername(&pipe_server, buf, &len);
ASSERT(r == UV_EBADF);

r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
ASSERT(r == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&server, buf, &len);
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == 0);

ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);

uv_close((uv_handle_t*)&server, close_cb);
len = sizeof buf;
r = uv_pipe_getpeername(&pipe_server, buf, &len);
ASSERT(r == UV_ENOTCONN);

uv_run(uv_default_loop(), UV_RUN_DEFAULT);
r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
ASSERT(r == 0);

r = uv_pipe_init(loop, &pipe_client, 0);
ASSERT(r == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
ASSERT(r == UV_EBADF);

ASSERT(close_cb_called == 1);
len = sizeof buf;
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == UV_EBADF);

uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);

len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
ASSERT(r == 0 && len == 0);

len = sizeof buf;
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == 0);

ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);

r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(pipe_client_connect_cb_called == 1);
ASSERT(pipe_close_cb_called == 2);

MAKE_VALGRIND_HAPPY();
return 0;
@@ -76,7 +159,6 @@ TEST_IMPL(pipe_getsockname) {

TEST_IMPL(pipe_getsockname_abstract) {
#if defined(__linux__)
uv_pipe_t server;
char buf[1024];
size_t len;
int r;
@@ -96,24 +178,24 @@ TEST_IMPL(pipe_getsockname_abstract) {
r = bind(sock, (struct sockaddr*)&sun, sun_len);
ASSERT(r == 0);

r = uv_pipe_init(uv_default_loop(), &server, 0);
r = uv_pipe_init(uv_default_loop(), &pipe_server, 0);
ASSERT(r == 0);
r = uv_pipe_open(&server, sock);
r = uv_pipe_open(&pipe_server, sock);
ASSERT(r == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&server, buf, &len);
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == 0);

ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);

uv_close((uv_handle_t*)&server, close_cb);
uv_close((uv_handle_t*)&pipe_server, pipe_close_cb);

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

close(sock);

ASSERT(close_cb_called == 1);
ASSERT(pipe_close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
#else
@@ -124,7 +206,6 @@ TEST_IMPL(pipe_getsockname_abstract) {

TEST_IMPL(pipe_getsockname_blocking) {
#ifdef _WIN32
uv_pipe_t reader;
HANDLE readh, writeh;
int readfd;
char buf1[1024], buf2[1024];
@@ -134,42 +215,44 @@ TEST_IMPL(pipe_getsockname_blocking) {
r = CreatePipe(&readh, &writeh, NULL, 65536);
ASSERT(r != 0);

r = uv_pipe_init(uv_default_loop(), &reader, 0);
r = uv_pipe_init(uv_default_loop(), &pipe_client, 0);
ASSERT(r == 0);
readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY);
ASSERT(r != -1);
r = uv_pipe_open(&reader, readfd);
r = uv_pipe_open(&pipe_client, readfd);
ASSERT(r == 0);
r = uv_read_start((uv_stream_t*)&reader, NULL, NULL);
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
ASSERT(r == 0);
Sleep(100);
r = uv_read_stop((uv_stream_t*)&reader);
r = uv_read_stop((uv_stream_t*)&pipe_client);
ASSERT(r == 0);

len1 = sizeof buf1;
r = uv_pipe_getsockname(&reader, buf1, &len1);
r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
ASSERT(r == 0);
ASSERT(buf1[len1 - 1] != 0);

r = uv_read_start((uv_stream_t*)&reader, NULL, NULL);
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
ASSERT(r == 0);
Sleep(100);

len2 = sizeof buf2;
r = uv_pipe_getsockname(&reader, buf2, &len2);
r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
ASSERT(r == 0);
ASSERT(buf2[len2 - 1] != 0);

r = uv_read_stop((uv_stream_t*)&reader);
r = uv_read_stop((uv_stream_t*)&pipe_client);
ASSERT(r == 0);

ASSERT(len1 == len2);
ASSERT(memcmp(buf1, buf2, len1) == 0);

close_cb_called = 0;
uv_close((uv_handle_t*)&reader, close_cb);
pipe_close_cb_called = 0;
uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

ASSERT(close_cb_called == 1);
ASSERT(pipe_close_cb_called == 1);

_close(readfd);
CloseHandle(writeh);
@@ -0,0 +1,99 @@
/* Copyright (c) 2015, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "uv.h"
#include "task.h"

#ifdef _WIN32

TEST_IMPL(pipe_set_non_blocking) {
RETURN_SKIP("Test not implemented on Windows.");
}

#else /* !_WIN32 */

#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

struct thread_ctx {
uv_barrier_t barrier;
int fd;
};

static void thread_main(void* arg) {
struct thread_ctx* ctx;
char buf[4096];
ssize_t n;

ctx = arg;
uv_barrier_wait(&ctx->barrier);

do
n = read(ctx->fd, buf, sizeof(buf));
while (n > 0 || (n == -1 && errno == EINTR));

ASSERT(n == 0);
}

TEST_IMPL(pipe_set_non_blocking) {
struct thread_ctx ctx;
uv_pipe_t pipe_handle;
uv_thread_t thread;
size_t nwritten;
char data[4096];
uv_buf_t buf;
int fd[2];
int n;

ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1));

ctx.fd = fd[1];
ASSERT(0 == uv_barrier_init(&ctx.barrier, 2));
ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx));
uv_barrier_wait(&ctx.barrier);

buf.len = sizeof(data);
buf.base = data;
memset(data, '.', sizeof(data));

nwritten = 0;
while (nwritten < 10 << 20) {
/* The stream is in blocking mode so uv_try_write() should always succeed
* with the exact number of bytes that we wanted written.
*/
n = uv_try_write((uv_stream_t*) &pipe_handle, &buf, 1);
ASSERT(n == sizeof(data));
nwritten += n;
}

uv_close((uv_handle_t*) &pipe_handle, NULL);
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));

ASSERT(0 == close(fd[1])); /* fd[0] is closed by uv_close(). */
ASSERT(0 == uv_thread_join(&thread));
uv_barrier_destroy(&ctx.barrier);

MAKE_VALGRIND_HAPPY();
return 0;
}

#endif /* !_WIN32 */
@@ -27,6 +27,7 @@
TEST_IMPL(platform_output) {
char buffer[512];
size_t rss;
size_t size;
double uptime;
uv_rusage_t rusage;
uv_cpu_info_t* cpus;
@@ -39,6 +40,11 @@ TEST_IMPL(platform_output) {
ASSERT(err == 0);
printf("uv_get_process_title: %s\n", buffer);

size = sizeof(buffer);
err = uv_cwd(buffer, &size);
ASSERT(err == 0);
printf("uv_cwd: %s\n", buffer);

err = uv_resident_set_memory(&rss);
ASSERT(err == 0);
printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss);
@@ -0,0 +1,114 @@
/* Copyright Bert Belder, and other libuv contributors. 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.
*/

#ifdef _WIN32

#include <errno.h>
#include <stdio.h>

#include "uv.h"
#include "task.h"

#ifdef _MSC_VER /* msvc */
# define NO_INLINE __declspec(noinline)
#else /* gcc */
# define NO_INLINE __attribute__ ((noinline))
#endif


uv_os_sock_t sock;
uv_poll_t handle;

static int close_cb_called = 0;


static void close_cb(uv_handle_t* h) {
close_cb_called++;
}


static void poll_cb(uv_poll_t* h, int status, int events) {
ASSERT(0 && "should never get here");
}


static void NO_INLINE close_socket_and_verify_stack() {
const uint32_t MARKER = 0xDEADBEEF;
const int VERIFY_AFTER = 10; /* ms */
int r;

volatile uint32_t data[65536];
size_t i;

for (i = 0; i < ARRAY_SIZE(data); i++)
data[i] = MARKER;

r = closesocket(sock);
ASSERT(r == 0);

uv_sleep(VERIFY_AFTER);

for (i = 0; i < ARRAY_SIZE(data); i++)
ASSERT(data[i] == MARKER);
}


TEST_IMPL(poll_close_doesnt_corrupt_stack) {
struct WSAData wsa_data;
int r;
unsigned long on;
struct sockaddr_in addr;

r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
ASSERT(r == 0);

sock = socket(AF_INET, SOCK_STREAM, 0);
ASSERT(sock != INVALID_SOCKET);
on = 1;
r = ioctlsocket(sock, FIONBIO, &on);
ASSERT(r == 0);

r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
ASSERT(r == 0);

r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
ASSERT(r != 0);
ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);

r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
ASSERT(r == 0);
r = uv_poll_start(&handle, UV_READABLE | UV_WRITABLE, poll_cb);
ASSERT(r == 0);

uv_close((uv_handle_t*) &handle, close_cb);

close_socket_and_verify_stack();

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

ASSERT(close_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}

#endif /* _WIN32 */
@@ -67,7 +67,8 @@ TEST_IMPL(poll_closesocket) {
r = ioctlsocket(sock, FIONBIO, &on);
ASSERT(r == 0);

addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
ASSERT(r == 0);

r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
ASSERT(r != 0);
@@ -22,7 +22,6 @@
#include <errno.h>

#ifndef _WIN32
# include <fcntl.h>
# include <sys/socket.h>
# include <unistd.h>
#endif
@@ -86,23 +85,7 @@ static int got_eagain(void) {
}


static void set_nonblocking(uv_os_sock_t sock) {
int r;
#ifdef _WIN32
unsigned long on = 1;
r = ioctlsocket(sock, FIONBIO, &on);
ASSERT(r == 0);
#else
int flags = fcntl(sock, F_GETFL, 0);
ASSERT(flags >= 0);
r = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
ASSERT(r >= 0);
#endif
}


static uv_os_sock_t create_nonblocking_bound_socket(
struct sockaddr_in bind_addr) {
static uv_os_sock_t create_bound_socket (struct sockaddr_in bind_addr) {
uv_os_sock_t sock;
int r;

@@ -113,8 +96,6 @@ static uv_os_sock_t create_nonblocking_bound_socket(
ASSERT(sock >= 0);
#endif

set_nonblocking(sock);

#ifndef _WIN32
{
/* Allow reuse of the port. */
@@ -479,8 +460,6 @@ static void server_poll_cb(uv_poll_t* handle, int status, int events) {
ASSERT(sock >= 0);
#endif

set_nonblocking(sock);

connection_context = create_connection_context(sock, 1);
connection_context->events = UV_READABLE | UV_WRITABLE;
r = uv_poll_start(&connection_context->poll_handle,
@@ -502,7 +481,7 @@ static void start_server(void) {
int r;

ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
sock = create_nonblocking_bound_socket(addr);
sock = create_bound_socket(addr);
context = create_server_context(sock);

r = listen(sock, 100);
@@ -523,7 +502,7 @@ static void start_client(void) {
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr));

sock = create_nonblocking_bound_socket(addr);
sock = create_bound_socket(addr);
context = create_connection_context(sock, 0);

context->events = UV_READABLE | UV_WRITABLE;
@@ -988,7 +988,8 @@ TEST_IMPL(environment_creation) {
}
}
if (prev) { /* verify sort order -- requires Vista */
#if _WIN32_WINNT >= 0x0600
#if _WIN32_WINNT >= 0x0600 && \
(!defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR))
ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1);
#endif
}
@@ -1014,7 +1015,7 @@ TEST_IMPL(spawn_with_an_odd_path) {
char *path = getenv("PATH");
ASSERT(path != NULL);
snprintf(newpath, 2048, ";.;%s", path);
SetEnvironmentVariable("PATH", path);
SetEnvironmentVariable("PATH", newpath);

init_process_options("", exit_cb);
options.file = options.args[0] = "program-that-had-better-not-exist";
@@ -1032,6 +1033,7 @@ TEST_IMPL(spawn_with_an_odd_path) {
#ifndef _WIN32
TEST_IMPL(spawn_setuid_setgid) {
int r;
struct passwd* pw;

/* if not root, then this will fail. */
uv_uid_t uid = getuid();
@@ -1043,14 +1045,16 @@ TEST_IMPL(spawn_setuid_setgid) {
init_process_options("spawn_helper1", exit_cb);

/* become the "nobody" user. */
struct passwd* pw;
pw = getpwnam("nobody");
ASSERT(pw != NULL);
options.uid = pw->pw_uid;
options.gid = pw->pw_gid;
options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID;

r = uv_spawn(uv_default_loop(), &process, &options);
if (r == UV_EACCES)
RETURN_SKIP("user 'nobody' cannot access the test runner");

ASSERT(r == 0);

r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
@@ -1240,7 +1244,6 @@ TEST_IMPL(closed_fd_events) {

/* create a pipe and share it with a child process */
ASSERT(0 == pipe(fd));
ASSERT(0 == fcntl(fd[0], F_SETFL, O_NONBLOCK));

/* spawn_helper4 blocks indefinitely. */
init_process_options("spawn_helper4", exit_cb);
@@ -1297,7 +1300,16 @@ TEST_IMPL(spawn_reads_child_path) {
int len;
char file[64];
char path[1024];
char *env[2] = {path, NULL};
char* env[3];

/* Need to carry over the dynamic linker path when the test runner is
* linked against libuv.so, see https://github.com/libuv/libuv/issues/85.
*/
#if defined(__APPLE__)
static const char dyld_path_var[] = "DYLD_LIBRARY_PATH";
#else
static const char dyld_path_var[] = "LD_LIBRARY_PATH";
#endif

/* Set up the process, but make sure that the file to run is relative and */
/* requires a lookup into PATH */
@@ -1312,6 +1324,16 @@ TEST_IMPL(spawn_reads_child_path) {
strcpy(path, "PATH=");
strcpy(path + 5, exepath);

env[0] = path;
env[1] = getenv(dyld_path_var);
env[2] = NULL;

if (env[1] != NULL) {
static char buf[1024 + sizeof(dyld_path_var)];
snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]);
env[1] = buf;
}

options.file = file;
options.args[0] = file;
options.env = env;
@@ -39,6 +39,9 @@ TEST_IMPL(tcp_bind6_error_addrinuse) {
uv_tcp_t server1, server2;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr));

r = uv_tcp_init(uv_default_loop(), &server1);
@@ -73,6 +76,9 @@ TEST_IMPL(tcp_bind6_error_addrnotavail) {
uv_tcp_t server;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("4:4:4:4:4:4:4:4", TEST_PORT, &addr));

r = uv_tcp_init(uv_default_loop(), &server);
@@ -98,6 +104,9 @@ TEST_IMPL(tcp_bind6_error_fault) {
uv_tcp_t server;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

garbage_addr = (struct sockaddr_in6*) &garbage;

r = uv_tcp_init(uv_default_loop(), &server);
@@ -123,6 +132,9 @@ TEST_IMPL(tcp_bind6_error_inval) {
uv_tcp_t server;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr1));
ASSERT(0 == uv_ip6_addr("::", TEST_PORT_2, &addr2));

@@ -149,6 +161,9 @@ TEST_IMPL(tcp_bind6_localhost_ok) {
uv_tcp_t server;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));

r = uv_tcp_init(uv_default_loop(), &server);
@@ -28,16 +28,6 @@

#define MAX_BYTES 1024 * 1024

#ifdef _WIN32

TEST_IMPL(tcp_try_write) {

MAKE_VALGRIND_HAPPY();
return 0;
}

#else /* !_WIN32 */

static uv_tcp_t server;
static uv_tcp_t client;
static uv_tcp_t incoming;
@@ -138,5 +128,3 @@ TEST_IMPL(tcp_try_write) {
MAKE_VALGRIND_HAPPY();
return 0;
}

#endif /* !_WIN32 */
@@ -147,23 +147,22 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) {


TEST_IMPL(udp_dual_stack) {
#if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
RETURN_SKIP("dual stack not enabled by default in this OS.");
#else
if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

do_test(ipv6_recv_ok, 0);

ASSERT(recv_cb_called == 1);
ASSERT(send_cb_called == 1);

return 0;
#endif
}


TEST_IMPL(udp_ipv6_only) {
if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

do_test(ipv6_recv_fail, UV_UDP_IPV6ONLY);

ASSERT(recv_cb_called == 0);
@@ -60,6 +60,9 @@ TEST_IMPL(udp_multicast_interface6) {
struct sockaddr_in6 addr;
struct sockaddr_in6 baddr;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));

r = uv_udp_init(uv_default_loop(), &server);
@@ -103,6 +103,9 @@ TEST_IMPL(udp_multicast_join6) {
uv_buf_t buf;
struct sockaddr_in6 addr;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));

r = uv_udp_init(uv_default_loop(), &server);
@@ -27,23 +27,20 @@
#include <string.h>


TEST_IMPL(udp_options) {
static int udp_options_test(const struct sockaddr* addr) {
static int invalid_ttls[] = { -1, 0, 256 };
struct sockaddr_in addr;
uv_loop_t* loop;
uv_udp_t h;
int i, r;

ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));

loop = uv_default_loop();

r = uv_udp_init(loop, &h);
ASSERT(r == 0);

uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */

r = uv_udp_bind(&h, (const struct sockaddr*) &addr, 0);
r = uv_udp_bind(&h, addr, 0);
ASSERT(r == 0);

r = uv_udp_set_broadcast(&h, 1);
@@ -88,6 +85,25 @@ TEST_IMPL(udp_options) {
}


TEST_IMPL(udp_options) {
struct sockaddr_in addr;

ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
return udp_options_test((const struct sockaddr*) &addr);
}


TEST_IMPL(udp_options6) {
struct sockaddr_in6 addr;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr));
return udp_options_test((const struct sockaddr*) &addr);
}


TEST_IMPL(udp_no_autobind) {
uv_loop_t* loop;
uv_udp_t h;
@@ -17,28 +17,8 @@
}],
],
'xcode_settings': {
'conditions': [
[ 'clang==1', {
'WARNING_CFLAGS': [
'-Wall',
'-Wextra',
'-Wno-unused-parameter',
'-Wno-dollar-in-identifier-extension'
]}, {
'WARNING_CFLAGS': [
'-Wall',
'-Wextra',
'-Wno-unused-parameter'
]}
]
],
'OTHER_LDFLAGS': [
],
'OTHER_CFLAGS': [
'-g',
'--std=gnu89',
'-pedantic'
],
'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter' ],
'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ],
}
},

@@ -221,6 +201,7 @@
'cflags': [ '-Wstrict-aliasing' ],
}],
[ 'OS=="linux"', {
'defines': [ '_GNU_SOURCE' ],
'sources': [
'src/unix/linux-core.c',
'src/unix/linux-inotify.c',
@@ -341,6 +322,7 @@
'test/test-loop-close.c',
'test/test-loop-stop.c',
'test/test-loop-time.c',
'test/test-loop-configure.c',
'test/test-walk-handles.c',
'test/test-watcher-cross-stop.c',
'test/test-multiple-listen.c',
@@ -353,9 +335,11 @@
'test/test-pipe-sendmsg.c',
'test/test-pipe-server-close.c',
'test/test-pipe-close-stdout-read-stdin.c',
'test/test-pipe-set-non-blocking.c',
'test/test-platform-output.c',
'test/test-poll.c',
'test/test-poll-close.c',
'test/test-poll-close-doesnt-corrupt-stack.c',
'test/test-poll-closesocket.c',
'test/test-process-title.c',
'test/test-ref.c',
@@ -426,6 +426,24 @@ CryptoStream.prototype.end = function(chunk, encoding) {
stream.Duplex.prototype.end.call(this, chunk, encoding);
};

/*
* Wait for both `finish` and `end` events to ensure that all data that
* was written on this side was read from the other side.
*/
function _destroyWhenReadAndWriteEndsDone(cryptoStream) {
var waiting = 1;

function finish() {
if (--waiting === 0) cryptoStream.destroy();
}

cryptoStream._opposite.once('end', finish);

if (!cryptoStream._finished) {
cryptoStream.once('finish', finish);
++waiting;
}
}

CryptoStream.prototype.destroySoon = function(err) {
if (this === this.pair.cleartext) {
@@ -440,18 +458,7 @@ CryptoStream.prototype.destroySoon = function(err) {
if (this._writableState.finished && this._opposite._ended) {
this.destroy();
} else {
// Wait for both `finish` and `end` events to ensure that all data that
// was written on this side was read from the other side.
var self = this;
var waiting = 1;
function finish() {
if (--waiting === 0) self.destroy();
}
this._opposite.once('end', finish);
if (!this._finished) {
this.once('finish', finish);
++waiting;
}
_destroyWhenReadAndWriteEndsDone(this);
}
};

@@ -586,6 +586,13 @@ exports._forkChild = function(fd) {
// set process.send()
var p = createPipe(true);
p.open(fd);

// p.open() puts the file descriptor in non-blocking mode
// but it must be synchronous for backwards compatibility.
var err = p.setBlocking(true);
if (err)
throw errnoException(err, 'setBlocking');

p.unref();
setupChannel(process, p);

@@ -89,13 +89,13 @@ Console.prototype.timeEnd = function(label) {
};


Console.prototype.trace = function() {
Console.prototype.trace = function trace() {
// TODO probably can to do this better with V8's debug object once that is
// exposed.
var err = new Error;
err.name = 'Trace';
err.message = util.format.apply(this, arguments);
Error.captureStackTrace(err, arguments.callee);
Error.captureStackTrace(err, trace);
this.error(err.stack);
};

@@ -592,20 +592,22 @@ exports.pbkdf2Sync = function(password, salt, iterations, keylen, digest) {


function pbkdf2(password, salt, iterations, keylen, digest, callback) {
var encoding = exports.DEFAULT_ENCODING;

function next(er, ret) {
if (ret)
ret = ret.toString(encoding);
callback(er, ret);
}

password = toBuf(password);
salt = toBuf(salt);

if (exports.DEFAULT_ENCODING === 'buffer')
if (encoding === 'buffer')
return binding.PBKDF2(password, salt, iterations, keylen, digest, callback);

// at this point, we need to handle encodings.
var encoding = exports.DEFAULT_ENCODING;
if (callback) {
function next(er, ret) {
if (ret)
ret = ret.toString(encoding);
callback(er, ret);
}
binding.PBKDF2(password, salt, iterations, keylen, digest, next);
} else {
var ret = binding.PBKDF2(password, salt, iterations, keylen, digest);
@@ -155,9 +155,9 @@ function Socket(options) {
} else if (!util.isUndefined(options.fd)) {
this._handle = createHandle(options.fd);
this._handle.open(options.fd);
if ((options.fd == 1 || options.fd == 2) &&
(this._handle instanceof Pipe) &&
process.platform === 'win32') {
// this._handle.open() puts the file descriptor in non-blocking
// mode but it must be synchronous for backwards compatibility.
if ((options.fd == 1 || options.fd == 2) && this._handle instanceof Pipe) {
// Make stdout and stderr blocking on Windows
var err = this._handle.setBlocking(true);
if (err)
@@ -0,0 +1,44 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.

var common = require('../common');
var assert = require('assert');
var fork = require('child_process').fork;
var N = 4 << 20; // 4 MB

for (var big = '*'; big.length < N; big += big);

if (process.argv[2] === 'child') {
process.send(big);
process.exit(42);
}

var proc = fork(__filename, ['child']);

proc.on('message', common.mustCall(function(msg) {
assert.equal(typeof msg, 'string');
assert.equal(msg.length, N);
assert.equal(msg, big);
}));

proc.on('exit', common.mustCall(function(exitCode) {
assert.equal(exitCode, 42);
}));
@@ -49,8 +49,9 @@ server.listen(common.PORT, function() {
req.end();
test();
} else {
timer = setImmediate(write);
req.write('hello');
req.write('hello', function() {
timer = setImmediate(write);
});
}
}

@@ -0,0 +1,44 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.

var common = require('../common');
var assert = require('assert');
var spawn = require('child_process').spawn;
var N = 4 << 20; // 4 MB

for (var big = '*'; big.length < N; big += big);

if (process.argv[2] === 'child') {
process.stdout.write(big);
process.exit(42);
}

var stdio = ['inherit', 'pipe', 'inherit'];
var proc = spawn(process.execPath, [__filename, 'child'], { stdio: stdio });

var chunks = [];
proc.stdout.setEncoding('utf8');
proc.stdout.on('data', chunks.push.bind(chunks));

proc.on('exit', common.mustCall(function(exitCode) {
assert.equal(exitCode, 42);
assert.equal(chunks.join(''), big);
}));
@@ -0,0 +1,34 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.

/*
* This test makes sure that every builtin module can be loaded
* when the V8's --use-strict command line option is passed to node.
*/

var child_process = require('child_process');

if (process.argv[2] !== 'child') {
child_process.fork(__filename, ['child'], { execArgv: ['--use-strict']});
} else {
var natives = process.binding('natives');
Object.keys(natives).forEach(require);
}