@@ -25,6 +25,7 @@ TEST_DECLARE (close_order)
TEST_DECLARE (run_once)
TEST_DECLARE (run_nowait)
TEST_DECLARE (loop_alive)
TEST_DECLARE (loop_close)
TEST_DECLARE (loop_stop)
TEST_DECLARE (loop_update_time)
TEST_DECLARE (barrier_1)
@@ -81,6 +82,7 @@ TEST_DECLARE (tcp_bind6_localhost_ok)
TEST_DECLARE (udp_send_and_recv)
TEST_DECLARE (udp_multicast_join)
TEST_DECLARE (udp_multicast_ttl)
TEST_DECLARE (udp_multicast_interface)
TEST_DECLARE (udp_dgram_too_big)
TEST_DECLARE (udp_dual_stack)
TEST_DECLARE (udp_ipv6_only)
@@ -92,12 +94,15 @@ 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_getsockname)
TEST_DECLARE (pipe_getsockname_abstract)
TEST_DECLARE (pipe_server_close)
TEST_DECLARE (connection_fail)
TEST_DECLARE (connection_fail_doesnt_auto_close)
TEST_DECLARE (shutdown_close_tcp)
TEST_DECLARE (shutdown_close_pipe)
TEST_DECLARE (shutdown_eof)
TEST_DECLARE (shutdown_twice)
TEST_DECLARE (callback_stack)
TEST_DECLARE (error_message)
TEST_DECLARE (timer)
@@ -171,6 +176,7 @@ TEST_DECLARE (spawn_stdout_to_file)
TEST_DECLARE (spawn_stdout_and_stderr_to_file)
TEST_DECLARE (spawn_auto_unref)
TEST_DECLARE (fs_poll)
TEST_DECLARE (fs_poll_getpath)
TEST_DECLARE (kill)
TEST_DECLARE (fs_file_noent)
TEST_DECLARE (fs_file_nametoolong)
@@ -202,6 +208,7 @@ TEST_DECLARE (fs_event_close_with_pending_event)
TEST_DECLARE (fs_event_close_in_callback)
TEST_DECLARE (fs_event_start_and_close)
TEST_DECLARE (fs_event_error_reporting)
TEST_DECLARE (fs_event_getpath)
TEST_DECLARE (fs_readdir_empty_dir)
TEST_DECLARE (fs_readdir_file)
TEST_DECLARE (fs_open_dir)
@@ -233,10 +240,12 @@ TEST_DECLARE (fs_stat_root)
#else
TEST_DECLARE (emfile)
TEST_DECLARE (close_fd)
TEST_DECLARE (spawn_fs_open)
TEST_DECLARE (spawn_setuid_setgid)
TEST_DECLARE (we_get_signal)
TEST_DECLARE (we_get_signals)
TEST_DECLARE (signal_multiple_loops)
TEST_DECLARE (closed_fd_events)
#endif
#ifdef __APPLE__
TEST_DECLARE (osx_select)
@@ -248,7 +257,7 @@ HELPER_DECLARE (pipe_echo_server)


TASK_LIST_START
TEST_OUTPUT_ENTRY (platform_output)
TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000)

#if 0
TEST_ENTRY (callback_order)
@@ -257,6 +266,7 @@ TASK_LIST_START
TEST_ENTRY (run_once)
TEST_ENTRY (run_nowait)
TEST_ENTRY (loop_alive)
TEST_ENTRY (loop_close)
TEST_ENTRY (loop_stop)
TEST_ENTRY (loop_update_time)
TEST_ENTRY (barrier_1)
@@ -349,6 +359,8 @@ TASK_LIST_START
TEST_ENTRY (pipe_bind_error_addrnotavail)
TEST_ENTRY (pipe_bind_error_inval)
TEST_ENTRY (pipe_listen_without_bind)
TEST_ENTRY (pipe_getsockname)
TEST_ENTRY (pipe_getsockname_abstract)

TEST_ENTRY (connection_fail)
TEST_ENTRY (connection_fail_doesnt_auto_close)
@@ -361,6 +373,9 @@ TASK_LIST_START
TEST_ENTRY (shutdown_eof)
TEST_HELPER (shutdown_eof, tcp4_echo_server)

TEST_ENTRY (shutdown_twice)
TEST_HELPER (shutdown_twice, tcp4_echo_server)

TEST_ENTRY (callback_stack)
TEST_HELPER (callback_stack, tcp4_echo_server)

@@ -432,7 +447,8 @@ TASK_LIST_START

TEST_ENTRY (hrtime)

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

TEST_ENTRY (getaddrinfo_basic)
TEST_ENTRY (getaddrinfo_concurrent)

@@ -460,6 +476,7 @@ TASK_LIST_START
TEST_ENTRY (spawn_stdout_and_stderr_to_file)
TEST_ENTRY (spawn_auto_unref)
TEST_ENTRY (fs_poll)
TEST_ENTRY (fs_poll_getpath)
TEST_ENTRY (kill)

