1
0
mirror of https://github.com/libuv/libuv synced 2025-03-28 21:13:16 +00:00

unix, win: add ability to create tcp/udp sockets early

Introduce two new APIs:

int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, int flags)
int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, int flags)

The lower 8 bits of the flags field are used for the socket domain.
AF_INET, AF_INET6 and AF_UNSPEC are supported. If AF_UNSPEC is specified
the socket is created lazily, just like uv_{tcp,udp}_init.

Some Windows notes:

getsockname fails with WSAEINVAL if the socket is not bound. This could
potentially be improved by detecting the socket family and filling
the sockaddr_in/6 struct manually.

bind returns WSAEFAULT if we try to bind a socket to the wrong family.
Unix returns EINVAL.

PR-URL: https://github.com/libuv/libuv/pull/400
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
Saúl Ibarra Corretgé 2015-06-17 00:34:58 +02:00
parent 2dddd565fd
commit f8f59824c4
12 changed files with 540 additions and 35 deletions

View File

@ -215,6 +215,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-tcp-close-accept.c \
test/test-tcp-close-while-connecting.c \
test/test-tcp-close.c \
test/test-tcp-create-socket-early.c \
test/test-tcp-connect-error-after-write.c \
test/test-tcp-connect-error.c \
test/test-tcp-connect-timeout.c \
@ -240,6 +241,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-timer.c \
test/test-tty.c \
test/test-udp-bind.c \
test/test-udp-create-socket-early.c \
test/test-udp-dgram-too-big.c \
test/test-udp-ipv6.c \
test/test-udp-multicast-interface.c \

View File

@ -30,7 +30,16 @@ API
.. c:function:: int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle)
Initialize the handle.
Initialize the handle. No socket is created as of yet.
.. c:function:: int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags)
Initialize the handle with the specified flags. At the moment the lower 8 bits
of the `flags` parameter are used as the socket domain. A socket will be created
for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created,
just like :c:func:`uv_tcp_init`.
.. versionadded:: 1.7.0
.. c:function:: int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock)

View File

@ -110,6 +110,15 @@ API
Initialize a new UDP handle. The actual socket is created lazily.
Returns 0 on success.
.. c:function:: int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags)
Initialize the handle with the specified flags. At the moment the lower 8 bits
of the `flags` parameter are used as the socket domain. A socket will be created
for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created,
just like :c:func:`uv_udp_init`.
.. versionadded:: 1.7.0
.. c:function:: int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock)
Opens an existing file descriptor or Windows SOCKET as a UDP handle.

View File

@ -507,6 +507,7 @@ struct uv_tcp_s {
};
UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle);
UV_EXTERN int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags);
UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock);
UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle,
@ -597,6 +598,7 @@ struct uv_udp_send_s {
};
UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
UV_EXTERN int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags);
UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock);
UV_EXTERN int uv_udp_bind(uv_udp_t* handle,
const struct sockaddr* addr,

View File

@ -28,18 +28,14 @@
#include <errno.h>
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
return 0;
}
static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
int sockfd;
int err;
if (uv__stream_fd(handle) != -1)
if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
handle->flags |= flags;
return 0;
}
err = uv__socket(domain, SOCK_STREAM, 0);
if (err < 0)
@ -56,6 +52,40 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
}
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
int domain;
/* Use the lower 8 bits for the domain */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return -EINVAL;
if (flags & ~0xFF)
return -EINVAL;
uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
/* If anything fails beyond this point we need to remove the handle from
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
*/
if (domain != AF_UNSPEC) {
int err = maybe_new_socket(tcp, domain, 0);
if (err) {
QUEUE_REMOVE(&tcp->handle_queue);
return err;
}
}
return 0;
}
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
}
int uv__tcp_bind(uv_tcp_t* tcp,
const struct sockaddr* addr,
unsigned int addrlen,

View File

@ -551,19 +551,45 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
}
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
int domain;
int err;
int fd;
/* Use the lower 8 bits for the domain */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return -EINVAL;
if (flags & ~0xFF)
return -EINVAL;
if (domain != AF_UNSPEC) {
err = uv__socket(domain, SOCK_DGRAM, 0);
if (err < 0)
return err;
fd = err;
} else {
fd = -1;
}
uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
handle->alloc_cb = NULL;
handle->recv_cb = NULL;
handle->send_queue_size = 0;
handle->send_queue_count = 0;
uv__io_init(&handle->io_watcher, uv__udp_io, -1);
uv__io_init(&handle->io_watcher, uv__udp_io, fd);
QUEUE_INIT(&handle->write_queue);
QUEUE_INIT(&handle->write_completed_queue);
return 0;
}
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
}
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
int err;

