mirror of
https://github.com/libuv/libuv
synced 2025-03-28 21:13:16 +00:00
unix: keep track of bound sockets sent via spawn
We use the UV_HANDLE_BOUND flag to mark a socket as bound to a port. We need to do this for sockets that are sent from another process as well as sockets that created by the process itself. First check if the port number is non-zero. If yes then mark it as bound. PR-URL: https://github.com/libuv/libuv/pull/1348 Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
This commit is contained in:
parent
88d716e126
commit
c5dd2d4218
101
src/unix/tcp.c
101
src/unix/tcp.c
@ -28,15 +28,12 @@
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
|
||||
static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t slen;
|
||||
int sockfd;
|
||||
int err;
|
||||
|
||||
if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = uv__socket(domain, SOCK_STREAM, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -48,10 +45,74 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & UV_HANDLE_BOUND) {
|
||||
/* Bind this new socket to an arbitrary port */
|
||||
slen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen);
|
||||
if (err) {
|
||||
uv__close(sockfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen);
|
||||
if (err) {
|
||||
uv__close(sockfd);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t slen;
|
||||
|
||||
if (domain == AF_UNSPEC) {
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uv__stream_fd(handle) != -1) {
|
||||
|
||||
if (flags & UV_HANDLE_BOUND) {
|
||||
|
||||
if (handle->flags & UV_HANDLE_BOUND) {
|
||||
/* It is already bound to a port. */
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Query to see if tcp socket is bound. */
|
||||
slen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
|
||||
return -errno;
|
||||
|
||||
if ((saddr.ss_family == AF_INET6 &&
|
||||
((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
|
||||
(saddr.ss_family == AF_INET &&
|
||||
((struct sockaddr_in*) &saddr)->sin_port != 0)) {
|
||||
/* Handle is already bound to a port. */
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bind to arbitrary port */
|
||||
if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
|
||||
return -errno;
|
||||
}
|
||||
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new_socket(handle, domain, flags);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
|
||||
int domain;
|
||||
|
||||
@ -260,6 +321,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
static int single_accept = -1;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
if (tcp->delayed_error)
|
||||
@ -273,30 +335,17 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
if (single_accept)
|
||||
tcp->flags |= UV_TCP_SINGLE_ACCEPT;
|
||||
|
||||
err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#ifdef __MVS__
|
||||
flags = UV_STREAM_READABLE;
|
||||
#if defined(__MVS__)
|
||||
/* on zOS the listen call does not bind automatically
|
||||
if the socket is unbound. Hence the manual binding to
|
||||
an arbitrary port is required to be done manually
|
||||
*/
|
||||
|
||||
if (!(tcp->flags & UV_HANDLE_BOUND)) {
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t slen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
|
||||
if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen))
|
||||
return -errno;
|
||||
|
||||
if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen))
|
||||
return -errno;
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
}
|
||||
#endif
|
||||
flags |= UV_HANDLE_BOUND;
|
||||
#endif
|
||||
err = maybe_new_socket(tcp, AF_INET, flags);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (listen(tcp->io_watcher.fd, backlog))
|
||||
return -errno;
|
||||
|
@ -43,6 +43,7 @@ int ipc_send_recv_helper(void);
|
||||
int ipc_helper_bind_twice(void);
|
||||
int stdio_over_pipes_helper(void);
|
||||
int spawn_stdin_stdout(void);
|
||||
int spawn_tcp_server_helper(void);
|
||||
|
||||
static int maybe_run_test(int argc, char **argv);
|
||||
|
||||
@ -111,6 +112,10 @@ static int maybe_run_test(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_tcp_server_helper") == 0) {
|
||||
return spawn_tcp_server_helper();
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper3") == 0) {
|
||||
char buffer[256];
|
||||
ASSERT(buffer == fgets(buffer, sizeof(buffer) - 1, stdin));
|
||||
|
@ -260,6 +260,7 @@ TEST_DECLARE (spawn_closed_process_io)
|
||||
TEST_DECLARE (spawn_reads_child_path)
|
||||
TEST_DECLARE (spawn_inherit_streams)
|
||||
TEST_DECLARE (spawn_quoted_path)
|
||||
TEST_DECLARE (spawn_tcp_server)
|
||||
TEST_DECLARE (fs_poll)
|
||||
TEST_DECLARE (fs_poll_getpath)
|
||||
TEST_DECLARE (kill)
|
||||
@ -743,6 +744,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (spawn_reads_child_path)
|
||||
TEST_ENTRY (spawn_inherit_streams)
|
||||
TEST_ENTRY (spawn_quoted_path)
|
||||
TEST_ENTRY (spawn_tcp_server)
|
||||
TEST_ENTRY (fs_poll)
|
||||
TEST_ENTRY (fs_poll_getpath)
|
||||
TEST_ENTRY (kill)
|
||||
|
@ -50,6 +50,7 @@ static size_t exepath_size = 1024;
|
||||
static char* args[5];
|
||||
static int no_term_signal;
|
||||
static int timer_counter;
|
||||
static uv_tcp_t tcp_server;
|
||||
|
||||
#define OUTPUT_SIZE 1024
|
||||
static char output[OUTPUT_SIZE];
|
||||
@ -622,6 +623,81 @@ TEST_IMPL(spawn_stdio_greater_than_3) {
|
||||
}
|
||||
|
||||
|
||||
int spawn_tcp_server_helper(void) {
|
||||
uv_tcp_t tcp;
|
||||
uv_os_sock_t handle;
|
||||
int r;
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp);
|
||||
ASSERT(r == 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
handle = _get_osfhandle(3);
|
||||
#else
|
||||
handle = 3;
|
||||
#endif
|
||||
r = uv_tcp_open(&tcp, handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Make sure that we can listen on a socket that was
|
||||
* passed down from the parent process
|
||||
*/
|
||||
r = uv_listen((uv_stream_t*)&tcp, SOMAXCONN, NULL);
|
||||
ASSERT(r == 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(spawn_tcp_server) {
|
||||
uv_stdio_container_t stdio[4];
|
||||
struct sockaddr_in addr;
|
||||
int fd;
|
||||
int r;
|
||||
|
||||
init_process_options("spawn_tcp_server_helper", exit_cb);
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
fd = -1;
|
||||
r = uv_tcp_init_ex(uv_default_loop(), &tcp_server, AF_INET);
|
||||
ASSERT(r == 0);
|
||||
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
#ifdef _WIN32
|
||||
r = uv_fileno((uv_handle_t*)&tcp_server, &handle);
|
||||
fd = _open_osfhandle((intptr_t) handle, 0);
|
||||
#else
|
||||
r = uv_fileno((uv_handle_t*)&tcp_server, &fd);
|
||||
#endif
|
||||
ASSERT(r == 0);
|
||||
ASSERT(fd > 0);
|
||||
|
||||
options.stdio = stdio;
|
||||
options.stdio[0].flags = UV_INHERIT_FD;
|
||||
options.stdio[0].data.fd = 0;
|
||||
options.stdio[1].flags = UV_INHERIT_FD;
|
||||
options.stdio[1].data.fd = 1;
|
||||
options.stdio[2].flags = UV_INHERIT_FD;
|
||||
options.stdio[2].data.fd = 2;
|
||||
options.stdio[3].flags = UV_INHERIT_FD;
|
||||
options.stdio[3].data.fd = fd;
|
||||
options.stdio_count = 4;
|
||||
|
||||
r = uv_spawn(uv_default_loop(), &process, &options);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(exit_cb_called == 1);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(spawn_ignored_stdio) {
|
||||
int r;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user