win: allow bound/connected socket in uv_tcp_open()
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: https://github.com/libuv/libuv/pull/1447 Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
parent
371ca6d4b2
commit
6827fa3451
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user