From 0cb2213db0e617377f78a11768c17956530dc19b Mon Sep 17 00:00:00 2001 From: Igor Zinkovsky Date: Tue, 25 Oct 2011 13:07:29 -0700 Subject: [PATCH] windows: when sharing a server socket, only call listen in the parent process --- src/win/internal.h | 52 +++++++++++++++++++++++++--------------------- src/win/pipe.c | 4 ++-- src/win/tcp.c | 39 +++++++++++++++++++++++++++++++++- test/run-tests.c | 21 ++++++++++++++----- test/test-ipc.c | 14 +++++++++++-- test/test-list.h | 7 ++++--- 6 files changed, 100 insertions(+), 37 deletions(-) diff --git a/src/win/internal.h b/src/win/internal.h index 55e02df57e..ec6e3b2bfc 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -44,30 +44,31 @@ void uv_process_timers(uv_loop_t* loop); */ /* Private uv_handle flags */ -#define UV_HANDLE_CLOSING 0x000001 -#define UV_HANDLE_CLOSED 0x000002 -#define UV_HANDLE_BOUND 0x000004 -#define UV_HANDLE_LISTENING 0x000008 -#define UV_HANDLE_CONNECTION 0x000010 -#define UV_HANDLE_CONNECTED 0x000020 -#define UV_HANDLE_READING 0x000040 -#define UV_HANDLE_ACTIVE 0x000040 -#define UV_HANDLE_EOF 0x000080 -#define UV_HANDLE_SHUTTING 0x000100 -#define UV_HANDLE_SHUT 0x000200 -#define UV_HANDLE_ENDGAME_QUEUED 0x000400 -#define UV_HANDLE_BIND_ERROR 0x001000 -#define UV_HANDLE_IPV6 0x002000 -#define UV_HANDLE_PIPESERVER 0x004000 -#define UV_HANDLE_READ_PENDING 0x008000 -#define UV_HANDLE_UV_ALLOCED 0x010000 -#define UV_HANDLE_SYNC_BYPASS_IOCP 0x020000 -#define UV_HANDLE_ZERO_READ 0x040000 -#define UV_HANDLE_TTY_RAW 0x080000 -#define UV_HANDLE_EMULATE_IOCP 0x100000 -#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x200000 -#define UV_HANDLE_TTY_SAVED_POSITION 0x400000 -#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x800000 +#define UV_HANDLE_CLOSING 0x0000001 +#define UV_HANDLE_CLOSED 0x0000002 +#define UV_HANDLE_BOUND 0x0000004 +#define UV_HANDLE_LISTENING 0x0000008 +#define UV_HANDLE_CONNECTION 0x0000010 +#define UV_HANDLE_CONNECTED 0x0000020 +#define UV_HANDLE_READING 0x0000040 +#define UV_HANDLE_ACTIVE 0x0000040 +#define UV_HANDLE_EOF 0x0000080 +#define UV_HANDLE_SHUTTING 0x0000100 +#define UV_HANDLE_SHUT 0x0000200 +#define UV_HANDLE_ENDGAME_QUEUED 0x0000400 +#define UV_HANDLE_BIND_ERROR 0x0001000 +#define UV_HANDLE_IPV6 0x0002000 +#define UV_HANDLE_PIPESERVER 0x0004000 +#define UV_HANDLE_READ_PENDING 0x0008000 +#define UV_HANDLE_UV_ALLOCED 0x0010000 +#define UV_HANDLE_SYNC_BYPASS_IOCP 0x0020000 +#define UV_HANDLE_ZERO_READ 0x0040000 +#define UV_HANDLE_TTY_RAW 0x0080000 +#define UV_HANDLE_EMULATE_IOCP 0x0100000 +#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x0200000 +#define UV_HANDLE_TTY_SAVED_POSITION 0x0400000 +#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x0800000 +#define UV_HANDLE_SHARED_TCP_SERVER 0x1000000 void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle); void uv_process_endgames(uv_loop_t* loop); @@ -140,6 +141,9 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info); +int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, + LPWSAPROTOCOL_INFOW protocol_info); + /* * UDP diff --git a/src/win/pipe.c b/src/win/pipe.c index 65d1f11cd1..eb7fd33cc0 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -989,9 +989,9 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req, /* Use the IPC framing protocol. */ if (send_handle) { tcp_send_handle = (uv_tcp_t*)send_handle; - if (WSADuplicateSocketW(tcp_send_handle->socket, handle->ipc_pid, + + if (uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid, &ipc_frame.socket_info)) { - uv__set_sys_error(loop, WSAGetLastError()); return -1; } ipc_frame.header.flags |= UV_IPC_UV_STREAM; diff --git a/src/win/tcp.c b/src/win/tcp.c index 0ff6890bcf..08869fa026 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -420,7 +420,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { } } - if (listen(handle->socket, backlog) == SOCKET_ERROR) { + if (!(handle->flags & UV_HANDLE_SHARED_TCP_SERVER) && + listen(handle->socket, backlog) == SOCKET_ERROR) { uv__set_sys_error(loop, WSAGetLastError()); return -1; } @@ -953,6 +954,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info) { } tcp->flags |= UV_HANDLE_BOUND; + tcp->flags |= UV_HANDLE_SHARED_TCP_SERVER; return uv_tcp_set_socket(tcp->loop, tcp, socket, 1); } @@ -968,3 +970,38 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { uv__set_artificial_error(handle->loop, UV_ENOSYS); return -1; } + + +int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, + LPWSAPROTOCOL_INFOW protocol_info) { + if (!(handle->flags & UV_HANDLE_CONNECTION)) { + /* + * We're about to share the socket with another process. Because + * this is a server socket, we assume that the other process will + * be accepting conections on this socket. So, before sharing the + * socket with another process, we call listen here in the parent + * process. This needs to be modified if the socket is shared with + * another process for anything other than accepting connections. + */ + + if (!(handle->flags & UV_HANDLE_LISTENING)) { + if (!(handle->flags & UV_HANDLE_BOUND)) { + uv__set_artificial_error(handle->loop, UV_EINVAL); + return -1; + } + if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { + uv__set_sys_error(handle->loop, WSAGetLastError()); + return -1; + } + } + + handle->flags |= UV_HANDLE_SHARED_TCP_SERVER; + } + + if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) { + uv__set_sys_error(handle->loop, WSAGetLastError()); + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/test/run-tests.c b/test/run-tests.c index 7fb48d14b6..1d8b0bcf50 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -112,7 +112,7 @@ static void ipc_on_connection(uv_stream_t* server, int status) { } -static int ipc_helper() { +static int ipc_helper(int listen_after_write) { /* * This is launched from test-ipc.c. stdin is a duplex channel that we * over which a handle will be transmitted. In this initial version only @@ -135,14 +135,21 @@ static int ipc_helper() { r = uv_tcp_bind(&tcp_server, uv_ip4_addr("0.0.0.0", TEST_PORT)); ASSERT(r == 0); - r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection); - ASSERT(r == 0); + if (!listen_after_write) { + r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection); + ASSERT(r == 0); + } buf = uv_buf_init("hello\n", 6); r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1, (uv_stream_t*)&tcp_server, NULL); ASSERT(r == 0); + if (listen_after_write) { + r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection); + ASSERT(r == 0); + } + r = uv_run(uv_default_loop()); ASSERT(r == 0); @@ -251,8 +258,12 @@ static int maybe_run_test(int argc, char **argv) { return 0; } - if (strcmp(argv[1], "ipc_helper") == 0) { - return ipc_helper(); + if (strcmp(argv[1], "ipc_helper_listen_before_write") == 0) { + return ipc_helper(0); + } + + if (strcmp(argv[1], "ipc_helper_listen_after_write") == 0) { + return ipc_helper(1); } if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) { diff --git a/test/test-ipc.c b/test/test-ipc.c index 5119b59bf5..d1f7bf1009 100644 --- a/test/test-ipc.c +++ b/test/test-ipc.c @@ -184,7 +184,7 @@ static void on_read(uv_pipe_t* pipe, ssize_t nread, uv_buf_t buf, } -TEST_IMPL(ipc) { +int run_ipc_test(const char* helper) { int r; uv_process_options_t options; uv_process_t process; @@ -199,7 +199,7 @@ TEST_IMPL(ipc) { ASSERT(r == 0); exepath[exepath_size] = '\0'; args[0] = exepath; - args[1] = "ipc_helper"; + args[1] = (char*)helper; args[2] = NULL; options.file = exepath; options.args = args; @@ -220,3 +220,13 @@ TEST_IMPL(ipc) { ASSERT(exit_cb_called == 1); return 0; } + + +TEST_IMPL(ipc_listen_before_write) { + return run_ipc_test("ipc_helper_listen_before_write"); +} + + +TEST_IMPL(ipc_listen_after_write) { + return run_ipc_test("ipc_helper_listen_after_write"); +} diff --git a/test/test-list.h b/test/test-list.h index 19c9991326..a29230e8bb 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -21,7 +21,8 @@ TEST_DECLARE (tty) TEST_DECLARE (stdio_over_pipes) -TEST_DECLARE (ipc) +TEST_DECLARE (ipc_listen_before_write) +TEST_DECLARE (ipc_listen_after_write) TEST_DECLARE (tcp_ping_pong) TEST_DECLARE (tcp_ping_pong_v6) TEST_DECLARE (tcp_ref) @@ -120,8 +121,8 @@ HELPER_DECLARE (pipe_echo_server) TASK_LIST_START TEST_ENTRY (tty) TEST_ENTRY (stdio_over_pipes) - TEST_ENTRY (ipc) - + TEST_ENTRY (ipc_listen_before_write) + TEST_ENTRY (ipc_listen_after_write) TEST_ENTRY (tcp_ref)