View File

@ -154,9 +154,18 @@ static int uv_tcp_set_socket(uv_loop_t* loop,
}
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
int domain;
/* Use the lower 8 bits for the domain */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return UV_EINVAL;
if (flags & ~0xFF)
return UV_EINVAL;
uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
handle->tcp.serv.accept_reqs = NULL;
handle->tcp.serv.pending_accepts = NULL;
handle->socket = INVALID_SOCKET;
@ -166,10 +175,39 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
handle->tcp.serv.processed_accepts = 0;
handle->delayed_error = 0;
/* If anything fails beyond this point we need to remove the handle from
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
*/
if (domain != AF_UNSPEC) {
SOCKET sock;
DWORD err;
sock = socket(domain, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
err = WSAGetLastError();
QUEUE_REMOVE(&handle->handle_queue);
return uv_translate_sys_error(err);
}
err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0);
if (err) {
closesocket(sock);
QUEUE_REMOVE(&handle->handle_queue);
return uv_translate_sys_error(err);
}
}
return 0;
}
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
return uv_tcp_init_ex(loop, handle, AF_UNSPEC);
}
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
int err;
unsigned int i;
@ -766,7 +804,7 @@ int uv_tcp_getsockname(const uv_tcp_t* handle,
int* namelen) {
int result;
if (!(handle->flags & UV_HANDLE_BOUND)) {
if (handle->socket == INVALID_SOCKET) {
return UV_EINVAL;
}
@ -788,7 +826,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
int* namelen) {
int result;
if (!(handle->flags & UV_HANDLE_BOUND)) {
if (handle->socket == INVALID_SOCKET) {
return UV_EINVAL;
}

View File

@ -42,7 +42,7 @@ int uv_udp_getsockname(const uv_udp_t* handle,
int* namelen) {
int result;
if (!(handle->flags & UV_HANDLE_BOUND)) {
if (handle->socket == INVALID_SOCKET) {
return UV_EINVAL;
}
@ -123,9 +123,18 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
}
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
int domain;
/* Use the lower 8 bits for the domain */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return UV_EINVAL;
if (flags & ~0xFF)
return UV_EINVAL;
uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
handle->socket = INVALID_SOCKET;
handle->reqs_pending = 0;
handle->activecnt = 0;
@ -133,15 +142,42 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
handle->func_wsarecvfrom = WSARecvFrom;
handle->send_queue_size = 0;
handle->send_queue_count = 0;
uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
handle->recv_req.type = UV_UDP_RECV;
handle->recv_req.data = handle;
/* If anything fails beyond this point we need to remove the handle from
* the handle queue, since it was added by uv__handle_init.
*/
if (domain != AF_UNSPEC) {
SOCKET sock;
DWORD err;
sock = socket(domain, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) {
err = WSAGetLastError();
QUEUE_REMOVE(&handle->handle_queue);
return uv_translate_sys_error(err);
}
err = uv_udp_set_socket(handle->loop, handle, sock, domain);
if (err) {
closesocket(sock);
QUEUE_REMOVE(&handle->handle_queue);
return uv_translate_sys_error(err);
}
}
return 0;
}
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
}
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
uv_udp_recv_stop(handle);
closesocket(handle->socket);
@ -191,25 +227,24 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
closesocket(sock);
return err;
}
if (flags & UV_UDP_REUSEADDR) {
DWORD yes = 1;
/* Set SO_REUSEADDR on the socket. */
if (setsockopt(sock,
SOL_SOCKET,
SO_REUSEADDR,
(char*) &yes,
sizeof yes) == SOCKET_ERROR) {
err = WSAGetLastError();
closesocket(sock);
return err;
}
}
if (addr->sa_family == AF_INET6)
handle->flags |= UV_HANDLE_IPV6;
}
if (flags & UV_UDP_REUSEADDR) {
DWORD yes = 1;
/* Set SO_REUSEADDR on the socket. */
if (setsockopt(handle->socket,
SOL_SOCKET,
SO_REUSEADDR,
(char*) &yes,
sizeof yes) == SOCKET_ERROR) {
err = WSAGetLastError();
return err;
}
}
if (addr->sa_family == AF_INET6)
handle->flags |= UV_HANDLE_IPV6;
if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
/* On windows IPV6ONLY is on by default. */
/* If the user doesn't specify it libuv turns it off. */

View File

