diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 58e424b1a0b..88afed448d9 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -97,6 +97,7 @@ typedef enum { UV_ENOBUFS, UV_ENOMEM, UV_ENOTDIR, + UV_EISDIR, UV_ENONET, UV_ENOPROTOOPT, UV_ENOTCONN, @@ -190,14 +191,14 @@ typedef struct uv_work_s uv_work_t; * All callbacks in libuv are made asynchronously. That is they are never * made by the function that takes them as a parameter. */ -UV_EXTERN uv_loop_t* uv_loop_new(); +UV_EXTERN uv_loop_t* uv_loop_new(void); UV_EXTERN void uv_loop_delete(uv_loop_t*); /* * Returns the default loop. */ -UV_EXTERN uv_loop_t* uv_default_loop(); +UV_EXTERN uv_loop_t* uv_default_loop(void); /* * This function starts the event loop. It blocks until the reference count diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index a63a6a47932..19d5b915018 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -158,7 +158,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { } -uv_loop_t* uv_loop_new() { +uv_loop_t* uv_loop_new(void) { uv_loop_t* loop = calloc(1, sizeof(uv_loop_t)); loop->ev = ev_loop_new(0); ev_set_userdata(loop->ev, loop); @@ -173,7 +173,7 @@ void uv_loop_delete(uv_loop_t* loop) { } -uv_loop_t* uv_default_loop() { +uv_loop_t* uv_default_loop(void) { if (!default_loop_ptr) { default_loop_ptr = &default_loop_struct; #if HAVE_KQUEUE diff --git a/deps/uv/src/unix/error.c b/deps/uv/src/unix/error.c index 6f49516d672..ac8bdd72cc8 100644 --- a/deps/uv/src/unix/error.c +++ b/deps/uv/src/unix/error.c @@ -75,6 +75,7 @@ static int uv__translate_lib_error(int code) { case UV_EADDRINUSE: return EADDRINUSE; case UV_EADDRNOTAVAIL: return EADDRNOTAVAIL; case UV_ENOTDIR: return ENOTDIR; + case UV_EISDIR: return EISDIR; case UV_ENOTCONN: return ENOTCONN; case UV_EEXIST: return EEXIST; case UV_EHOSTUNREACH: return EHOSTUNREACH; @@ -106,6 +107,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case EADDRINUSE: return UV_EADDRINUSE; case EADDRNOTAVAIL: return UV_EADDRNOTAVAIL; case ENOTDIR: return UV_ENOTDIR; + case EISDIR: return UV_EISDIR; case ENOTCONN: return UV_ENOTCONN; case EEXIST: return UV_EEXIST; case EHOSTUNREACH: return UV_EHOSTUNREACH; diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 3267b0cf8c8..4914fb4190d 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -99,12 +99,23 @@ static void uv_default_loop_init(void) { } -uv_loop_t* uv_default_loop() { +uv_loop_t* uv_default_loop(void) { uv_once(&uv_default_loop_init_guard_, uv_default_loop_init); return &uv_default_loop_; } +uv_loop_t* uv_loop_new(void) { + assert(0 && "implement me"); + return NULL; +} + + +void uv_loop_delete(uv_loop_t* loop) { + assert(0 && "implement me"); +} + + void uv_ref(uv_loop_t* loop) { loop->refs++; } diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index f0860864691..f57c825d15e 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -824,9 +824,19 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, /* An error occurred doing the read. */ if ((handle->flags & UV_HANDLE_READING)) { handle->flags &= ~UV_HANDLE_READING; - uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); buf = (handle->flags & UV_HANDLE_ZERO_READ) ? uv_buf_init(NULL, 0) : handle->read_buffer; + + err = GET_REQ_SOCK_ERROR(req); + + if (err == WSAECONNABORTED) { + /* Treat WSAECONNABORTED as connection closed. */ + handle->flags |= UV_HANDLE_EOF; + uv__set_error(loop, UV_EOF, ERROR_SUCCESS); + } else { + uv__set_sys_error(loop, err); + } + handle->read_cb((uv_stream_t*)handle, -1, buf); } } else { @@ -887,8 +897,14 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv__set_sys_error(loop, WSAEWOULDBLOCK); handle->read_cb((uv_stream_t*)handle, 0, buf); } else { - /* Ouch! serious error. */ - uv__set_sys_error(loop, err); + if (err == WSAECONNABORTED) { + /* Treat WSAECONNABORTED as connection closed. */ + handle->flags |= UV_HANDLE_EOF; + uv__set_error(loop, UV_EOF, ERROR_SUCCESS); + } else { + /* Ouch! serious error. */ + uv__set_sys_error(loop, err); + } handle->flags &= ~UV_HANDLE_READING; handle->read_cb((uv_stream_t*)handle, -1, buf); } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index b38f9536f14..9051fdb35ce 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -41,6 +41,7 @@ TEST_DECLARE (tcp_listen_without_bind) TEST_DECLARE (tcp_close) TEST_DECLARE (tcp_flags) TEST_DECLARE (tcp_write_error) +TEST_DECLARE (tcp_write_to_half_open_connection) TEST_DECLARE (tcp_bind6_error_addrinuse) TEST_DECLARE (tcp_bind6_error_addrnotavail) TEST_DECLARE (tcp_bind6_error_fault) @@ -163,6 +164,7 @@ TASK_LIST_START TEST_ENTRY (tcp_close) TEST_ENTRY (tcp_flags) TEST_ENTRY (tcp_write_error) + TEST_ENTRY (tcp_write_to_half_open_connection) TEST_ENTRY (tcp_bind6_error_addrinuse) TEST_ENTRY (tcp_bind6_error_addrnotavail) diff --git a/deps/uv/test/test-tcp-write-to-half-open-connection.c b/deps/uv/test/test-tcp-write-to-half-open-connection.c new file mode 100644 index 00000000000..9e7f553ad24 --- /dev/null +++ b/deps/uv/test/test-tcp-write-to-half-open-connection.c @@ -0,0 +1,139 @@ +/* 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 +#include +#include + +static void connection_cb(uv_stream_t* server, int status); +static void connect_cb(uv_connect_t* req, int status); +static void write_cb(uv_write_t* req, int status); +static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf); +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size); + +static uv_tcp_t tcp_server; +static uv_tcp_t tcp_client; +static uv_tcp_t tcp_peer; /* client socket as accept()-ed by server */ +static uv_connect_t connect_req; +static uv_write_t write_req; + +static int write_cb_called; +static int read_cb_called; +static int read_eof_cb_called; + + +static void connection_cb(uv_stream_t* server, int status) { + int r; + uv_buf_t buf; + + ASSERT(server == (uv_stream_t*)&tcp_server); + ASSERT(status == 0); + + r = uv_tcp_init(server->loop, &tcp_peer); + ASSERT(r == 0); + + r = uv_accept(server, (uv_stream_t*)&tcp_peer); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&tcp_peer, alloc_cb, read_cb); + ASSERT(r == 0); + + buf.base = "hello\n"; + buf.len = 6; + + r = uv_write(&write_req, (uv_stream_t*)&tcp_peer, &buf, 1, write_cb); + ASSERT(r == 0); +} + + +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) { + static char slab[1024]; + return uv_buf_init(slab, sizeof slab); +} + + +static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { + if (nread == -1) { + fprintf(stderr, "read_cb error: %s\n", uv_err_name(uv_last_error(stream->loop))); + ASSERT(uv_last_error(stream->loop).code == UV_EOF); + + uv_close((uv_handle_t*)&tcp_server, NULL); + uv_close((uv_handle_t*)&tcp_peer, NULL); + + read_eof_cb_called++; + } + + read_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(req == &connect_req); + ASSERT(status == 0); + + /* Close the client. */ + uv_close((uv_handle_t*)&tcp_client, NULL); +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + write_cb_called++; +} + + +TEST_IMPL(tcp_write_to_half_open_connection) { + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + ASSERT(loop != NULL); + + r = uv_tcp_init(loop, &tcp_server); + ASSERT(r == 0); + + r = uv_tcp_bind(&tcp_server, uv_ip4_addr("127.0.0.1", TEST_PORT)); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&tcp_server, 1, connection_cb); + ASSERT(r == 0); + + r = uv_tcp_init(loop, &tcp_client); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &tcp_client, + uv_ip4_addr("127.0.0.1", TEST_PORT), + connect_cb); + ASSERT(r == 0); + + r = uv_run(loop); + ASSERT(r == 0); + + ASSERT(write_cb_called > 0); + ASSERT(read_cb_called > 0); + ASSERT(read_eof_cb_called > 0); + + return 0; +} diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 3dac47f1339..83129b5c956 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -308,6 +308,7 @@ 'test/test-tcp-connect-error.c', 'test/test-tcp-connect6-error.c', 'test/test-tcp-write-error.c', + 'test/test-tcp-write-to-half-open-connection.c', 'test/test-tcp-writealot.c', 'test/test-threadpool.c', 'test/test-timer-again.c',