#ifdef _WIN32
@@ -472,10 +489,12 @@ TASK_LIST_START
#else
TEST_ENTRY (emfile)
TEST_ENTRY (close_fd)
TEST_ENTRY (spawn_fs_open)
TEST_ENTRY (spawn_setuid_setgid)
TEST_ENTRY (we_get_signal)
TEST_ENTRY (we_get_signals)
TEST_ENTRY (signal_multiple_loops)
TEST_ENTRY (closed_fd_events)
#endif

#ifdef __APPLE__
@@ -511,6 +530,7 @@ TASK_LIST_START
TEST_ENTRY (fs_event_close_in_callback)
TEST_ENTRY (fs_event_start_and_close)
TEST_ENTRY (fs_event_error_reporting)
TEST_ENTRY (fs_event_getpath)
TEST_ENTRY (fs_readdir_empty_dir)
TEST_ENTRY (fs_readdir_file)
TEST_ENTRY (fs_open_dir)
@@ -0,0 +1,54 @@
/* Copyright Joyent, Inc. and other Node 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.
*/

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

static uv_timer_t timer_handle;

static void timer_cb(uv_timer_t* handle, int status) {
ASSERT(handle);
ASSERT(status == 0);
uv_stop(handle->loop);
}


TEST_IMPL(loop_close) {
int r;
uv_loop_t loop;

ASSERT(0 == uv_loop_init(&loop));

uv_timer_init(&loop, &timer_handle);
uv_timer_start(&timer_handle, timer_cb, 100, 100);

ASSERT(UV_EBUSY == uv_loop_close(&loop));

uv_run(&loop, UV_RUN_DEFAULT);

uv_close((uv_handle_t*) &timer_handle, NULL);
r = uv_run(&loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

ASSERT(0 == uv_loop_close(&loop));

return 0;
}
@@ -0,0 +1,122 @@
/* Copyright Joyent, Inc. and other Node 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.
*/

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

#if defined(__linux__)
#include <sys/socket.h>
#include <sys/un.h>
#endif

#ifndef _WIN32
# include <unistd.h> /* close */
#endif


static int close_cb_called = 0;


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


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

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

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

ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);

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

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

