]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/socket-server.c
win32: Avoid some compiler warnings when cross-compiling for mingw32
[pulseaudio] / src / pulsecore / socket-server.c
index 9885a02b9843f812b43bc0f682b1bd94975b0043..0b0b2a5ce0e2605249957df890132313b24da4b5 100644 (file)
@@ -6,7 +6,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2 of the License,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
@@ -32,9 +32,6 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #ifndef SUN_LEN
     ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
 #endif
 #endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
 
 #ifdef HAVE_LIBWRAP
 #include <tcpd.h>
-#endif
 
-#ifndef HAVE_INET_NTOP
-#include "inet_ntop.h"
+/* Solaris requires that the allow_severity and deny_severity variables be
+ * defined in the client program. */
+#ifdef __sun
+#include <syslog.h>
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
 #endif
 
-#ifndef HAVE_INET_PTON
-#include "inet_pton.h"
-#endif
-
-#include "winsock.h"
+#endif /* HAVE_LIBWRAP */
 
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
 
+#include <pulsecore/socket.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/refcnt.h>
+#include <pulsecore/arpa-inet.h>
 
 #include "socket-server.h"
 
@@ -86,7 +81,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) {
@@ -104,13 +104,11 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_ev
 
     pa_socket_server_ref(s);
 
-    if ((nfd = accept(fd, NULL, NULL)) < 0) {
+    if ((nfd = pa_accept_cloexec(fd, NULL, NULL)) < 0) {
         pa_log("accept(): %s", pa_cstrerror(errno));
         goto finish;
     }
 
-    pa_make_fd_cloexec(nfd);
-
     if (!s->on_connection) {
         pa_close(nfd);
         goto finish;
@@ -152,15 +150,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;
@@ -186,20 +180,18 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file
     pa_assert(m);
     pa_assert(filename);
 
-    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+    if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
         pa_log("socket(): %s", pa_cstrerror(errno));
         goto fail;
     }
 
-    pa_make_fd_cloexec(fd);
-
     memset(&sa, 0, sizeof(sa));
     sa.sun_family = AF_UNIX;
     pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
 
     pa_make_socket_low_delay(fd);
 
-    if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) {
+    if (bind(fd, (struct sockaddr*) &sa, (socklen_t) SUN_LEN(&sa)) < 0) {
         pa_log("bind(): %s", pa_cstrerror(errno));
         goto fail;
     }
@@ -237,7 +229,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;
@@ -246,15 +238,13 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address
     pa_assert(m);
     pa_assert(port);
 
-    if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+    if ((fd = pa_socket_cloexec(PF_INET, SOCK_STREAM, 0)) < 0) {
         pa_log("socket(PF_INET): %s", pa_cstrerror(errno));
         goto fail;
     }
 
-    pa_make_fd_cloexec(fd);
-
 #ifdef SO_REUSEADDR
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &on, sizeof(on)) < 0)
         pa_log("setsockopt(): %s", pa_cstrerror(errno));
 #endif
 
@@ -266,8 +256,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) {
@@ -289,7 +290,8 @@ fail:
     return NULL;
 }
 
-pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, 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, pa_bool_t fallback, const char *tcpwrap_service) {
     pa_socket_server *ss;
     int fd = -1;
     struct sockaddr_in6 sa;
@@ -298,22 +300,20 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad
     pa_assert(m);
     pa_assert(port > 0);
 
-    if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
+    if ((fd = pa_socket_cloexec(PF_INET6, SOCK_STREAM, 0)) < 0) {
         pa_log("socket(PF_INET6): %s", pa_cstrerror(errno));
         goto fail;
     }
 
-    pa_make_fd_cloexec(fd);
-
 #ifdef IPV6_V6ONLY
     on = 1;
-    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
+    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *) &on, sizeof(on)) < 0)
         pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno));
 #endif
 
 #ifdef SO_REUSEADDR
     on = 1;
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &on, sizeof(on)) < 0)
         pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno));
 #endif
 
@@ -325,8 +325,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) {
@@ -347,36 +358,41 @@ fail:
 
     return NULL;
 }
+#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);
 }
 
-pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
+#ifdef HAVE_IPV6
+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);
 }
 
-pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
+#ifdef HAVE_IPV6
+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);
@@ -384,12 +400,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;
 }
 
-pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) {
+#ifdef HAVE_IPV6
+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);
@@ -397,10 +414,11 @@ 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;
 }
+#endif
 
 static void socket_server_free(pa_socket_server*s) {
     pa_assert(s);
@@ -441,6 +459,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
     pa_assert(l > 0);
 
     switch (s->type) {
+#ifdef HAVE_IPV6
         case SOCKET_SERVER_IPV6: {
             struct sockaddr_in6 sa;
             socklen_t sa_len = sizeof(sa);
@@ -458,11 +477,13 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
                 pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
 
             } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) {
-                char hn[256];
-                if (!pa_get_host_name(hn, sizeof(hn)))
+                char *id;
+
+                if (!(id = pa_machine_id()))
                     return NULL;
 
-                pa_snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port));
+                pa_snprintf(c, l, "{%s}tcp6:localhost:%u", id, (unsigned) ntohs(sa.sin6_port));
+                pa_xfree(id);
             } else {
                 char ip[INET6_ADDRSTRLEN];
 
@@ -476,6 +497,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
 
             return c;
         }
+#endif
 
         case SOCKET_SERVER_IPV4: {
             struct sockaddr_in sa;
@@ -493,11 +515,13 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
 
                 pa_snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
             } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) {
-                char hn[256];
-                if (!pa_get_host_name(hn, sizeof(hn)))
+                char *id;
+
+                if (!(id = pa_machine_id()))
                     return NULL;
 
-                pa_snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port));
+                pa_snprintf(c, l, "{%s}tcp:localhost:%u", id, (unsigned) ntohs(sa.sin_port));
+                pa_xfree(id);
             } else {
                 char ip[INET_ADDRSTRLEN];
 
@@ -513,15 +537,16 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
         }
 
         case SOCKET_SERVER_UNIX: {
-            char hn[256];
+            char *id;
 
             if (!s->filename)
                 return NULL;
 
-            if (!pa_get_host_name(hn, sizeof(hn)))
+            if (!(id = pa_machine_id()))
                 return NULL;
 
-            pa_snprintf(c, l, "{%s}unix:%s", hn, s->filename);
+            pa_snprintf(c, l, "{%s}unix:%s", id, s->filename);
+            pa_xfree(id);
             return c;
         }