mirror of https://github.com/nodejs/node.git
deps: upgrade libuv to 3b8c0da
parent
b9abb64fbb
commit
7e5aeac28f
|
@ -93,7 +93,8 @@ enum {
|
|||
UV_STREAM_WRITABLE = 0x40, /* The stream is writable */
|
||||
UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */
|
||||
UV_TCP_NODELAY = 0x100, /* Disable Nagle. */
|
||||
UV_TCP_KEEPALIVE = 0x200 /* Turn on keep-alive. */
|
||||
UV_TCP_KEEPALIVE = 0x200, /* Turn on keep-alive. */
|
||||
UV_TCP_CONNECTING = 0x400 /* Not alway set. See uv_connect() in tcp.c */
|
||||
};
|
||||
|
||||
inline static void uv__req_init(uv_loop_t* loop,
|
||||
|
@ -139,8 +140,6 @@ int uv__stream_open(uv_stream_t*, int fd, int flags);
|
|||
void uv__stream_destroy(uv_stream_t* stream);
|
||||
void uv__server_io(uv_loop_t* loop, uv__io_t* watcher, int events);
|
||||
int uv__accept(int sockfd);
|
||||
int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr,
|
||||
socklen_t addrlen, uv_connect_cb cb);
|
||||
|
||||
/* tcp */
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
|
||||
|
|
|
@ -784,12 +784,15 @@ static void uv__stream_connect(uv_stream_t* stream) {
|
|||
if (error == EINPROGRESS)
|
||||
return;
|
||||
|
||||
if (error == 0)
|
||||
uv__io_start(stream->loop, &stream->read_watcher);
|
||||
|
||||
stream->connect_req = NULL;
|
||||
uv__req_unregister(stream->loop, req);
|
||||
|
||||
/* Hack. See uv__connect() in tcp.c */
|
||||
if (stream->flags & UV_TCP_CONNECTING) {
|
||||
assert(stream->type == UV_TCP);
|
||||
uv__handle_stop(stream);
|
||||
}
|
||||
|
||||
if (req->cb) {
|
||||
uv__set_sys_error(stream->loop, error);
|
||||
req->cb(req, error ? -1 : 0);
|
||||
|
@ -797,65 +800,6 @@ static void uv__stream_connect(uv_stream_t* stream) {
|
|||
}
|
||||
|
||||
|
||||
int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr,
|
||||
socklen_t addrlen, uv_connect_cb cb) {
|
||||
int sockfd;
|
||||
int r;
|
||||
|
||||
if (stream->type != UV_TCP)
|
||||
return uv__set_sys_error(stream->loop, ENOTSOCK);
|
||||
|
||||
if (stream->connect_req)
|
||||
return uv__set_sys_error(stream->loop, EALREADY);
|
||||
|
||||
if (stream->fd <= 0) {
|
||||
sockfd = uv__socket(addr->sa_family, SOCK_STREAM, 0);
|
||||
|
||||
if (sockfd == -1)
|
||||
return uv__set_sys_error(stream->loop, errno);
|
||||
|
||||
if (uv__stream_open(stream,
|
||||
sockfd,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
stream->delayed_error = 0;
|
||||
|
||||
do
|
||||
r = connect(stream->fd, addr, addrlen);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1) {
|
||||
if (errno == EINPROGRESS)
|
||||
; /* not an error */
|
||||
else if (errno == ECONNREFUSED)
|
||||
/* If we get a ECONNREFUSED wait until the next tick to report the
|
||||
* error. Solaris wants to report immediately--other unixes want to
|
||||
* wait.
|
||||
*/
|
||||
stream->delayed_error = errno;
|
||||
else
|
||||
return uv__set_sys_error(stream->loop, errno);
|
||||
}
|
||||
|
||||
uv__req_init(stream->loop, req, UV_CONNECT);
|
||||
req->cb = cb;
|
||||
req->handle = stream;
|
||||
ngx_queue_init(&req->queue);
|
||||
stream->connect_req = req;
|
||||
|
||||
uv__io_start(stream->loop, &stream->write_watcher);
|
||||
|
||||
if (stream->delayed_error)
|
||||
uv__io_feed(stream->loop, &stream->write_watcher, UV__IO_WRITE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt,
|
||||
uv_stream_t* send_handle, uv_write_cb cb) {
|
||||
int empty_queue;
|
||||
|
|
|
@ -34,6 +34,26 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
|
|||
}
|
||||
|
||||
|
||||
static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
|
||||
int sockfd;
|
||||
|
||||
if (handle->fd != -1)
|
||||
return 0;
|
||||
|
||||
sockfd = uv__socket(domain, SOCK_STREAM, 0);
|
||||
|
||||
if (sockfd == -1)
|
||||
return uv__set_sys_error(handle->loop, errno);
|
||||
|
||||
if (uv__stream_open((uv_stream_t*)handle, sockfd, flags)) {
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__bind(uv_tcp_t* tcp,
|
||||
int domain,
|
||||
struct sockaddr* addr,
|
||||
|
@ -44,23 +64,8 @@ static int uv__bind(uv_tcp_t* tcp,
|
|||
saved_errno = errno;
|
||||
status = -1;
|
||||
|
||||
if (tcp->fd < 0) {
|
||||
if ((tcp->fd = uv__socket(domain, SOCK_STREAM, 0)) == -1) {
|
||||
uv__set_sys_error(tcp->loop, errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (uv__stream_open((uv_stream_t*)tcp,
|
||||
tcp->fd,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
|
||||
close(tcp->fd);
|
||||
tcp->fd = -1;
|
||||
status = -2;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
assert(tcp->fd >= 0);
|
||||
if (maybe_new_socket(tcp, domain, UV_STREAM_READABLE|UV_STREAM_WRITABLE))
|
||||
return -1;
|
||||
|
||||
tcp->delayed_error = 0;
|
||||
if (bind(tcp->fd, addr, addrsize) == -1) {
|
||||
|
@ -79,6 +84,67 @@ out:
|
|||
}
|
||||
|
||||
|
||||
static int uv__connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
struct sockaddr* addr,
|
||||
socklen_t addrlen,
|
||||
uv_connect_cb cb) {
|
||||
int r;
|
||||
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
if (handle->connect_req)
|
||||
return uv__set_sys_error(handle->loop, EALREADY);
|
||||
|
||||
if (maybe_new_socket(handle,
|
||||
addr->sa_family,
|
||||
UV_STREAM_READABLE|UV_STREAM_WRITABLE)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle->delayed_error = 0;
|
||||
|
||||
do
|
||||
r = connect(handle->fd, addr, addrlen);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1) {
|
||||
if (errno == EINPROGRESS) {
|
||||
/* Not an error. However, we need to keep the event loop from spinning
|
||||
* while the connection is in progress. Artificially start the handle
|
||||
* and stop it again in uv__stream_connect() in stream.c. Yes, it's a
|
||||
* hack but there's no good alternative, the v0.8 ABI is frozen.
|
||||
*/
|
||||
if (!uv__is_active(handle)) {
|
||||
handle->flags |= UV_TCP_CONNECTING;
|
||||
uv__handle_start(handle);
|
||||
}
|
||||
}
|
||||
else if (errno == ECONNREFUSED)
|
||||
/* If we get a ECONNREFUSED wait until the next tick to report the
|
||||
* error. Solaris wants to report immediately--other unixes want to
|
||||
* wait.
|
||||
*/
|
||||
handle->delayed_error = errno;
|
||||
else
|
||||
return uv__set_sys_error(handle->loop, errno);
|
||||
}
|
||||
|
||||
uv__req_init(handle->loop, req, UV_CONNECT);
|
||||
req->cb = cb;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
ngx_queue_init(&req->queue);
|
||||
handle->connect_req = req;
|
||||
|
||||
uv__io_start(handle->loop, &handle->write_watcher);
|
||||
|
||||
if (handle->delayed_error)
|
||||
uv__io_feed(handle->loop, &handle->write_watcher, UV__IO_WRITE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr) {
|
||||
return uv__bind(handle,
|
||||
AF_INET,
|
||||
|
@ -170,33 +236,14 @@ out:
|
|||
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
int r;
|
||||
if (tcp->delayed_error)
|
||||
return uv__set_sys_error(tcp->loop, tcp->delayed_error);
|
||||
|
||||
if (tcp->delayed_error) {
|
||||
uv__set_sys_error(tcp->loop, tcp->delayed_error);
|
||||
if (maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tcp->fd < 0) {
|
||||
if ((tcp->fd = uv__socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
uv__set_sys_error(tcp->loop, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_STREAM_READABLE)) {
|
||||
close(tcp->fd);
|
||||
tcp->fd = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
assert(tcp->fd >= 0);
|
||||
|
||||
r = listen(tcp->fd, backlog);
|
||||
if (r < 0) {
|
||||
uv__set_sys_error(tcp->loop, errno);
|
||||
return -1;
|
||||
}
|
||||
if (listen(tcp->fd, backlog))
|
||||
return uv__set_sys_error(tcp->loop, errno);
|
||||
|
||||
tcp->connection_cb = cb;
|
||||
|
||||
|
@ -209,37 +256,31 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
|||
|
||||
|
||||
int uv__tcp_connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
struct sockaddr_in address,
|
||||
uv_connect_cb cb) {
|
||||
int saved_errno = errno;
|
||||
uv_tcp_t* handle,
|
||||
struct sockaddr_in addr,
|
||||
uv_connect_cb cb) {
|
||||
int saved_errno;
|
||||
int status;
|
||||
|
||||
status = uv__connect(req,
|
||||
(uv_stream_t*)handle,
|
||||
(struct sockaddr*)&address,
|
||||
sizeof address,
|
||||
cb);
|
||||
|
||||
saved_errno = errno;
|
||||
status = uv__connect(req, handle, (struct sockaddr*)&addr, sizeof addr, cb);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_connect6(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
struct sockaddr_in6 address,
|
||||
uv_connect_cb cb) {
|
||||
int saved_errno = errno;
|
||||
uv_tcp_t* handle,
|
||||
struct sockaddr_in6 addr,
|
||||
uv_connect_cb cb) {
|
||||
int saved_errno;
|
||||
int status;
|
||||
|
||||
status = uv__connect(req,
|
||||
(uv_stream_t*)handle,
|
||||
(struct sockaddr*)&address,
|
||||
sizeof address,
|
||||
cb);
|
||||
|
||||
saved_errno = errno;
|
||||
status = uv__connect(req, handle, (struct sockaddr*)&addr, sizeof addr, cb);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
#include <string.h> /* strlen */
|
||||
|
||||
static ares_channel channel;
|
||||
static struct ares_options options;
|
||||
static int optmask;
|
||||
|
||||
static int ares_bynamecallbacks;
|
||||
static int bynamecallbacksig;
|
||||
|
@ -63,19 +61,12 @@ static void aresbyaddrcallback( void *arg,
|
|||
}
|
||||
|
||||
|
||||
static void prep_tcploopback() {
|
||||
/* for test, use echo server - TCP port TEST_PORT on loopback */
|
||||
struct sockaddr_in test_server = uv_ip4_addr("127.0.0.1", 0);
|
||||
int rc;
|
||||
|
||||
optmask = ARES_OPT_SERVERS | ARES_OPT_TCP_PORT | ARES_OPT_FLAGS;
|
||||
options.servers = &test_server.sin_addr;
|
||||
options.nservers = 1;
|
||||
options.tcp_port = htons(TEST_PORT);
|
||||
options.flags = ARES_FLAG_USEVC;
|
||||
|
||||
rc = uv_ares_init_options(uv_default_loop(), &channel, &options, optmask);
|
||||
ASSERT(rc == ARES_SUCCESS);
|
||||
static void setup_cares() {
|
||||
int r;
|
||||
struct ares_options options;
|
||||
memset(&options, 0, sizeof options);
|
||||
r = uv_ares_init_options(uv_default_loop(), &channel, &options, 0);
|
||||
ASSERT(r == ARES_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
@ -91,7 +82,7 @@ TEST_IMPL(gethostbyname) {
|
|||
}
|
||||
|
||||
printf("Start basic gethostbyname test\n");
|
||||
prep_tcploopback();
|
||||
setup_cares();
|
||||
|
||||
ares_bynamecallbacks = 0;
|
||||
bynamecallbacksig = 7;
|
||||
|
@ -112,7 +103,7 @@ TEST_IMPL(gethostbyname) {
|
|||
/* two sequential call on new channel */
|
||||
|
||||
printf("Start gethostbyname and gethostbyaddr sequential test\n");
|
||||
prep_tcploopback();
|
||||
setup_cares();
|
||||
|
||||
ares_bynamecallbacks = 0;
|
||||
bynamecallbacksig = 7;
|
||||
|
@ -151,7 +142,7 @@ TEST_IMPL(gethostbyname) {
|
|||
/* two simultaneous calls on new channel */
|
||||
|
||||
printf("Start gethostbyname and gethostbyaddr concurrent test\n");
|
||||
prep_tcploopback();
|
||||
setup_cares();
|
||||
|
||||
ares_bynamecallbacks = 0;
|
||||
bynamecallbacksig = 7;
|
||||
|
|
|
@ -56,6 +56,7 @@ TEST_DECLARE (tcp_close)
|
|||
TEST_DECLARE (tcp_flags)
|
||||
TEST_DECLARE (tcp_write_error)
|
||||
TEST_DECLARE (tcp_write_to_half_open_connection)
|
||||
TEST_DECLARE (tcp_unexpected_read)
|
||||
TEST_DECLARE (tcp_bind6_error_addrinuse)
|
||||
TEST_DECLARE (tcp_bind6_error_addrnotavail)
|
||||
TEST_DECLARE (tcp_bind6_error_fault)
|
||||
|
@ -251,6 +252,7 @@ TASK_LIST_START
|
|||
TEST_ENTRY (tcp_flags)
|
||||
TEST_ENTRY (tcp_write_error)
|
||||
TEST_ENTRY (tcp_write_to_half_open_connection)
|
||||
TEST_ENTRY (tcp_unexpected_read)
|
||||
|
||||
TEST_ENTRY (tcp_bind6_error_addrinuse)
|
||||
TEST_ENTRY (tcp_bind6_error_addrnotavail)
|
||||
|
@ -342,7 +344,6 @@ TASK_LIST_START
|
|||
TEST_ENTRY (getaddrinfo_concurrent)
|
||||
|
||||
TEST_ENTRY (gethostbyname)
|
||||
TEST_HELPER (gethostbyname, tcp4_echo_server)
|
||||
|
||||
TEST_ENTRY (getsockname_tcp)
|
||||
TEST_ENTRY (getsockname_udp)
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/* 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_check_t check_handle;
|
||||
static uv_timer_t timer_handle;
|
||||
static uv_tcp_t server_handle;
|
||||
static uv_tcp_t client_handle;
|
||||
static uv_tcp_t peer_handle;
|
||||
static uv_write_t write_req;
|
||||
static uv_connect_t connect_req;
|
||||
|
||||
static unsigned long ticks; /* event loop ticks */
|
||||
|
||||
|
||||
static void check_cb(uv_check_t* handle, int status) {
|
||||
ticks++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle, int status) {
|
||||
uv_close((uv_handle_t*) &check_handle, NULL);
|
||||
uv_close((uv_handle_t*) &timer_handle, NULL);
|
||||
uv_close((uv_handle_t*) &server_handle, NULL);
|
||||
uv_close((uv_handle_t*) &client_handle, NULL);
|
||||
uv_close((uv_handle_t*) &peer_handle, NULL);
|
||||
}
|
||||
|
||||
|
||||
static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
|
||||
ASSERT(0 && "alloc_cb should not have been called");
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
|
||||
ASSERT(0 && "read_cb should not have been called");
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
ASSERT(req->handle == (uv_stream_t*) &client_handle);
|
||||
ASSERT(0 == status);
|
||||
}
|
||||
|
||||
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
ASSERT(req->handle == (uv_stream_t*) &peer_handle);
|
||||
ASSERT(0 == status);
|
||||
}
|
||||
|
||||
|
||||
static void connection_cb(uv_stream_t* handle, int status) {
|
||||
uv_buf_t buf;
|
||||
|
||||
buf = uv_buf_init("PING", 4);
|
||||
|
||||
ASSERT(0 == status);
|
||||
ASSERT(0 == uv_tcp_init(uv_default_loop(), &peer_handle));
|
||||
ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle));
|
||||
ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb));
|
||||
ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &peer_handle,
|
||||
&buf, 1, write_cb));
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_unexpected_read) {
|
||||
struct sockaddr_in addr;
|
||||
uv_loop_t* loop;
|
||||
|
||||
addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
|
||||
loop = uv_default_loop();
|
||||
|
||||
ASSERT(0 == uv_timer_init(loop, &timer_handle));
|
||||
ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1000, 0));
|
||||
ASSERT(0 == uv_check_init(loop, &check_handle));
|
||||
ASSERT(0 == uv_check_start(&check_handle, check_cb));
|
||||
ASSERT(0 == uv_tcp_init(loop, &server_handle));
|
||||
ASSERT(0 == uv_tcp_init(loop, &client_handle));
|
||||
ASSERT(0 == uv_tcp_bind(&server_handle, addr));
|
||||
ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb));
|
||||
ASSERT(0 == uv_tcp_connect(&connect_req, &client_handle, addr, connect_cb));
|
||||
ASSERT(0 == uv_run(loop));
|
||||
|
||||
/* This is somewhat inexact but the idea is that the event loop should not
|
||||
* start busy looping when the server sends a message and the client isn't
|
||||
* reading.
|
||||
*/
|
||||
ASSERT(ticks <= 10);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -355,6 +355,7 @@
|
|||
'test/test-tcp-write-error.c',
|
||||
'test/test-tcp-write-to-half-open-connection.c',
|
||||
'test/test-tcp-writealot.c',
|
||||
'test/test-tcp-unexpected-read.c',
|
||||
'test/test-threadpool.c',
|
||||
'test/test-mutexes.c',
|
||||
'test/test-thread.c',
|
||||
|
|
Loading…
Reference in New Issue