ASSERT(close_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(pipe_getsockname_abstract) {
#if defined(__linux__)
uv_pipe_t server;
char buf[1024];
size_t len;
int r;
int sock;
struct sockaddr_un sun;
socklen_t sun_len;
char abstract_pipe[] = "\0test-pipe";

sock = socket(AF_LOCAL, SOCK_STREAM, 0);
ASSERT(sock != -1);

sun_len = sizeof sun;
memset(&sun, 0, sun_len);
sun.sun_family = AF_UNIX;
memcpy(sun.sun_path, abstract_pipe, sizeof abstract_pipe);

r = bind(sock, (struct sockaddr*)&sun, sun_len);
ASSERT(r == 0);

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

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

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

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

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

close(sock);

ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
#else
MAKE_VALGRIND_HAPPY();
return 0;
#endif
}

@@ -28,6 +28,7 @@ TEST_IMPL(platform_output) {
char buffer[512];
size_t rss;
double uptime;
uv_rusage_t rusage;
uv_cpu_info_t* cpus;
uv_interface_address_t* interfaces;
int count;
@@ -47,6 +48,20 @@ TEST_IMPL(platform_output) {
ASSERT(uptime > 0);
printf("uv_uptime: %f\n", uptime);

err = uv_getrusage(&rusage);
ASSERT(err == 0);
ASSERT(rusage.ru_utime.tv_sec >= 0);
ASSERT(rusage.ru_utime.tv_usec >= 0);
ASSERT(rusage.ru_stime.tv_sec >= 0);
ASSERT(rusage.ru_stime.tv_usec >= 0);
printf("uv_getrusage:\n");
printf(" user: %llu sec %llu microsec\n",
(unsigned long long) rusage.ru_utime.tv_sec,
(unsigned long long) rusage.ru_utime.tv_usec);
printf(" system: %llu sec %llu microsec\n",
(unsigned long long) rusage.ru_stime.tv_sec,
(unsigned long long) rusage.ru_stime.tv_usec);

err = uv_cpu_info(&cpus, &count);
ASSERT(err == 0);

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

/*
* This is a regression test for issue #1113 (calling uv_shutdown twice will
* leave a ghost request in the system)
*/

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

static uv_shutdown_t req1;
static uv_shutdown_t req2;

static int shutdown_cb_called = 0;

static void close_cb(uv_handle_t* handle) {

}

static void shutdown_cb(uv_shutdown_t* req, int status) {
ASSERT(req == &req1);
ASSERT(status == 0);
shutdown_cb_called++;
uv_close((uv_handle_t*) req->handle, close_cb);
}

static void connect_cb(uv_connect_t* req, int status) {
int r;

ASSERT(status == 0);

r = uv_shutdown(&req1, req->handle, shutdown_cb);
ASSERT(r == 0);
r = uv_shutdown(&req2, req->handle, shutdown_cb);
ASSERT(r != 0);

}

TEST_IMPL(shutdown_twice) {
struct sockaddr_in addr;
uv_loop_t* loop;
int r;
uv_tcp_t h;

uv_connect_t connect_req;

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

r = uv_tcp_init(loop, &h);

r = uv_tcp_connect(&connect_req,
&h,
(const struct sockaddr*) &addr,
connect_cb);
ASSERT(r == 0);

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

ASSERT(shutdown_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}
@@ -84,28 +84,27 @@ static void signal_handling_worker(void* context) {
uv_signal_t signal1a;
uv_signal_t signal1b;
uv_signal_t signal2;
uv_loop_t* loop;
uv_loop_t loop;
int r;

action = (enum signal_action) (uintptr_t) context;

loop = uv_loop_new();
ASSERT(loop != NULL);
ASSERT(0 == uv_loop_init(&loop));

/* Setup the signal watchers and start them. */
if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {
r = uv_signal_init(loop, &signal1a);
r = uv_signal_init(&loop, &signal1a);
ASSERT(r == 0);
r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);
ASSERT(r == 0);
r = uv_signal_init(loop, &signal1b);
r = uv_signal_init(&loop, &signal1b);
ASSERT(r == 0);
r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);
ASSERT(r == 0);
}

if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {
r = uv_signal_init(loop, &signal2);
r = uv_signal_init(&loop, &signal2);
ASSERT(r == 0);
r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);
ASSERT(r == 0);
@@ -117,7 +116,7 @@ static void signal_handling_worker(void* context) {
/* Wait for all signals. The signal callbacks stop the watcher, so uv_run
* will return when all signal watchers caught a signal.
*/
r = uv_run(loop, UV_RUN_DEFAULT);
r = uv_run(&loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

/* Restart the signal watchers. */
@@ -136,7 +135,7 @@ static void signal_handling_worker(void* context) {
/* Wait for signals once more. */
uv_sem_post(&sem);

r = uv_run(loop, UV_RUN_DEFAULT);
r = uv_run(&loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

/* Close the watchers. */
@@ -150,10 +149,10 @@ static void signal_handling_worker(void* context) {
}

/* Wait for the signal watchers to close. */
r = uv_run(loop, UV_RUN_DEFAULT);
r = uv_run(&loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

uv_loop_delete(loop);
uv_loop_close(&loop);
}


@@ -166,12 +165,13 @@ static void loop_creating_worker(void* context) {
(void) context;

do {
uv_loop_t* loop;
uv_loop_t *loop;
uv_signal_t signal;
int r;

loop = uv_loop_new();
loop = malloc(sizeof(*loop));
ASSERT(loop != NULL);
ASSERT(0 == uv_loop_init(loop));

r = uv_signal_init(loop, &signal);
ASSERT(r == 0);
@@ -184,7 +184,7 @@ static void loop_creating_worker(void* context) {
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

uv_loop_delete(loop);
uv_loop_close(loop);

increment_counter(&loop_creation_counter);
} while (!stop);
@@ -40,6 +40,7 @@ static char exepath[1024];
static size_t exepath_size = 1024;
static char* args[3];
static int no_term_signal;
static int timer_counter;

#define OUTPUT_SIZE 1024
static char output[OUTPUT_SIZE];
@@ -118,6 +119,12 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
}


static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
uv_read_stop(tcp);
on_read(tcp, nread, buf);
}


static void write_cb(uv_write_t* req, int status) {
ASSERT(status == 0);
uv_close((uv_handle_t*)req->handle, close_cb);
@@ -145,6 +152,11 @@ static void timer_cb(uv_timer_t* handle, int status) {
}


static void timer_counter_cb(uv_timer_t* handle, int status) {
++timer_counter;
}


TEST_IMPL(spawn_fails) {
int r;

@@ -218,6 +230,7 @@ TEST_IMPL(spawn_stdout_to_file) {
uv_file file;
uv_fs_t fs_req;
uv_stdio_container_t stdio[2];
uv_buf_t buf;

/* Setup. */
unlink("stdout_file");
@@ -246,8 +259,8 @@ TEST_IMPL(spawn_stdout_to_file) {
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);

r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output),
0, NULL);
buf = uv_buf_init(output, sizeof(output));
r = uv_fs_read(uv_default_loop(), &fs_req, file, &buf, 1, 0, NULL);
ASSERT(r == 12);
uv_fs_req_cleanup(&fs_req);

@@ -271,14 +284,15 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) {
uv_file file;
uv_fs_t fs_req;
uv_stdio_container_t stdio[3];
uv_buf_t buf;

/* Setup. */
unlink("stdout_file");

init_process_options("spawn_helper6", exit_cb);

r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR,
S_IREAD | S_IWRITE, NULL);
S_IRUSR | S_IWUSR, NULL);
ASSERT(r != -1);
uv_fs_req_cleanup(&fs_req);

@@ -301,8 +315,8 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) {
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);

r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output),
0, NULL);
buf = uv_buf_init(output, sizeof(output));
r = uv_fs_read(uv_default_loop(), &fs_req, file, &buf, 1, 0, NULL);
ASSERT(r == 27);
uv_fs_req_cleanup(&fs_req);

@@ -1049,3 +1063,102 @@ TEST_IMPL(spawn_auto_unref) {
MAKE_VALGRIND_HAPPY();
return 0;
}


#ifndef _WIN32
TEST_IMPL(spawn_fs_open) {
int fd;
uv_fs_t fs_req;
uv_pipe_t in;
uv_write_t write_req;
uv_buf_t buf;
uv_stdio_container_t stdio[1];

fd = uv_fs_open(uv_default_loop(), &fs_req, "/dev/null", O_RDWR, 0, NULL);
ASSERT(fd >= 0);

init_process_options("spawn_helper8", exit_cb);

ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0));

options.stdio = stdio;
options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
options.stdio[0].data.stream = (uv_stream_t*) &in;
options.stdio_count = 1;

ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));

