Skip to content

Commit

Permalink
win: allow bound/connected socket in uv_tcp_open()
Browse files Browse the repository at this point in the history
On Unix you can pass bound and even connected socket to uv_tcp_open
and it will work as expected: you can run uv_listen or other io
functions (uv_read, uv_write) on it without problems.
On windows on the other hand the function always assumes to have clean
socket and for example uv_listen will try to bind it again, and
uv_read/write will return with errors about unreadable streams
(basically invalid internal flags).

To check if socket is already bound uv_tcp_getsockname is called which
on windows returns error when socket is unbound. To further
differentiate connected one from just bound, uv_tcp_getpeername also
returns error but when target socket is not connected.

PR-URL: libuv#1447
Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
  • Loading branch information
Neverous authored and bnoordhuis committed Aug 8, 2017
1 parent 371ca6d commit 6827fa3
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/win/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,8 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
WSAPROTOCOL_INFOW protocol_info;
int opt_len;
int err;
struct sockaddr_storage saddr;
int saddr_len;

/* Detect the address family of the socket. */
opt_len = (int) sizeof protocol_info;
Expand All @@ -1466,6 +1468,19 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
return uv_translate_sys_error(err);
}

/* Support already active socket. */
saddr_len = sizeof(saddr);
if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) {
/* Socket is already bound. */
handle->flags |= UV_HANDLE_BOUND;
saddr_len = sizeof(saddr);
if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) {
/* Socket is already connected. */
uv_connection_init((uv_stream_t*) handle);
handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
}
}

return 0;
}

Expand Down
5 changes: 5 additions & 0 deletions test/test-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ TEST_DECLARE (tcp_try_write)
TEST_DECLARE (tcp_write_queue_order)
TEST_DECLARE (tcp_open)
TEST_DECLARE (tcp_open_twice)
TEST_DECLARE (tcp_open_bound)
TEST_DECLARE (tcp_open_connected)
TEST_DECLARE (tcp_connect_error_after_write)
TEST_DECLARE (tcp_shutdown_after_write)
TEST_DECLARE (tcp_bind_error_addrinuse)
Expand Down Expand Up @@ -491,6 +493,9 @@ TASK_LIST_START
TEST_ENTRY (tcp_open)
TEST_HELPER (tcp_open, tcp4_echo_server)
TEST_ENTRY (tcp_open_twice)
TEST_ENTRY (tcp_open_bound)
TEST_ENTRY (tcp_open_connected)
TEST_HELPER (tcp_open_connected, tcp4_echo_server)

TEST_ENTRY (tcp_shutdown_after_write)
TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server)
Expand Down
57 changes: 57 additions & 0 deletions test/test-tcp-open.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,60 @@ TEST_IMPL(tcp_open_twice) {
MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(tcp_open_bound) {
struct sockaddr_in addr;
uv_tcp_t server;
uv_os_sock_t sock;

startup();
sock = create_tcp_socket();

ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));

ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));

ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr)));

ASSERT(0 == uv_tcp_open(&server, sock));

ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL));

MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(tcp_open_connected) {
struct sockaddr_in addr;
uv_tcp_t client;
uv_os_sock_t sock;
uv_buf_t buf = uv_buf_init("PING", 4);

ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));

startup();
sock = create_tcp_socket();

ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr)));

ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));

ASSERT(0 == uv_tcp_open(&client, sock));

ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb));

ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb));

ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb));

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

ASSERT(shutdown_cb_called == 1);
ASSERT(write_cb_called == 1);
ASSERT(close_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}

0 comments on commit 6827fa3

Please sign in to comment.