tcp: uv_tcp_dualstack()

Explicitly disable/enable dualstack depending on presence of flag set by
uv_tcp_dualstack() function.
This commit is contained in:
Fedor Indutny 2013-03-20 01:14:10 +04:00
parent d1e6be1460
commit 8f15aae52f
26 changed files with 91 additions and 49 deletions

View File

@ -783,6 +783,11 @@ UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle,
*/
UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
enum uv_tcp_flags {
/* Used with uv_tcp_bind, when an IPv6 address is used */
UV_TCP_IPV6ONLY = 1
};
/*
* Bind the handle to an address and port. `addr` should point to an
* initialized struct sockaddr_in or struct sockaddr_in6.
@ -793,8 +798,9 @@ UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
* That is, a successful call to uv_tcp_bind() does not guarantee that
* the call to uv_listen() or uv_tcp_connect() will succeed as well.
*/
UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr);
UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int flags);
UV_EXTERN int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name,
int* namelen);
UV_EXTERN int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name,

View File

@ -155,7 +155,7 @@ static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *addrs) {
CHECK(0 == uv_tcp_init(loop, &sx->tcp_handle));
what = "uv_tcp_bind";
err = uv_tcp_bind(&sx->tcp_handle, &s.addr);
err = uv_tcp_bind(&sx->tcp_handle, &s.addr, 0);
if (err == 0) {
what = "uv_listen";
err = uv_listen((uv_stream_t *) &sx->tcp_handle, 128, on_connection);

View File

@ -58,7 +58,8 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
int uv__tcp_bind(uv_tcp_t* tcp,
const struct sockaddr* addr,
unsigned int addrlen) {
unsigned int addrlen,
unsigned int flags) {
int err;
int on;
@ -72,6 +73,19 @@ int uv__tcp_bind(uv_tcp_t* tcp,
if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
return -errno;
#ifdef IPV6_V6ONLY
if (addr->sa_family == AF_INET6) {
on = (flags & UV_TCP_IPV6ONLY) != 0;
if (setsockopt(tcp->io_watcher.fd,
IPPROTO_IPV6,
IPV6_V6ONLY,
&on,
sizeof on) == -1) {
return -errno;
}
}
#endif
errno = 0;
if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE)
return -errno;

View File

@ -152,7 +152,9 @@ int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) {
}
int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr) {
int uv_tcp_bind(uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int flags) {
unsigned int addrlen;
if (handle->type != UV_TCP)
@ -165,7 +167,7 @@ int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr) {
else
return UV_EINVAL;
return uv__tcp_bind(handle, addr, addrlen);
return uv__tcp_bind(handle, addr, addrlen, flags);
}

View File

@ -61,7 +61,8 @@ enum {
int uv__tcp_bind(uv_tcp_t* tcp,
const struct sockaddr* addr,
unsigned int addrlen);
unsigned int addrlen,
unsigned int flags);
int uv__tcp_connect(uv_connect_t* req,
uv_tcp_t* handle,

View File

@ -237,7 +237,8 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
static int uv_tcp_try_bind(uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen) {
unsigned int addrlen,
unsigned int flags) {
DWORD err;
int r;
@ -261,6 +262,19 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
}
}
#ifdef IPV6_V6ONLY
if (addr->sa_family == AF_INET6) {
int on;
on = (flags & UV_TCP_IPV6ONLY) != 0;
/* TODO: how to handle errors? This may fail if there is no ipv4 stack */
/* available, or when run on XP/2003 which have no support for dualstack */
/* sockets. For now we're silently ignoring the error. */
setsockopt(handle->socket, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof on);
}
#endif
r = bind(handle->socket, addr, addrlen);
if (r == SOCKET_ERROR) {
@ -500,7 +514,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
if (!(handle->flags & UV_HANDLE_BOUND)) {
err = uv_tcp_try_bind(handle,
(const struct sockaddr*) &uv_addr_ip4_any_,
sizeof(uv_addr_ip4_any_));
sizeof(uv_addr_ip4_any_),
0);
if (err)
return err;
}
@ -685,7 +700,7 @@ static int uv_tcp_try_connect(uv_connect_t* req,
} else {
abort();
}
err = uv_tcp_try_bind(handle, bind_addr, addrlen);
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
if (err)
return err;
}
@ -1372,10 +1387,11 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
*/
int uv__tcp_bind(uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen) {
unsigned int addrlen,
unsigned int flags) {
int err;
err = uv_tcp_try_bind(handle, addr, addrlen);
err = uv_tcp_try_bind(handle, addr, addrlen, flags);
if (err)
return uv_translate_sys_error(err);

View File

@ -210,7 +210,8 @@ static void send_listen_handles(uv_handle_type type,
if (type == UV_TCP) {
ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &ctx.server_handle));
ASSERT(0 == uv_tcp_bind((uv_tcp_t*) &ctx.server_handle,
(const struct sockaddr*) &listen_addr));
(const struct sockaddr*) &listen_addr,
0));
}
else
ASSERT(0);