buf = uv_buf_init((char*) &fd, sizeof(fd));
ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));

ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(0 == uv_fs_close(uv_default_loop(), &fs_req, fd, NULL));

ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 2); /* One for `in`, one for process */

MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* !_WIN32 */


#ifndef _WIN32
TEST_IMPL(closed_fd_events) {
uv_stdio_container_t stdio[3];
uv_pipe_t pipe_handle;
int fd[2];

/* 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);
options.stdio_count = 3;
options.stdio = stdio;
options.stdio[0].flags = UV_INHERIT_FD;
options.stdio[0].data.fd = fd[0];
options.stdio[1].flags = UV_IGNORE;
options.stdio[2].flags = UV_IGNORE;

ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
uv_unref((uv_handle_t*) &process);

/* read from the pipe with uv */
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
fd[0] = -1;

ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once));

ASSERT(1 == write(fd[1], "", 1));

ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));

/* should have received just one byte */
ASSERT(output_used == 1);

/* close the pipe and see if we still get events */
uv_close((uv_handle_t*) &pipe_handle, close_cb);

ASSERT(1 == write(fd[1], "", 1));

ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0));

/* see if any spurious events interrupt the timer */
if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE))
/* have to run again to really trigger the timer */
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));

ASSERT(timer_counter == 1);

/* cleanup */
ASSERT(0 == uv_process_kill(&process, /* SIGTERM */ 15));
ASSERT(0 == close(fd[1]));

MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* !_WIN32 */
@@ -112,8 +112,9 @@ static void do_work(void* arg) {
int r;
struct test_thread* thread = arg;

loop = uv_loop_new();
loop = malloc(sizeof *loop);
ASSERT(loop != NULL);
ASSERT(0 == uv_loop_init(loop));

for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) {
struct getaddrinfo_req* req = getaddrinfo_reqs + i;
@@ -132,7 +133,8 @@ static void do_work(void* arg) {
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

uv_loop_delete(loop);
ASSERT(0 == uv_loop_close(loop));
free(loop);
thread->thread_called = 1;
}

@@ -86,7 +86,7 @@ static void saturate_threadpool(void) {
* the thread pool is saturated. As with any timing dependent test,
* this is obviously not ideal.
*/
if (uv_cond_timedwait(&signal_cond, &signal_mutex, 350 * 1e6)) {
if (uv_cond_timedwait(&signal_cond, &signal_mutex, (uint64_t)(350 * 1e6))) {
ASSERT(0 == uv_cancel((uv_req_t*) req));
break;
}
@@ -0,0 +1,96 @@
/* Copyright Joyent, Inc. and other Node 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.
*/

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CHECK_HANDLE(handle) \
ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)

static uv_udp_t server;
static uv_udp_t client;

static int sv_send_cb_called;
static int close_cb_called;


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


static void sv_send_cb(uv_udp_send_t* req, int status) {
ASSERT(req != NULL);
ASSERT(status == 0);
CHECK_HANDLE(req->handle);

sv_send_cb_called++;

uv_close((uv_handle_t*) req->handle, close_cb);
}


TEST_IMPL(udp_multicast_interface) {
int r;
uv_udp_send_t req;
uv_buf_t buf;
struct sockaddr_in addr;
struct sockaddr_in baddr;

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

r = uv_udp_init(uv_default_loop(), &server);
ASSERT(r == 0);

ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &baddr));
r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0);
ASSERT(r == 0);

r = uv_udp_set_multicast_interface(&server, "0.0.0.0");
ASSERT(r == 0);

/* server sends "PING" */
buf = uv_buf_init("PING", 4);
r = uv_udp_send(&req,
&server,
&buf,
1,
(const struct sockaddr*)&addr,
sv_send_cb);
ASSERT(r == 0);

ASSERT(close_cb_called == 0);
ASSERT(sv_send_cb_called == 0);

/* run the loop till all events are processed */
uv_run(uv_default_loop(), UV_RUN_DEFAULT);