@ -81,6 +81,10 @@ TEST_DECLARE (tcp_connect_error_fault)
TEST_DECLARE (tcp_connect_timeout)
TEST_DECLARE (tcp_close_while_connecting)
TEST_DECLARE (tcp_close)
TEST_DECLARE (tcp_create_early)
TEST_DECLARE (tcp_create_early_bad_bind)
TEST_DECLARE (tcp_create_early_bad_domain)
TEST_DECLARE (tcp_create_early_accept)
#ifndef _WIN32
TEST_DECLARE (tcp_close_accept)
TEST_DECLARE (tcp_oob)
@ -96,6 +100,9 @@ TEST_DECLARE (tcp_bind6_error_inval)
TEST_DECLARE (tcp_bind6_localhost_ok)
TEST_DECLARE (udp_bind)
TEST_DECLARE (udp_bind_reuseaddr)
TEST_DECLARE (udp_create_early)
TEST_DECLARE (udp_create_early_bad_bind)
TEST_DECLARE (udp_create_early_bad_domain)
TEST_DECLARE (udp_send_and_recv)
TEST_DECLARE (udp_send_immediate)
TEST_DECLARE (udp_send_unreachable)
@ -413,6 +420,10 @@ TASK_LIST_START
TEST_ENTRY (tcp_connect_timeout)
TEST_ENTRY (tcp_close_while_connecting)
TEST_ENTRY (tcp_close)
TEST_ENTRY (tcp_create_early)
TEST_ENTRY (tcp_create_early_bad_bind)
TEST_ENTRY (tcp_create_early_bad_domain)
TEST_ENTRY (tcp_create_early_accept)
#ifndef _WIN32
TEST_ENTRY (tcp_close_accept)
TEST_ENTRY (tcp_oob)
@ -432,6 +443,9 @@ TASK_LIST_START
TEST_ENTRY (udp_bind)
TEST_ENTRY (udp_bind_reuseaddr)
TEST_ENTRY (udp_create_early)
TEST_ENTRY (udp_create_early_bad_bind)
TEST_ENTRY (udp_create_early_bad_domain)
TEST_ENTRY (udp_send_and_recv)
TEST_ENTRY (udp_send_immediate)
TEST_ENTRY (udp_send_unreachable)

View File

