diff --git a/deps/uv/c-ares/ares.h b/deps/uv/c-ares/ares.h index 45ca564612..a8d381576e 100644 --- a/deps/uv/c-ares/ares.h +++ b/deps/uv/c-ares/ares.h @@ -96,9 +96,9 @@ typedef int ares_socklen_t; # include # include #elif defined(WIN32) -# include # include # include +# include #else # include # include diff --git a/deps/uv/c-ares/ares_setup.h b/deps/uv/c-ares/ares_setup.h index 8dbb9338c4..b405aae265 100644 --- a/deps/uv/c-ares/ares_setup.h +++ b/deps/uv/c-ares/ares_setup.h @@ -108,7 +108,6 @@ */ #ifdef HAVE_WINDOWS_H -# include # ifdef HAVE_WINSOCK2_H # include # ifdef HAVE_WS2TCPIP_H @@ -119,6 +118,7 @@ # include # endif # endif +# include #endif /* diff --git a/deps/uv/c-ares/config-win32.h b/deps/uv/c-ares/config-win32.h index 898ba90472..13c5de56e6 100644 --- a/deps/uv/c-ares/config-win32.h +++ b/deps/uv/c-ares/config-win32.h @@ -51,9 +51,6 @@ #define HAVE_UNISTD_H 1 #endif -/* Define if you have the header file. */ -#define HAVE_WINDOWS_H 1 - /* Define if you have the header file. */ #define HAVE_WINSOCK_H 1 diff --git a/deps/uv/config-mingw.mk b/deps/uv/config-mingw.mk index f3804d8fa7..f1f1ce9e45 100644 --- a/deps/uv/config-mingw.mk +++ b/deps/uv/config-mingw.mk @@ -24,7 +24,7 @@ CC = $(PREFIX)gcc AR = $(PREFIX)ar E=.exe -CFLAGS=-g --std=gnu89 -Wno-variadic-macros -D_WIN32_WINNT=0x0501 -Ic-ares/config_win32 +CFLAGS=-g --std=gnu89 -D_WIN32_WINNT=0x0501 -Ic-ares/config_win32 LINKFLAGS=-lm CARES_OBJS += c-ares/windows_port.o diff --git a/deps/uv/config-unix.mk b/deps/uv/config-unix.mk index 0946dcee91..4e503b3e54 100644 --- a/deps/uv/config-unix.mk +++ b/deps/uv/config-unix.mk @@ -21,7 +21,7 @@ CC = $(PREFIX)gcc AR = $(PREFIX)ar E= -CFLAGS=--std=gnu89 -Wno-variadic-macros -g +CFLAGS=--std=gnu89 -g LINKFLAGS=-lm CPPFLAGS += -D_LARGEFILE_SOURCE diff --git a/deps/uv/test/echo-server.c b/deps/uv/test/echo-server.c index 1243a9a489..ab5491c2f8 100644 --- a/deps/uv/test/echo-server.c +++ b/deps/uv/test/echo-server.c @@ -34,6 +34,9 @@ typedef struct { static int server_closed; static uv_tcp_t server; +static int server6_closed; +static uv_tcp_t server6; + static void after_write(uv_req_t* req, int status); static void after_read(uv_stream_t*, ssize_t nread, uv_buf_t buf); @@ -97,6 +100,8 @@ static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) { if (buf.base[i] == 'Q') { uv_close((uv_handle_t*)&server, on_server_close); server_closed = 1; + uv_close((uv_handle_t*)&server6, on_server_close); + server6_closed = 1; } } } @@ -129,6 +134,9 @@ static void on_connection(uv_handle_t* server, int status) { uv_tcp_t* handle; int r; + if (status != 0) { + fprintf(stderr, "Connect error %d\n", uv_last_error()); + } ASSERT(status == 0); handle = (uv_tcp_t*) malloc(sizeof *handle); @@ -136,6 +144,9 @@ static void on_connection(uv_handle_t* server, int status) { uv_tcp_init(handle); + /* associate server with stream */ + handle->data = server; + r = uv_accept(server, (uv_stream_t*)handle); ASSERT(r == 0); @@ -145,12 +156,13 @@ static void on_connection(uv_handle_t* server, int status) { static void on_server_close(uv_handle_t* handle) { - ASSERT(handle == (uv_handle_t*)&server); + ASSERT(handle == (uv_handle_t*)&server || handle == (uv_handle_t*)&server6); } static int echo_start(int port) { struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", port); + struct sockaddr_in6 addr6 = uv_ip6_addr("::1", port); int r; r = uv_tcp_init(&server); @@ -174,6 +186,27 @@ static int echo_start(int port) { return 1; } + r = uv_tcp_init(&server6); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Socket creation error\n"); + return 1; + } + + r = uv_tcp_bind6(&server6, addr6); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Bind6 error\n"); + return 1; + } + + r = uv_tcp_listen(&server6, 128, on_connection); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Listen error\n"); + return 1; + } + return 0; } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index ddedfa1be8..190574acaa 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -20,6 +20,7 @@ */ TEST_DECLARE (ping_pong) +TEST_DECLARE (ping_pong_v6) TEST_DECLARE (delayed_accept) TEST_DECLARE (tcp_writealot) TEST_DECLARE (bind_error_addrinuse) @@ -60,6 +61,9 @@ TASK_LIST_START TEST_ENTRY (ping_pong) TEST_HELPER (ping_pong, echo_server) + TEST_ENTRY (ping_pong_v6) + TEST_HELPER (ping_pong_v6, echo_server) + TEST_ENTRY (delayed_accept) TEST_ENTRY (tcp_writealot) diff --git a/deps/uv/test/test-ping-pong.c b/deps/uv/test/test-ping-pong.c index 1858adc825..14208e7519 100644 --- a/deps/uv/test/test-ping-pong.c +++ b/deps/uv/test/test-ping-pong.c @@ -175,3 +175,40 @@ TEST_IMPL(ping_pong) { return 0; } + + +/* same ping-pong test, but using IPv6 connection */ +static void pinger_v6_new() { + int r; + struct sockaddr_in6 server_addr = uv_ip6_addr("::1", TEST_PORT); + pinger_t *pinger; + + pinger = (pinger_t*)malloc(sizeof(*pinger)); + pinger->state = 0; + pinger->pongs = 0; + + /* Try to connec to the server and do NUM_PINGS ping-pongs. */ + r = uv_tcp_init(&pinger->tcp); + pinger->tcp.data = pinger; + ASSERT(!r); + + /* We are never doing multiple reads/connects at a time anyway. */ + /* so these handles can be pre-initialized. */ + uv_req_init(&pinger->connect_req, (uv_handle_t*)(&pinger->tcp), + pinger_on_connect); + + r = uv_tcp_connect6(&pinger->connect_req, server_addr); + ASSERT(!r); +} + + +TEST_IMPL(ping_pong_v6) { + uv_init(); + + pinger_v6_new(); + uv_run(); + + ASSERT(completed_pingers == 1); + + return 0; +} diff --git a/deps/uv/uv-unix.c b/deps/uv/uv-unix.c index db3ce11876..c9b6628027 100644 --- a/deps/uv/uv-unix.c +++ b/deps/uv/uv-unix.c @@ -659,7 +659,9 @@ static uv_req_t* uv__write(uv_tcp_t* tcp) { /* Pop the req off tcp->write_queue. */ ngx_queue_remove(&req->queue); - free(req->bufs); /* FIXME: we should not be allocing for each read */ + if (req->bufs != req->bufsml) { + free(req->bufs); + } req->bufs = NULL; /* Add it to the write_completed_queue where it will have its @@ -943,6 +945,13 @@ int uv_tcp_connect(uv_req_t* req, struct sockaddr_in addr) { } +/* TODO: Implement IPv6 Connect for UNIX */ +int uv_tcp_connect6(uv_req_t* req, struct sockaddr_in6 addr) { + uv_err_new_artificial((uv_handle_t*)req->handle, UV_EAFNOSUPPORT); + return -1; +} + + static size_t uv__buf_count(uv_buf_t bufs[], int bufcnt) { size_t total = 0; int i; @@ -966,11 +975,19 @@ int uv_write(uv_req_t* req, uv_buf_t bufs[], int bufcnt) { ngx_queue_init(&req->queue); req->type = UV_WRITE; - /* TODO: Don't malloc for each write... */ - req->bufs = malloc(sizeof(uv_buf_t) * bufcnt); + + if (bufcnt < UV_REQ_BUFSML_SIZE) { + req->bufs = req->bufsml; + } + else { + req->bufs = malloc(sizeof(uv_buf_t) * bufcnt); + } + memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf_t)); req->bufcnt = bufcnt; + // fprintf(stderr, "cnt: %d bufs: %p bufsml: %p\n", bufcnt, req->bufs, req->bufsml); + req->write_index = 0; tcp->write_queue_size += uv__buf_count(bufs, bufcnt); diff --git a/deps/uv/uv-unix.h b/deps/uv/uv-unix.h index 576598aea6..f6c5134bca 100644 --- a/deps/uv/uv-unix.h +++ b/deps/uv/uv-unix.h @@ -39,13 +39,15 @@ typedef struct { size_t len; } uv_buf_t; +#define UV_REQ_BUFSML_SIZE (4) #define UV_REQ_PRIVATE_FIELDS \ int write_index; \ ev_timer timer; \ ngx_queue_t queue; \ uv_buf_t* bufs; \ - int bufcnt; + int bufcnt; \ + uv_buf_t bufsml[UV_REQ_BUFSML_SIZE]; /* TODO: union or classes please! */ diff --git a/deps/uv/uv-win.c b/deps/uv/uv-win.c index 61719798d4..e6b8492d45 100644 --- a/deps/uv/uv-win.c +++ b/deps/uv/uv-win.c @@ -139,6 +139,12 @@ static LPFN_ACCEPTEX pAcceptEx; static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs; static LPFN_DISCONNECTEX pDisconnectEx; static LPFN_TRANSMITFILE pTransmitFile; +/* need IPv6 versions of winsock extension functions */ +static LPFN_CONNECTEX pConnectEx6; +static LPFN_ACCEPTEX pAcceptEx6; +static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6; +static LPFN_DISCONNECTEX pDisconnectEx6; +static LPFN_TRANSMITFILE pTransmitFile6; /* @@ -157,6 +163,7 @@ static LPFN_TRANSMITFILE pTransmitFile; #define UV_HANDLE_SHUT 0x0200 #define UV_HANDLE_ENDGAME_QUEUED 0x0400 #define UV_HANDLE_BIND_ERROR 0x1000 +#define UV_HANDLE_IPV6 0x2000 /* * Private uv_req flags. @@ -208,6 +215,7 @@ static int uv_refs_ = 0; /* Ip address used to bind to any port at any interface */ static struct sockaddr_in uv_addr_ip4_any_; +static struct sockaddr_in6 uv_addr_ip6_any_; /* A zero-size buffer for use by uv_read */ @@ -417,6 +425,7 @@ void uv_init() { int errorno; LARGE_INTEGER timer_frequency; SOCKET dummy; + SOCKET dummy6; /* Initialize winsock */ errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); @@ -426,6 +435,7 @@ void uv_init() { /* Set implicit binding address used by connectEx */ uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0); + uv_addr_ip6_any_ = uv_ip6_addr("::1", 0); /* Retrieve the needed winsock extension function pointers. */ dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); @@ -453,6 +463,33 @@ void uv_init() { uv_fatal_error(WSAGetLastError(), "closesocket"); } +/* need IPv6 versions of winsock extension functions */ + dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); + if (dummy == INVALID_SOCKET) { + uv_fatal_error(WSAGetLastError(), "socket"); + } + + uv_get_extension_function(dummy6, + wsaid_connectex, + (void**)&pConnectEx6); + uv_get_extension_function(dummy6, + wsaid_acceptex, + (void**)&pAcceptEx6); + uv_get_extension_function(dummy6, + wsaid_getacceptexsockaddrs, + (void**)&pGetAcceptExSockAddrs6); + uv_get_extension_function(dummy6, + wsaid_disconnectex, + (void**)&pDisconnectEx6); + uv_get_extension_function(dummy6, + wsaid_transmitfile, + (void**)&pTransmitFile6); + + if (closesocket(dummy6) == SOCKET_ERROR) { + uv_fatal_error(WSAGetLastError(), "closesocket"); + } + + /* Create an I/O completion port */ uv_iocp_ = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (uv_iocp_ == NULL) { @@ -815,7 +852,7 @@ int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) { uv_set_sys_error(WSAEFAULT); return -1; } - + handle->flags |= UV_HANDLE_IPV6; return uv__bind(handle, AF_INET6, (struct sockaddr*)&addr, sizeof(struct sockaddr_in6)); } @@ -825,6 +862,8 @@ static void uv_queue_accept(uv_tcp_t* handle) { BOOL success; DWORD bytes; SOCKET accept_socket; + short family; + LPFN_ACCEPTEX pAcceptExFamily; assert(handle->flags & UV_HANDLE_LISTENING); assert(handle->accept_socket == INVALID_SOCKET); @@ -835,8 +874,17 @@ static void uv_queue_accept(uv_tcp_t* handle) { req->type = UV_ACCEPT; req->flags |= UV_REQ_PENDING; + /* choose family and extension function */ + if ((handle->flags & UV_HANDLE_IPV6) != 0) { + family = AF_INET6; + pAcceptExFamily = pAcceptEx6; + } else { + family = AF_INET; + pAcceptExFamily = pAcceptEx; + } + /* Open a socket for the accepted connection. */ - accept_socket = socket(AF_INET, SOCK_STREAM, 0); + accept_socket = socket(family, SOCK_STREAM, 0); if (accept_socket == INVALID_SOCKET) { req->error = uv_new_sys_error(WSAGetLastError()); uv_insert_pending_req(req); @@ -846,14 +894,14 @@ static void uv_queue_accept(uv_tcp_t* handle) { /* Prepare the overlapped structure. */ memset(&(req->overlapped), 0, sizeof(req->overlapped)); - success = pAcceptEx(handle->socket, - accept_socket, - (void*)&handle->accept_buffer, - 0, - sizeof(struct sockaddr_storage), - sizeof(struct sockaddr_storage), - &bytes, - &req->overlapped); + success = pAcceptExFamily(handle->socket, + accept_socket, + (void*)&handle->accept_buffer, + 0, + sizeof(struct sockaddr_storage), + sizeof(struct sockaddr_storage), + &bytes, + &req->overlapped); if (!success && WSAGetLastError() != ERROR_IO_PENDING) { /* Make this req pending reporting an error. */ @@ -1045,6 +1093,51 @@ int uv_tcp_connect(uv_req_t* req, struct sockaddr_in addr) { } +int uv_tcp_connect6(uv_req_t* req, struct sockaddr_in6 addr) { + int addrsize = sizeof(struct sockaddr_in6); + BOOL success; + DWORD bytes; + uv_tcp_t* handle = (uv_tcp_t*)req->handle; + + assert(!(req->flags & UV_REQ_PENDING)); + + if (handle->flags & UV_HANDLE_BIND_ERROR) { + uv_last_error_ = handle->error; + return -1; + } + + if (addr.sin6_family != AF_INET6) { + uv_set_sys_error(WSAEFAULT); + return -1; + } + + if (!(handle->flags & UV_HANDLE_BOUND) && + uv_tcp_bind6(handle, uv_addr_ip6_any_) < 0) + return -1; + + memset(&req->overlapped, 0, sizeof(req->overlapped)); + req->type = UV_CONNECT; + + success = pConnectEx6(handle->socket, + (struct sockaddr*)&addr, + addrsize, + NULL, + 0, + &bytes, + &req->overlapped); + + if (!success && WSAGetLastError() != ERROR_IO_PENDING) { + uv_set_sys_error(WSAGetLastError()); + return -1; + } + + req->flags |= UV_REQ_PENDING; + handle->reqs_pending++; + + return 0; +} + + static size_t uv_count_bufs(uv_buf_t bufs[], int count) { size_t bytes = 0; int i; diff --git a/deps/uv/uv.h b/deps/uv/uv.h index e7df5b6590..bd84c516fe 100644 --- a/deps/uv/uv.h +++ b/deps/uv/uv.h @@ -282,6 +282,7 @@ int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in); int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6); int uv_tcp_connect(uv_req_t* req, struct sockaddr_in); +int uv_tcp_connect6(uv_req_t* req, struct sockaddr_in6); int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);