ASSERT(sv_send_cb_called == 1);
ASSERT(close_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}
@@ -31,7 +31,7 @@
'targets': [
{
'target_name': 'libuv',
'type': '<(library)',
'type': '<(uv_library)',
'include_dirs': [
'include',
'src/',
@@ -61,7 +61,9 @@
'include/uv.h',
'include/tree.h',
'include/uv-errno.h',
'include/uv-version.h',
'src/fs-poll.c',
'src/heap-inl.h',
'src/inet.c',
'src/queue.h',
'src/uv-common.c',
@@ -167,10 +169,10 @@
],
},
'conditions': [
['library=="shared_library"', {
['uv_library=="shared_library"', {
'cflags': [ '-fPIC' ],
}],
['library=="shared_library" and OS!="mac"', {
['uv_library=="shared_library" and OS!="mac"', {
'link_settings': {
# Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR
# in src/version.c
@@ -265,7 +267,7 @@
[ 'OS in "mac freebsd dragonflybsd openbsd netbsd".split()', {
'sources': [ 'src/unix/kqueue.c' ],
}],
['library=="shared_library"', {
['uv_library=="shared_library"', {
'defines': [ 'BUILDING_UV_SHARED=1' ]
}],
# FIXME(bnoordhuis or tjfontaine) Unify this, it's extremely ugly.
@@ -324,6 +326,7 @@
'test/test-list.h',
'test/test-loop-handles.c',
'test/test-loop-alive.c',
'test/test-loop-close.c',
'test/test-loop-stop.c',
'test/test-loop-time.c',
'test/test-walk-handles.c',
@@ -334,6 +337,7 @@
'test/test-ping-pong.c',
'test/test-pipe-bind-error.c',
'test/test-pipe-connect-error.c',
'test/test-pipe-getsockname.c',
'test/test-pipe-server-close.c',
'test/test-platform-output.c',
'test/test-poll.c',
@@ -345,6 +349,7 @@
'test/test-semaphore.c',
'test/test-shutdown-close.c',
'test/test-shutdown-eof.c',
'test/test-shutdown-twice.c',
'test/test-signal.c',
'test/test-signal-multiple-loops.c',
'test/test-spawn.c',
@@ -387,6 +392,7 @@
'test/test-udp-multicast-ttl.c',
'test/test-ip4-addr.c',
'test/test-ip6-addr.c',
'test/test-udp-multicast-interface.c',
],
'conditions': [
[ 'OS=="win"', {
@@ -33,14 +33,17 @@ if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok
if /i "%1"=="nobuild" set nobuild=1&goto arg-ok
if /i "%1"=="x86" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok
if /i "%1"=="ia32" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok
if /i "%1"=="x64" set target_arch=x64&set platform=amd64&set vs_toolset=x64&goto arg-ok
if /i "%1"=="x64" set target_arch=x64&set platform=x64&set vs_toolset=x64&goto arg-ok
if /i "%1"=="shared" set library=shared_library&goto arg-ok
if /i "%1"=="static" set library=static_library&goto arg-ok
:arg-ok
shift
goto next-arg
:args-done

if defined WindowsSDKDir goto select-target
if defined VCINSTALLDIR goto select-target

@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
@@ -99,7 +102,7 @@ exit /b 1

:have_gyp
if not defined PYTHON set PYTHON="python"
%PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Dlibrary=%library%
%PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library%
if errorlevel 1 goto create-msvs-files-failed
if not exist uv.sln goto create-msvs-files-failed
echo Project files generated.
@@ -109,10 +112,8 @@ echo Project files generated.
if defined nobuild goto run

@rem Check if VS build env is available
if not defined VCINSTALLDIR goto msbuild-not-found
goto msbuild-found

:msbuild-not-found
if defined VCINSTALLDIR goto msbuild-found
if defined WindowsSDKDir goto msbuild-found
echo Build skipped. To build, this file needs to run from VS cmd prompt.
goto run

@@ -20,10 +20,8 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var net = require('net');
var url = require('url');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var ClientRequest = require('_http_client').ClientRequest;
var debug = util.debuglog('http');

// New Agent code.
@@ -267,44 +265,4 @@ Agent.prototype.destroy = function() {
});
};

Agent.prototype.request = function(options, cb) {
if (util.isString(options)) {
options = url.parse(options);
}
// don't try to do dns lookups of foo.com:8080, just foo.com
if (options.hostname) {
options.host = options.hostname;
}

if (options && options.path && / /.test(options.path)) {
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
// with an additional rule for ignoring percentage-escaped characters
// but that's a) hard to capture in a regular expression that performs
// well, and b) possibly too restrictive for real-world usage. That's
// why it only scans for spaces because those are guaranteed to create
// an invalid request.
throw new TypeError('Request path contains unescaped characters.');
} else if (options.protocol && options.protocol !== this.protocol) {
throw new Error('Protocol:' + options.protocol + ' not supported.');
}

options = util._extend({
agent: this,
keepAlive: this.keepAlive
}, options);

// if it's false, then make a new one, just like this one.
if (options.agent === false)
options.agent = new this.constructor();

debug('agent.request', options);
return new ClientRequest(options, cb);
};

Agent.prototype.get = function(options, cb) {
var req = this.request(options, cb);
req.end();
return req;
};

exports.globalAgent = new Agent();
@@ -21,6 +21,7 @@

var util = require('util');
var net = require('net');
var url = require('url');
var EventEmitter = require('events').EventEmitter;
var HTTPParser = process.binding('http_parser').HTTPParser;
var assert = require('assert').ok;
@@ -35,17 +36,39 @@ var debug = common.debug;
var IncomingMessage = require('_http_incoming').IncomingMessage;
var OutgoingMessage = require('_http_outgoing').OutgoingMessage;

var agent = require('_http_agent');
var globalAgent = agent.globalAgent;
var Agent = require('_http_agent');


function ClientRequest(options, cb) {
var self = this;
OutgoingMessage.call(self);

options = util._extend({}, options);
if (util.isString(options)) {
options = url.parse(options);
} else {
options = util._extend({}, options);
}

self.agent = util.isUndefined(options.agent) ? globalAgent : options.agent;
var agent = options.agent;
var defaultAgent = options._defaultAgent || Agent.globalAgent;
if (agent === false) {
agent = new defaultAgent.constructor();
} else if (util.isNullOrUndefined(agent)) {
agent = defaultAgent;
}
self.agent = agent;

if (options.path && / /.test(options.path)) {
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
// with an additional rule for ignoring percentage-escaped characters
// but that's a) hard to capture in a regular expression that performs
// well, and b) possibly too restrictive for real-world usage. That's
// why it only scans for spaces because those are guaranteed to create
// an invalid request.
throw new TypeError('Request path contains unescaped characters.');
} else if (options.protocol && options.protocol !== self.agent.protocol) {
throw new Error('Protocol:' + options.protocol + ' not supported.');
}

var defaultPort = options.defaultPort || self.agent.defaultPort;

@@ -114,8 +137,7 @@ function ClientRequest(options, cb) {
// but only if the Agent will actually reuse the connection!
// If it's not a keepAlive agent, and the maxSockets==Infinity, then
// there's never a case where this socket will actually be reused
var agent = self.agent;
if (!agent.keepAlive && !Number.isFinite(agent.maxSockets)) {
if (!self.agent.keepAlive && !Number.isFinite(self.agent.maxSockets)) {
self._last = true;
self.shouldKeepAlive = false;
} else {
@@ -80,18 +80,6 @@ function Credentials(secureProtocol, flags, context) {

exports.Credentials = Credentials;

function addNewline(buf) {
var last = buf[buf.length - 1];
var isBuf = Buffer.isBuffer(buf);

if (!isBuf && !util.isString(buf))
throw new Error('Certificate should be of type Buffer or string');

if (isBuf ? last !== 10 : last !== '\n')
return buf.toString().trim() + '\n';
else
return buf;
}

exports.createCredentials = function(options, context) {
if (!options) options = {};
@@ -103,15 +91,14 @@ exports.createCredentials = function(options, context) {
if (context) return c;

if (options.key) {
var key = addNewline(options.key);
if (options.passphrase) {
c.context.setKey(key, options.passphrase);
c.context.setKey(options.key, options.passphrase);
} else {
c.context.setKey(key);
c.context.setKey(options.key);
}
}

if (options.cert) c.context.setCert(addNewline(options.cert));
if (options.cert) c.context.setCert(options.cert);

if (options.ciphers) c.context.setCiphers(options.ciphers);

@@ -49,11 +49,13 @@ var client = require('_http_client');
var ClientRequest = exports.ClientRequest = client.ClientRequest;

exports.request = function(options, cb) {
return globalAgent.request(options, cb);
return new ClientRequest(options, cb);
};

exports.get = function(options, cb) {
return globalAgent.get(options, cb);
var req = exports.request(options, cb);
req.end();
return req;
};

exports._connectionListener = server._connectionListener;
@@ -20,6 +20,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var tls = require('tls');
var url = require('url');
var http = require('http');
var util = require('util');
var inherits = require('util').inherits;
@@ -126,9 +127,17 @@ exports.globalAgent = globalAgent;
exports.Agent = Agent;

exports.request = function(options, cb) {
return globalAgent.request(options, cb);
if (util.isString(options)) {
options = url.parse(options);
} else {
options = util._extend({}, options);
}
options._defaultAgent = globalAgent;
return http.request(options, cb);
};

exports.get = function(options, cb) {
return globalAgent.get(options, cb);
var req = exports.request(options, cb);
req.end();
return req;
};
@@ -26,6 +26,8 @@ var util = require('util');
var assert = require('assert');
var cares = process.binding('cares_wrap');
var uv = process.binding('uv');
var Pipe = process.binding('pipe_wrap').Pipe;


var cluster;
var errnoException = util._errnoException;
@@ -34,7 +36,6 @@ function noop() {}

// constructor for lazy loading
function createPipe() {
var Pipe = process.binding('pipe_wrap').Pipe;
return new Pipe();
}

@@ -147,6 +148,14 @@ 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') {
// Make stdout and stderr blocking on Windows
var err = this._handle.setBlocking(true);
if (err)
throw errnoException(err, 'setBlocking');
}
this.readable = options.readable !== false;
this.writable = options.writable !== false;
} else {
@@ -145,8 +145,8 @@ int NodeBIO::Gets(BIO* bio, char* out, int size) {

int i = nbio->IndexOf('\n', size);

// Include '\n'
if (i < size)
// Include '\n', if it's there. If not, don't read off the end.
if (i < size && i >= 0 && static_cast<size_t>(i) < nbio->Length())
i++;

// Shift `i` a bit to NULL-terminate string later
@@ -769,12 +769,14 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {

buf += off;

uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);

if (cb->IsFunction()) {
ASYNC_CALL(write, cb, fd, buf, len, pos)
ASYNC_CALL(write, cb, fd, &uvbuf, 1, pos)
return;
}

SYNC_CALL(write, NULL, fd, buf, len, pos)
SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos)
args.GetReturnValue().Set(SYNC_RESULT);
}

@@ -818,8 +820,10 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
pos = GET_OFFSET(args[2]);
cb = args[4];

uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);

if (!cb->IsFunction()) {
SYNC_CALL(write, NULL, fd, buf, len, pos)
SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos)
if (must_free)
delete[] buf;
return args.GetReturnValue().Set(SYNC_RESULT);
@@ -829,8 +833,8 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
int err = uv_fs_write(env->event_loop(),
&req_wrap->req_,
fd,
buf,
len,
&uvbuf,
1,
pos,
After);
req_wrap->object()->Set(env->oncomplete_string(), cb);
@@ -896,12 +900,14 @@ static void Read(const FunctionCallbackInfo<Value>& args) {

buf = buffer_data + off;

uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);

cb = args[5];

if (cb->IsFunction()) {
ASYNC_CALL(read, cb, fd, buf, len, pos);
ASYNC_CALL(read, cb, fd, &uvbuf, 1, pos);
} else {
SYNC_CALL(read, 0, fd, buf, len, pos)
SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
args.GetReturnValue().Set(SYNC_RESULT);
}
}
@@ -91,6 +91,8 @@ void PipeWrap::Initialize(Handle<Object> target,
NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref);
NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref);

NODE_SET_PROTOTYPE_METHOD(t, "setBlocking", StreamWrap::SetBlocking);

NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart);
NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop);
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", StreamWrap::Shutdown);
@@ -87,7 +87,6 @@ void StreamWrap::UpdateWriteQueueSize() {
object()->Set(env()->write_queue_size_string(), write_queue_size);
}


void StreamWrap::ReadStart(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());
HandleScope scope(env->isolate());
@@ -496,6 +495,17 @@ void StreamWrap::WriteUcs2String(const FunctionCallbackInfo<Value>& args) {
WriteStringImpl<UCS2>(args);
}

void StreamWrap::SetBlocking(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());
HandleScope scope(env->isolate());

StreamWrap* wrap = Unwrap<StreamWrap>(args.This());

assert(args.Length() > 0);
int err = uv_stream_set_blocking(wrap->stream(), args[0]->IsTrue());

args.GetReturnValue().Set(err);
}

void StreamWrap::AfterWrite(uv_write_t* req, int status) {
WriteWrap* req_wrap = CONTAINER_OF(req, WriteWrap, req_);
@@ -126,6 +126,8 @@ class StreamWrap : public HandleWrap {
static void WriteUtf8String(const v8::FunctionCallbackInfo<v8::Value>& args);
static void WriteUcs2String(const v8::FunctionCallbackInfo<v8::Value>& args);

static void SetBlocking(const v8::FunctionCallbackInfo<v8::Value>& args);

inline StreamWrapCallbacks* callbacks() const {
return callbacks_;
}
@@ -24,33 +24,36 @@ var assert = require('assert');
var net = require('net');
var tracing = require('tracing');

var errMsg = 'net - error: server connection';
var cntr = 0;
var al = tracing.addAsyncListener({
error: function(stor, er) {
cntr++;
process._rawDebug('Handling error: ' + er.message);
assert.equal(errMsg, er.message);
return true;
}
});

process.on('exit', function(status) {
tracing.removeAsyncListener(al);

console.log('exit status:', status);
assert.equal(status, 0);
console.log('cntr:', cntr);
assert.equal(cntr, 1);
console.log('ok');
});


var server = net.createServer(function(c) {
throw new Error('net - error: server connection');
this.close();
throw new Error(errMsg);
});


server.listen(common.PORT, function() {
net.connect(common.PORT, function() {
setImmediate(function() {
process.exit();
});
this.destroy();
});
});
@@ -0,0 +1,69 @@
// 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 path = require('path');

// if child process output to console and exit
if (process.argv[2] === 'child') {
console.log('hello');
for (var i = 0; i < 200; i++) {
console.log('filler');
}
console.log('goodbye');
process.exit(0);
} else {
// parent process
var spawn = require('child_process').spawn;

// spawn self as child
var child = spawn(process.argv[0], [process.argv[1], 'child']);

var gotHello = false;
var gotBye = false;

child.stderr.setEncoding('utf8');
child.stderr.on('data', function (data) {
console.log('parent stderr: ' + data);
assert.ok(false);
});

// check if we receive both 'hello' at start and 'goodbye' at end
child.stdout.setEncoding('utf8');
child.stdout.on('data', function (data) {
if (data.slice(0, 6) == 'hello\n') {
gotHello = true;
} else if (data.slice(data.length - 8) == 'goodbye\n') {
gotBye = true;
} else {
gotBye = false;
}
});

child.on('close', function (data) {
assert(gotHello);
assert(gotBye);
});
}
@@ -29,7 +29,7 @@ var agent = new Agent({
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 5,
maxFreeSockets: 5,
maxFreeSockets: 5
});

var server = http.createServer(function (req, res) {
@@ -47,9 +47,10 @@ var server = http.createServer(function (req, res) {
});

function get(path, callback) {
return agent.get({
return http.get({
host: 'localhost',
port: common.PORT,
agent: agent,
path: path
}, callback);
}
@@ -0,0 +1,47 @@
// 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 http = require('http');
var net = require('net');

var request = 0;
var response = 0;
process.on('exit', function() {
assert.equal(request, 1, 'http server "request" callback was not called');
assert.equal(response, 1, 'http request "response" callback was not called');
});

var server = http.createServer(function(req, res) {
request++;
res.end();
}).listen(function() {
var options = {
agent: null,
port: this.address().port
};
http.get(options, function(res) {
response++;
res.resume();
server.close();
});
});
@@ -44,7 +44,7 @@ var agent = http.Agent({
// then 10 more when they all finish.
function makeReqs(n, cb) {
for (var i = 0; i < n; i++)
makeReq(i, then)
makeReq(i, then);

function then(er) {
if (er)
@@ -55,7 +55,11 @@ function makeReqs(n, cb) {
}

function makeReq(i, cb) {
agent.request({ port: common.PORT, path: '/' + i }, function(res) {
http.request({
port: common.PORT,
path: '/' + i,
agent: agent
}, function(res) {
var data = '';
res.setEncoding('ascii');
res.on('data', function(c) {
@@ -54,9 +54,10 @@ function makeRequest(n) {
return;
}

var req = agent.request({
var req = http.request({
port: common.PORT,
path: '/' + n
path: '/' + n,
agent: agent
});

req.end();
@@ -48,82 +48,45 @@ function parent() {
});
}

function child0() {
// Just a very simple wrapper around TTY(2)
// Essentially the same as stderr, but without all the net stuff.
var Writable = require('stream').Writable;
var util = require('util');

// a lowlevel stderr writer
var TTY = process.binding('tty_wrap').TTY;
var handle = new TTY(2, false);

util.inherits(W, Writable);

function W(opts) {
Writable.call(this, opts);
}

W.prototype._write = function(chunk, encoding, cb) {
var req = { oncomplete: afterWrite };
var err = handle.writeUtf8String(req, chunk.toString() + '\n');
if (err) throw errnoException(err, 'write');
// here's the problem.
// it needs to tell the Writable machinery that it's ok to write
// more, but that the current buffer length is handle.writeQueueSize
if (req.writeQueueSize === 0)
req.cb = cb;
else
cb();
}
function afterWrite(status, handle, req) {
if (req.cb)
req.cb();
}

var w = new W
w.write('child 0');
w.write('foo');
w.write('bar');
w.write('baz');
}

// using console.error
function child1() {
console.error('child 1');
function child0() {
console.error('child 0');
console.error('foo');
console.error('bar');
console.error('baz');
}

// using process.stderr
function child2() {
process.stderr.write('child 2\n');
function child1() {
process.stderr.write('child 1\n');
process.stderr.write('foo\n');
process.stderr.write('bar\n');
process.stderr.write('baz\n');
}

// using a net socket
function child3() {
function child2() {
var net = require('net');
var socket = new net.Socket({ fd: 2 });
socket.write('child 3\n');
var socket = new net.Socket({
fd: 2,
readable: false,
writable: true});
socket.write('child 2\n');
socket.write('foo\n');
socket.write('bar\n');
socket.write('baz\n');
}


function child4() {
console.error('child 4\nfoo\nbar\nbaz');
function child3() {
console.error('child 3\nfoo\nbar\nbaz');
}

function child5() {
process.stderr.write('child 5\nfoo\nbar\nbaz\n');
function child4() {
process.stderr.write('child 4\nfoo\nbar\nbaz\n');
}

var children = [ child0, child1, child2, child3, child4, child5 ];
var children = [ child0, child1, child2, child3, child4 ];

if (!process.argv[2]) {
parent();