@ -0,0 +1,206 @@
/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
* 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 <string.h>
#ifdef _WIN32
# define INVALID_FD (INVALID_HANDLE_VALUE)
#else
# define INVALID_FD (-1)
#endif
static void on_connect(uv_connect_t* req, int status) {
ASSERT(status == 0);
uv_close((uv_handle_t*) req->handle, NULL);
}
static void on_connection(uv_stream_t* server, int status) {
uv_tcp_t* handle;
int r;
ASSERT(status == 0);
handle = malloc(sizeof(*handle));
ASSERT(handle != NULL);
r = uv_tcp_init_ex(server->loop, handle, AF_INET);
ASSERT(r == 0);
r = uv_accept(server, (uv_stream_t*)handle);
ASSERT(r == UV_EBUSY);
uv_close((uv_handle_t*) server, NULL);
uv_close((uv_handle_t*) handle, (uv_close_cb)free);
}
static void tcp_listener(uv_loop_t* loop, uv_tcp_t* server) {
struct sockaddr_in addr;
int r;
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
r = uv_tcp_init(loop, server);
ASSERT(r == 0);
r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*) server, 128, on_connection);
ASSERT(r == 0);
}
static void tcp_connector(uv_loop_t* loop, uv_tcp_t* client, uv_connect_t* req) {
struct sockaddr_in server_addr;
int r;
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
r = uv_tcp_init(loop, client);
ASSERT(r == 0);
r = uv_tcp_connect(req,
client,
(const struct sockaddr*) &server_addr,
on_connect);
ASSERT(r == 0);
}
TEST_IMPL(tcp_create_early) {
struct sockaddr_in addr;
struct sockaddr_in sockname;
uv_tcp_t client;
uv_os_fd_t fd;
int r, namelen;
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET);
ASSERT(r == 0);
r = uv_fileno((const uv_handle_t*) &client, &fd);
ASSERT(r == 0);
ASSERT(fd != INVALID_FD);
/* Windows returns WSAEINVAL if the socket is not bound */
#ifndef _WIN32
namelen = sizeof sockname;
r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
ASSERT(r == 0);
ASSERT(sockname.sin_family == AF_INET);
#endif
r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
namelen = sizeof sockname;
r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
ASSERT(r == 0);
ASSERT(memcmp(&addr.sin_addr,
&sockname.sin_addr,
sizeof(addr.sin_addr)) == 0);
uv_close((uv_handle_t*) &client, NULL);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(tcp_create_early_bad_bind) {
struct sockaddr_in addr;
uv_tcp_t client;
uv_os_fd_t fd;
int r;
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET6);
ASSERT(r == 0);
r = uv_fileno((const uv_handle_t*) &client, &fd);
ASSERT(r == 0);
ASSERT(fd != INVALID_FD);
/* Windows returns WSAEINVAL if the socket is not bound */
#ifndef _WIN32
{
int namelen;
struct sockaddr_in6 sockname;
namelen = sizeof sockname;
r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
ASSERT(r == 0);
ASSERT(sockname.sin6_family == AF_INET6);
}
#endif
r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0);
#ifndef _WIN32
ASSERT(r == UV_EINVAL);
#else
ASSERT(r == UV_EFAULT);
#endif
uv_close((uv_handle_t*) &client, NULL);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(tcp_create_early_bad_domain) {
uv_tcp_t client;
int r;
r = uv_tcp_init_ex(uv_default_loop(), &client, 47);
ASSERT(r == UV_EINVAL);
r = uv_tcp_init_ex(uv_default_loop(), &client, 1024);
ASSERT(r == UV_EINVAL);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(tcp_create_early_accept) {
uv_tcp_t client, server;
uv_connect_t connect_req;
tcp_listener(uv_default_loop(), &server);
tcp_connector(uv_default_loop(), &client, &connect_req);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY();
return 0;
}

View File

@ -0,0 +1,132 @@
/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
* 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 <string.h>
#ifdef _WIN32
# define INVALID_FD (INVALID_HANDLE_VALUE)
#else
# define INVALID_FD (-1)
#endif
TEST_IMPL(udp_create_early) {
struct sockaddr_in addr;
struct sockaddr_in sockname;
uv_udp_t client;
uv_os_fd_t fd;
int r, namelen;
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET);
ASSERT(r == 0);
r = uv_fileno((const uv_handle_t*) &client, &fd);
ASSERT(r == 0);
ASSERT(fd != INVALID_FD);
/* Windows returns WSAEINVAL if the socket is not bound */
#ifndef _WIN32
namelen = sizeof sockname;
r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
ASSERT(r == 0);
ASSERT(sockname.sin_family == AF_INET);
#endif
r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
namelen = sizeof sockname;
r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
ASSERT(r == 0);
ASSERT(memcmp(&addr.sin_addr,
&sockname.sin_addr,
sizeof(addr.sin_addr)) == 0);
uv_close((uv_handle_t*) &client, NULL);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(udp_create_early_bad_bind) {
struct sockaddr_in addr;
uv_udp_t client;
uv_os_fd_t fd;
int r;
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET6);
ASSERT(r == 0);
r = uv_fileno((const uv_handle_t*) &client, &fd);
ASSERT(r == 0);
ASSERT(fd != INVALID_FD);
/* Windows returns WSAEINVAL if the socket is not bound */
#ifndef _WIN32
{
int namelen;
struct sockaddr_in6 sockname;
namelen = sizeof sockname;
r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
ASSERT(r == 0);
ASSERT(sockname.sin6_family == AF_INET6);
}
#endif
r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
#ifndef _WIN32
ASSERT(r == UV_EINVAL);
#else
ASSERT(r == UV_EFAULT);
#endif
uv_close((uv_handle_t*) &client, NULL);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(udp_create_early_bad_domain) {
uv_udp_t client;
int r;
r = uv_udp_init_ex(uv_default_loop(), &client, 47);
ASSERT(r == UV_EINVAL);
r = uv_udp_init_ex(uv_default_loop(), &client, 1024);
ASSERT(r == UV_EINVAL);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY();
return 0;
}

2
uv.gyp
View File

@ -356,6 +356,7 @@
'test/test-tcp-close.c',
'test/test-tcp-close-accept.c',
'test/test-tcp-close-while-connecting.c',
'test/test-tcp-create-socket-early.c',
'test/test-tcp-connect-error-after-write.c',
'test/test-tcp-shutdown-after-write.c',
'test/test-tcp-flags.c',
@ -384,6 +385,7 @@
'test/test-timer.c',
'test/test-tty.c',
'test/test-udp-bind.c',
'test/test-udp-create-socket-early.c',
'test/test-udp-dgram-too-big.c',
'test/test-udp-ipv6.c',
'test/test-udp-open.c',