<ItemGroup>
<ClCompile Include="..\test\echo-server.c" />
<ClCompile Include="..\test\test-async.c" />
- <ClCompile Include="..\test\test-bind6-error.c" />
<ClCompile Include="..\test\test-delayed-accept.c" />
<ClCompile Include="..\test\test-callback-stack.c" />
<ClCompile Include="..\test\test-connection-fail.c" />
<ClCompile Include="..\test\test-ping-pong.c" />
<ClCompile Include="..\test\runner-win.c" />
<ClCompile Include="..\test\runner.c" />
- <ClCompile Include="..\test\test-bind-error.c" />
+ <ClCompile Include="..\test\test-pipe-bind-error.c" />
<ClCompile Include="..\test\test-shutdown-eof.c" />
+ <ClCompile Include="..\test\test-tcp-bind-error.c" />
+ <ClCompile Include="..\test\test-tcp-bind6-error.c" />
<ClCompile Include="..\test\test-tcp-writealot.c" />
<ClCompile Include="..\test\test-timer-again.c" />
<ClCompile Include="..\test\test-timer.c" />
switch (sys_errno) {
case 0: return UV_OK;
case EACCES: return UV_EACCESS;
+ case EBADF: return UV_EBADF;
case EAGAIN: return UV_EAGAIN;
case ECONNRESET: return UV_ECONNRESET;
case EFAULT: return UV_EFAULT;
void uv__server_io(EV_P_ ev_io* watcher, int revents) {
int fd;
struct sockaddr_storage addr;
- socklen_t addrlen = sizeof(struct sockaddr_storage);
uv_stream_t* stream = watcher->data;
assert(watcher == &stream->read_watcher ||
while (1) {
assert(stream->accepted_fd < 0);
- fd = accept(stream->fd, (struct sockaddr*)&addr, &addrlen);
+ fd = uv__accept(stream->fd, (struct sockaddr*)&addr, sizeof addr);
if (fd < 0) {
if (errno == EAGAIN) {
if (stream->connect_req) {
uv__stream_connect(stream);
} else {
+ assert(revents & (EV_READ | EV_WRITE));
+
if (revents & EV_READ) {
uv__read((uv_stream_t*)stream);
}
&& "uv_write (unix) does not yet support other types of streams");
empty_queue = (stream->write_queue_size == 0);
- assert(stream->fd >= 0);
+
+ if (stream->fd < 0) {
+ uv_err_new((uv_handle_t*)stream, EBADF);
+ return -1;
+ }
ngx_queue_init(&req->queue);
req->type = UV_WRITE;
status = 0;
out:
- if (0) uv__req_init((uv_req_t*)req);
+ handle->delayed_error = status; /* Passed to callback. */
+ handle->connect_req = req;
req->handle = (uv_stream_t*)handle;
req->type = UV_CONNECT;
req->cb = cb;
ngx_queue_init(&req->queue);
- if (cb) {
- cb(req, status);
- }
+ /* Run callback on next tick. */
+ ev_feed_event(EV_DEFAULT_ &handle->read_watcher, EV_CUSTOM);
+ assert(ev_is_pending(&handle->read_watcher));
/* Mimic the Windows pipe implementation, always
* return 0 and let the callback handle errors.
void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req) {
- DWORD bytes, err, mode;
+ DWORD bytes, avail, err, mode;
uv_buf_t buf;
assert(handle->type == UV_NAMED_PIPE);
handle->read_cb((uv_stream_t*)handle, -1, buf);
}
} else {
- /*
- * Temporarily switch to non-blocking mode.
- * This is so that ReadFile doesn't block if the read buffer is empty.
- */
- mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT;
- if (!SetNamedPipeHandleState(handle->handle, &mode, NULL, NULL)) {
- /* We can't continue processing this read. */
- handle->flags &= ~UV_HANDLE_READING;
- uv_set_sys_error(GetLastError());
- buf.base = 0;
- buf.len = 0;
- handle->read_cb((uv_stream_t*)handle, -1, buf);
- }
-
/* Do non-blocking reads until the buffer is empty */
while (handle->flags & UV_HANDLE_READING) {
- buf = handle->alloc_cb((uv_stream_t*)handle, 65536);
+ if (!PeekNamedPipe(handle->handle,
+ NULL,
+ 0,
+ NULL,
+ &avail,
+ NULL)) {
+ uv_set_sys_error(GetLastError());
+ buf.base = 0;
+ buf.len = 0;
+ handle->read_cb((uv_stream_t*)handle, -1, buf);
+ break;
+ }
+
+ buf = handle->alloc_cb((uv_stream_t*)handle, avail);
assert(buf.len > 0);
if (ReadFile(handle->handle,
/* Successful read */
handle->read_cb((uv_stream_t*)handle, bytes, buf);
/* Read again only if bytes == buf.len */
- if (bytes < buf.len) {
+ if (bytes <= buf.len) {
break;
}
} else {
break;
}
} else {
- err = GetLastError();
- if (err == ERROR_NO_DATA) {
- /* Read buffer was completely empty, report a 0-byte read. */
- uv_set_sys_error(WSAEWOULDBLOCK);
- handle->read_cb((uv_stream_t*)handle, 0, buf);
- } else {
- /* Ouch! serious error. */
- uv_set_sys_error(err);
- handle->read_cb((uv_stream_t*)handle, -1, buf);
- }
+ /* Ouch! serious error. */
+ uv_set_sys_error(GetLastError());
+ handle->read_cb((uv_stream_t*)handle, -1, buf);
break;
}
}
- /* TODO: if the read callback stops reading we can't start reading again
- because the pipe will still be in nowait mode. */
+ /* Post another 0-read if still reading and not closing. */
if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) {
- /* Switch back to blocking mode so that we can use IOCP for 0-reads */
- mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
- if (SetNamedPipeHandleState(handle->handle, &mode, NULL, NULL)) {
- /* Post another 0-read */
- uv_pipe_queue_read(handle);
- } else {
- /* Report and continue. */
- /* We can't continue processing this read. */
- handle->flags &= ~UV_HANDLE_READING;
- uv_set_sys_error(GetLastError());
- buf.base = 0;
- buf.len = 0;
- handle->read_cb((uv_stream_t*)handle, -1, buf);
- }
+ uv_pipe_queue_read(handle);
}
}
if (ares_errors > 0) {
printf("There were %d failures\n", ares_errors);
}
- LOGF("ares_gethostbyname: %d calls in %d ms \n", ares_callbacks, (int) (end_time - start_time));
+ LOGF("ares_gethostbyname: %.0f req/s\n",
+ 1000.0 * ares_callbacks / (double)(end_time - start_time));
return 0;
}
ASSERT(calls_initiated == TOTAL_CALLS);
ASSERT(calls_completed == TOTAL_CALLS);
- LOGF("getaddrinfo: %d calls in %d ms (%.0f requests/second)\n",
- calls_completed,
- (int) (end_time - start_time),
+ LOGF("getaddrinfo: %.0f req/s\n",
(double) calls_completed / (double) (end_time - start_time) * 1000.0);
return 0;
}
rewind_cursor();
- log_progress(total, passed, failed, task->task_name);
+ if (!benchmark_output) {
+ log_progress(total, passed, failed, task->task_name);
+ }
if (run_test(task->task_name, timeout, benchmark_output) == 0) {
passed++;
}
rewind_cursor();
- log_progress(total, passed, failed, "Done.\n");
+
+ if (!benchmark_output) {
+ log_progress(total, passed, failed, "Done.\n");
+ }
return 0;
}
sizeof errmsg,
"exit code %d",
status);
+ goto out;
+ }
+
+ if (benchmark_output) {
+ /* Give the helpers time to clean up their act. */
+ uv_sleep(1000);
}
out:
#ifdef _WIN32
# define TEST_PIPENAME "\\\\.\\pipe\\uv-test"
+# define TEST_PIPENAME_2 "\\\\.\\pipe\\uv-test2"
#else
# define TEST_PIPENAME "/tmp/uv-test-sock"
+# define TEST_PIPENAME_2 "/tmp/uv-test-sock2"
#endif
typedef enum {
} stream_type;
/* Log to stderr. */
-#define LOG(...) fprintf(stderr, "%s", __VA_ARGS__)
-#define LOGF(...) fprintf(stderr, __VA_ARGS__)
+#define LOG(...) \
+ do { \
+ fprintf(stderr, "%s", __VA_ARGS__); \
+ fflush(stderr); \
+ } while (0)
+
+#define LOGF(...) \
+ do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ } while (0)
/* Die with fatal error. */
#define FATAL(msg) \
__FILE__, \
__LINE__, \
msg); \
+ fflush(stderr); \
abort(); \
} while (0)
TEST_DECLARE (pipe_ping_pong)
TEST_DECLARE (delayed_accept)
TEST_DECLARE (tcp_writealot)
-TEST_DECLARE (bind_error_addrinuse)
-TEST_DECLARE (bind_error_addrnotavail_1)
-TEST_DECLARE (bind_error_addrnotavail_2)
-TEST_DECLARE (bind_error_fault)
-TEST_DECLARE (bind_error_inval)
-TEST_DECLARE (bind_localhost_ok)
-TEST_DECLARE (listen_without_bind)
-TEST_DECLARE (bind6_error_addrinuse)
-TEST_DECLARE (bind6_error_addrnotavail)
-TEST_DECLARE (bind6_error_fault)
-TEST_DECLARE (bind6_error_inval)
-TEST_DECLARE (bind6_localhost_ok)
+TEST_DECLARE (tcp_bind_error_addrinuse)
+TEST_DECLARE (tcp_bind_error_addrnotavail_1)
+TEST_DECLARE (tcp_bind_error_addrnotavail_2)
+TEST_DECLARE (tcp_bind_error_fault)
+TEST_DECLARE (tcp_bind_error_inval)
+TEST_DECLARE (tcp_bind_localhost_ok)
+TEST_DECLARE (tcp_listen_without_bind)
+TEST_DECLARE (tcp_bind6_error_addrinuse)
+TEST_DECLARE (tcp_bind6_error_addrnotavail)
+TEST_DECLARE (tcp_bind6_error_fault)
+TEST_DECLARE (tcp_bind6_error_inval)
+TEST_DECLARE (tcp_bind6_localhost_ok)
+TEST_DECLARE (pipe_bind_error_addrinuse)
+TEST_DECLARE (pipe_bind_error_addrnotavail)
+TEST_DECLARE (pipe_bind_error_inval)
+TEST_DECLARE (pipe_listen_without_bind)
TEST_DECLARE (connection_fail)
TEST_DECLARE (connection_fail_doesnt_auto_close)
TEST_DECLARE (shutdown_eof)
TEST_ENTRY (tcp_writealot)
TEST_HELPER (tcp_writealot, tcp4_echo_server)
- TEST_ENTRY (bind_error_addrinuse)
- TEST_ENTRY (bind_error_addrnotavail_1)
- TEST_ENTRY (bind_error_addrnotavail_2)
- TEST_ENTRY (bind_error_fault)
- TEST_ENTRY (bind_error_inval)
- TEST_ENTRY (bind_localhost_ok)
- TEST_ENTRY (listen_without_bind)
-
- TEST_ENTRY (bind6_error_addrinuse)
- TEST_ENTRY (bind6_error_addrnotavail)
- TEST_ENTRY (bind6_error_fault)
- TEST_ENTRY (bind6_error_inval)
- TEST_ENTRY (bind6_localhost_ok)
+ TEST_ENTRY (tcp_bind_error_addrinuse)
+ TEST_ENTRY (tcp_bind_error_addrnotavail_1)
+ TEST_ENTRY (tcp_bind_error_addrnotavail_2)
+ TEST_ENTRY (tcp_bind_error_fault)
+ TEST_ENTRY (tcp_bind_error_inval)
+ TEST_ENTRY (tcp_bind_localhost_ok)
+ TEST_ENTRY (tcp_listen_without_bind)
+
+ TEST_ENTRY (tcp_bind6_error_addrinuse)
+ TEST_ENTRY (tcp_bind6_error_addrnotavail)
+ TEST_ENTRY (tcp_bind6_error_fault)
+ TEST_ENTRY (tcp_bind6_error_inval)
+ TEST_ENTRY (tcp_bind6_localhost_ok)
+
+ TEST_ENTRY (pipe_bind_error_addrinuse)
+ TEST_ENTRY (pipe_bind_error_addrnotavail)
+ TEST_ENTRY (pipe_bind_error_inval)
+ TEST_ENTRY (pipe_listen_without_bind)
TEST_ENTRY (connection_fail)
TEST_ENTRY (connection_fail_doesnt_auto_close)
#define BUFSIZE 10240
static char PING[] = "PING\n";
+static int pinger_on_connect_count;
typedef struct {
static void pinger_on_connect(uv_connect_t *req, int status) {
pinger_t *pinger = (pinger_t*)req->handle->data;
+ pinger_on_connect_count++;
+
ASSERT(status == 0);
pinger_write_ping(pinger);
r = uv_tcp_connect6(&pinger->connect_req, &pinger->tcp, server_addr,
pinger_on_connect);
ASSERT(!r);
+
+ /* Synchronous connect callbacks are not allowed. */
+ ASSERT(pinger_on_connect_count == 0);
}
/* We are never doing multiple reads/connects at a time anyway. */
/* so these handles can be pre-initialized. */
- r = uv_tcp_connect(&pinger->connect_req, &pinger->tcp, server_addr, pinger_on_connect);
+ r = uv_tcp_connect(&pinger->connect_req, &pinger->tcp, server_addr,
+ pinger_on_connect);
ASSERT(!r);
+
+ /* Synchronous connect callbacks are not allowed. */
+ ASSERT(pinger_on_connect_count == 0);
}
/* We are never doing multiple reads/connects at a time anyway. */
/* so these handles can be pre-initialized. */
- r = uv_pipe_connect(&pinger->connect_req, &pinger->pipe, TEST_PIPENAME, pinger_on_connect);
+ r = uv_pipe_connect(&pinger->connect_req, &pinger->pipe, TEST_PIPENAME,
+ pinger_on_connect);
ASSERT(!r);
+
+ /* Synchronous connect callbacks are not allowed. */
+ ASSERT(pinger_on_connect_count == 0);
}
--- /dev/null
+/* 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>
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+/* TODO: define a bad pipe name for unix (see pipe_bind_error_addrnotavail) */
+# define BAD_PIPENAME ""
+#endif
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(pipe_bind_error_addrinuse) {
+ uv_pipe_t server1, server2;
+ int r;
+
+ uv_init();
+
+ r = uv_pipe_init(&server1);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server1, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(&server2);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server2, TEST_PIPENAME);
+ ASSERT(r == -1);
+
+ ASSERT(uv_last_error().code == UV_EADDRINUSE);
+
+ r = uv_pipe_listen(&server1, NULL);
+ ASSERT(r == 0);
+ r = uv_pipe_listen(&server2, NULL);
+ ASSERT(r == -1);
+
+ ASSERT(uv_last_error().code == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*)&server1, close_cb);
+ uv_close((uv_handle_t*)&server2, close_cb);
+
+ uv_run();
+
+ ASSERT(close_cb_called == 2);
+
+ return 0;
+}
+
+
+TEST_IMPL(pipe_bind_error_addrnotavail) {
+ uv_pipe_t server;
+ int r;
+
+ uv_init();
+
+ r = uv_pipe_init(&server);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server, BAD_PIPENAME);
+
+ ASSERT(r == -1);
+ ASSERT(uv_last_error().code == UV_EADDRNOTAVAIL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run();
+
+ ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(pipe_bind_error_inval) {
+ uv_pipe_t server;
+ int r;
+
+ uv_init();
+
+ r = uv_pipe_init(&server);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server, TEST_PIPENAME);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server, TEST_PIPENAME_2);
+ ASSERT(r == -1);
+
+ ASSERT(uv_last_error().code == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run();
+
+ ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(pipe_listen_without_bind) {
+ uv_pipe_t server;
+ int r;
+
+ uv_init();
+
+ r = uv_pipe_init(&server);
+ ASSERT(r == 0);
+ r = uv_pipe_listen(&server, NULL);
+ ASSERT(r == -1);
+
+ ASSERT(uv_last_error().code == UV_ENOTCONN);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run();
+
+ ASSERT(close_cb_called == 1);
+
+ return 0;
+}
}
-TEST_IMPL(bind_error_addrinuse) {
+TEST_IMPL(tcp_bind_error_addrinuse) {
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", TEST_PORT);
uv_tcp_t server1, server2;
int r;
}
-TEST_IMPL(bind_error_addrnotavail_1) {
+TEST_IMPL(tcp_bind_error_addrnotavail_1) {
struct sockaddr_in addr = uv_ip4_addr("127.255.255.255", TEST_PORT);
uv_tcp_t server;
int r;
}
-TEST_IMPL(bind_error_addrnotavail_2) {
+TEST_IMPL(tcp_bind_error_addrnotavail_2) {
struct sockaddr_in addr = uv_ip4_addr("4.4.4.4", TEST_PORT);
uv_tcp_t server;
int r;
}
-TEST_IMPL(bind_error_fault) {
+TEST_IMPL(tcp_bind_error_fault) {
char garbage[] = "blah blah blah blah blah blah blah blah blah blah blah blah";
struct sockaddr_in* garbage_addr;
uv_tcp_t server;
/* Notes: On Linux uv_bind(server, NULL) will segfault the program. */
-TEST_IMPL(bind_error_inval) {
+TEST_IMPL(tcp_bind_error_inval) {
struct sockaddr_in addr1 = uv_ip4_addr("0.0.0.0", TEST_PORT);
struct sockaddr_in addr2 = uv_ip4_addr("0.0.0.0", TEST_PORT_2);
uv_tcp_t server;
}
-TEST_IMPL(bind_localhost_ok) {
+TEST_IMPL(tcp_bind_localhost_ok) {
struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
uv_tcp_t server;
}
-TEST_IMPL(listen_without_bind) {
+TEST_IMPL(tcp_listen_without_bind) {
int r;
uv_tcp_t server;
}
-TEST_IMPL(bind6_error_addrinuse) {
+TEST_IMPL(tcp_bind6_error_addrinuse) {
struct sockaddr_in6 addr = uv_ip6_addr("::", TEST_PORT);
uv_tcp_t server1, server2;
int r;
}
-TEST_IMPL(bind6_error_addrnotavail) {
+TEST_IMPL(tcp_bind6_error_addrnotavail) {
struct sockaddr_in6 addr = uv_ip6_addr("4:4:4:4:4:4:4:4", TEST_PORT);
uv_tcp_t server;
int r;
}
-TEST_IMPL(bind6_error_fault) {
+TEST_IMPL(tcp_bind6_error_fault) {
char garbage[] = "blah blah blah blah blah blah blah blah blah blah blah blah";
struct sockaddr_in6* garbage_addr;
uv_tcp_t server;
/* Notes: On Linux uv_bind6(server, NULL) will segfault the program. */
-TEST_IMPL(bind6_error_inval) {
+TEST_IMPL(tcp_bind6_error_inval) {
struct sockaddr_in6 addr1 = uv_ip6_addr("::", TEST_PORT);
struct sockaddr_in6 addr2 = uv_ip6_addr("::", TEST_PORT_2);
uv_tcp_t server;
}
-TEST_IMPL(bind6_localhost_ok) {
+TEST_IMPL(tcp_bind6_localhost_ok) {
struct sockaddr_in6 addr = uv_ip6_addr("::1", TEST_PORT);
uv_tcp_t server;