View File

@ -193,7 +193,9 @@ static void pinger_new(void) {
pinger->tcp.data = pinger;
ASSERT(0 == uv_tcp_bind(&pinger->tcp, (const struct sockaddr*) &client_addr));
ASSERT(0 == uv_tcp_bind(&pinger->tcp,
(const struct sockaddr*) &client_addr,
0));
r = uv_tcp_connect(&pinger->connect_req,
&pinger->tcp,

View File

@ -379,7 +379,7 @@ HELPER_IMPL(tcp_pump_server) {
server = (uv_stream_t*)&tcpServer;
r = uv_tcp_init(loop, &tcpServer);
ASSERT(r == 0);
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &listen_addr);
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &listen_addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&tcpServer, MAX_WRITE_HANDLES, connection_cb);
ASSERT(r == 0);

View File

@ -108,7 +108,7 @@ HELPER_IMPL(tcp4_blackhole_server) {
r = uv_tcp_init(loop, &tcp_server);
ASSERT(r == 0);
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb);

View File

@ -311,7 +311,7 @@ static int dns_start(int port) {
return 1;
}
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
if (r) {
/* TODO: Error codes */
fprintf(stderr, "Bind error\n");

View File

@ -229,7 +229,7 @@ static int tcp4_echo_start(int port) {
return 1;
}
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
if (r) {
/* TODO: Error codes */
fprintf(stderr, "Bind error\n");
@ -264,7 +264,7 @@ static int tcp6_echo_start(int port) {
}
/* IPv6 is optional as not all platforms support it */
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6);
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6, 0);
if (r) {
/* show message but return OK */
fprintf(stderr, "IPv6 not supported\n");

View File

@ -101,7 +101,7 @@ static void connection_fail(uv_connect_cb connect_cb) {
/* We are never doing multiple reads/connects at a time anyway. */
/* so these handles can be pre-initialized. */
ASSERT(0 == uv_tcp_bind(&tcp, (const struct sockaddr*) &client_addr));
ASSERT(0 == uv_tcp_bind(&tcp, (const struct sockaddr*) &client_addr, 0));
r = uv_tcp_connect(&req,
&tcp,

View File

@ -108,7 +108,7 @@ static void start_server(void) {
r = uv_tcp_init(uv_default_loop(), server);
ASSERT(r == 0);
r = uv_tcp_bind(server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)server, 128, connection_cb);

View File

@ -49,7 +49,7 @@ TEST_IMPL(emfile) {
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
ASSERT(0 == uv_tcp_init(loop, &server_handle));
ASSERT(0 == uv_tcp_init(loop, &client_handle));
ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr));
ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb));
/* Lower the file descriptor limit and use up all fds save one. */

View File

@ -180,7 +180,7 @@ static int tcp_listener(void) {
return 1;
}
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
if (r) {
fprintf(stderr, "Bind error\n");
return 1;

View File

@ -145,7 +145,7 @@ TEST_IMPL(ipc_send_recv_tcp) {
r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp);
ASSERT(r == 0);
r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = run_test();

View File

@ -375,7 +375,7 @@ TEST_IMPL(listen_with_simultaneous_accepts) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_tcp_simultaneous_accepts(&server, 1);
@ -400,7 +400,7 @@ TEST_IMPL(listen_no_simultaneous_accepts) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_tcp_simultaneous_accepts(&server, 0);
@ -566,7 +566,7 @@ int ipc_helper(int listen_after_write) {
r = uv_tcp_init(uv_default_loop(), &tcp_server);
ASSERT(r == 0);
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
if (!listen_after_write) {
@ -618,7 +618,7 @@ int ipc_helper_tcp_connection(void) {
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection_tcp_conn);

View File

@ -53,7 +53,7 @@ static void start_server(void) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&server, 128, connection_cb);

View File

@ -42,12 +42,12 @@ TEST_IMPL(tcp_bind_error_addrinuse) {
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
r = uv_tcp_init(uv_default_loop(), &server1);
ASSERT(r == 0);
r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_tcp_init(uv_default_loop(), &server2);
ASSERT(r == 0);
r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&server1, 128, NULL);
@ -78,7 +78,7 @@ TEST_IMPL(tcp_bind_error_addrnotavail_1) {
ASSERT(r == 0);
/* It seems that Linux is broken here - bind succeeds. */
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0 || r == UV_EADDRNOTAVAIL);
uv_close((uv_handle_t*)&server, close_cb);
@ -101,7 +101,7 @@ TEST_IMPL(tcp_bind_error_addrnotavail_2) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == UV_EADDRNOTAVAIL);
uv_close((uv_handle_t*)&server, close_cb);
@ -126,7 +126,7 @@ TEST_IMPL(tcp_bind_error_fault) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0);
ASSERT(r == UV_EINVAL);
uv_close((uv_handle_t*)&server, close_cb);
@ -152,9 +152,9 @@ TEST_IMPL(tcp_bind_error_inval) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0);
ASSERT(r == UV_EINVAL);
uv_close((uv_handle_t*)&server, close_cb);
@ -177,7 +177,7 @@ TEST_IMPL(tcp_bind_localhost_ok) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
MAKE_VALGRIND_HAPPY();

