From 76089b11eb27675bad4d929d34cc43639f0e54ee Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Jan 2010 00:13:13 +0100 Subject: native: fallback to another port if the default port is taken Unless the port number is explicitly configured we will now fallback to a kernel picked port if the one we'd like by default we cannot get. http://pulseaudio.org/ticket/773 --- src/modules/module-protocol-stub.c | 13 +++++--- src/pulsecore/socket-server.c | 65 ++++++++++++++++++++++++++------------ src/pulsecore/socket-server.h | 16 +++++----- 3 files changed, 61 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 5b351d19..e0e7aa1f 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -246,6 +246,7 @@ int pa__init(pa_module*m) { #if defined(USE_TCP_SOCKETS) uint32_t port = IPV4_PORT; + pa_bool_t port_fallback = TRUE; const char *listen_on; #else int r; @@ -293,6 +294,10 @@ int pa__init(pa_module*m) { #endif #if defined(USE_TCP_SOCKETS) + + if (pa_modargs_get_value(ma, "port", NULL)) + port_fallback = FALSE; + if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { pa_log("port= expects a numerical argument between 1 and 65535."); goto fail; @@ -302,14 +307,14 @@ int pa__init(pa_module*m) { if (listen_on) { # ifdef HAVE_IPV6 - u->socket_server_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, (uint16_t) port, TCPWRAP_SERVICE); + u->socket_server_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE); # endif - u->socket_server_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, (uint16_t) port, TCPWRAP_SERVICE); + u->socket_server_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE); } else { # ifdef HAVE_IPV6 - u->socket_server_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, (uint16_t) port, TCPWRAP_SERVICE); + u->socket_server_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE); # endif - u->socket_server_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, (uint16_t) port, TCPWRAP_SERVICE); + u->socket_server_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE); } # ifdef HAVE_IPV6 diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index 5d55de3e..3b7c6973 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -86,7 +86,12 @@ struct pa_socket_server { pa_io_event *io_event; pa_mainloop_api *mainloop; - enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; + enum { + SOCKET_SERVER_GENERIC, + SOCKET_SERVER_IPV4, + SOCKET_SERVER_UNIX, + SOCKET_SERVER_IPV6 + } type; }; static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { @@ -150,15 +155,11 @@ pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { pa_assert(m); pa_assert(fd >= 0); - s = pa_xnew(pa_socket_server, 1); + s = pa_xnew0(pa_socket_server, 1); PA_REFCNT_INIT(s); s->fd = fd; - s->filename = NULL; - s->on_connection = NULL; - s->userdata = NULL; - s->tcpwrap_service = NULL; - s->mainloop = m; + pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s)); s->type = SOCKET_SERVER_GENERIC; @@ -233,7 +234,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file #endif /* HAVE_SYS_UN_H */ -pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) { +pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) { pa_socket_server *ss; int fd = -1; struct sockaddr_in sa; @@ -260,8 +261,19 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address sa.sin_addr.s_addr = htonl(address); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + + if (errno == EADDRINUSE && fallback) { + sa.sin_port = 0; + + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0) + goto good; + } + pa_log("bind(): %s", pa_cstrerror(errno)); goto fail; + + good: + ; } if (listen(fd, 5) < 0) { @@ -284,7 +296,7 @@ fail: } #ifdef HAVE_IPV6 -pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service) { +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) { pa_socket_server *ss; int fd = -1; struct sockaddr_in6 sa; @@ -318,8 +330,19 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad memcpy(sa.sin6_addr.s6_addr, address, 16); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + + if (errno == EADDRINUSE && fallback) { + sa.sin6_port = 0; + + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0) + goto good; + } + pa_log("bind(): %s", pa_cstrerror(errno)); goto fail; + + good: + ; } if (listen(fd, 5) < 0) { @@ -342,39 +365,39 @@ fail: } #endif -pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { +pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) { pa_assert(m); pa_assert(port > 0); - return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service); + return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, fallback, tcpwrap_service); } #ifdef HAVE_IPV6 -pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { +pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) { pa_assert(m); pa_assert(port > 0); - return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service); + return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, fallback, tcpwrap_service); } #endif -pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { +pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) { pa_assert(m); pa_assert(port > 0); - return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service); + return pa_socket_server_new_ipv4(m, INADDR_ANY, port, fallback, tcpwrap_service); } #ifdef HAVE_IPV6 -pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { +pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) { pa_assert(m); pa_assert(port > 0); - return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service); + return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, fallback, tcpwrap_service); } #endif -pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { +pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) { struct in_addr ipv4; pa_assert(m); @@ -382,13 +405,13 @@ pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const cha pa_assert(port > 0); if (inet_pton(AF_INET, name, &ipv4) > 0) - return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service); + return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, fallback, tcpwrap_service); return NULL; } #ifdef HAVE_IPV6 -pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { +pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) { struct in6_addr ipv6; pa_assert(m); @@ -396,7 +419,7 @@ pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const cha pa_assert(port > 0); if (inet_pton(AF_INET6, name, &ipv6) > 0) - return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service); + return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, fallback, tcpwrap_service); return NULL; } diff --git a/src/pulsecore/socket-server.h b/src/pulsecore/socket-server.h index 72b6eda4..16da07b8 100644 --- a/src/pulsecore/socket-server.h +++ b/src/pulsecore/socket-server.h @@ -33,15 +33,15 @@ typedef struct pa_socket_server pa_socket_server; pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd); pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename); -pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service); #ifdef HAVE_IPV6 -pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, pa_bool_t fallback, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service); #endif void pa_socket_server_unref(pa_socket_server*s); -- cgit