View File

@ -43,12 +43,12 @@ TEST_IMPL(tcp_bind6_error_addrinuse) {
r = uv_tcp_init(uv_default_loop(), &server1);
ASSERT(r == 0);
r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_tcp_init(uv_default_loop(), &server2);
ASSERT(r == 0);
r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&server1, 128, NULL);
@ -77,7 +77,7 @@ TEST_IMPL(tcp_bind6_error_addrnotavail) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == UV_EADDRNOTAVAIL);
uv_close((uv_handle_t*)&server, close_cb);
@ -102,7 +102,7 @@ TEST_IMPL(tcp_bind6_error_fault) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0);
ASSERT(r == UV_EINVAL);
uv_close((uv_handle_t*)&server, close_cb);
@ -128,9 +128,9 @@ TEST_IMPL(tcp_bind6_error_inval) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0);
ASSERT(r == UV_EINVAL);
uv_close((uv_handle_t*)&server, close_cb);
@ -153,7 +153,7 @@ TEST_IMPL(tcp_bind6_localhost_ok) {
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
MAKE_VALGRIND_HAPPY();

View File

@ -156,7 +156,7 @@ TEST_IMPL(tcp_close_accept) {
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
ASSERT(0 == uv_tcp_init(loop, &tcp_server));
ASSERT(0 == uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr));
ASSERT(0 == uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0));
ASSERT(0 == uv_listen((uv_stream_t*) &tcp_server,
ARRAY_SIZE(tcp_outgoing),
connection_cb));

View File

@ -85,7 +85,7 @@ static void start_server(uv_loop_t* loop, uv_tcp_t* handle) {
r = uv_tcp_init(loop, handle);
ASSERT(r == 0);
r = uv_tcp_bind(handle, (const struct sockaddr*) &addr);
r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)handle, 128, connection_cb);

View File

@ -110,7 +110,7 @@ static void start_server(void) {
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr));
ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
}

View File

@ -98,7 +98,7 @@ TEST_IMPL(tcp_unexpected_read) {
ASSERT(0 == uv_tcp_init(loop, &server_handle));
ASSERT(0 == uv_tcp_init(loop, &client_handle));
ASSERT(0 == uv_tcp_init(loop, &peer_handle));
ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr));
ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb));
ASSERT(0 == uv_tcp_connect(&connect_req,
&client_handle,

View File

@ -115,7 +115,7 @@ TEST_IMPL(tcp_write_to_half_open_connection) {
r = uv_tcp_init(loop, &tcp_server);
ASSERT(r == 0);
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr);
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&tcp_server, 1, connection_cb);