]> 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 b5a6dc3177ba083a670ff3aba040cf70ca9d1013..0b0b2a5ce0e2605249957df890132313b24da4b5 100644 (file)
@@ -1,5 +1,3 @@
-/* $Id$ */
-
 /***
   This file is part of PulseAudio.
 
@@ -8,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
@@ -27,7 +25,6 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/types.h>
@@ -35,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"
 
 struct pa_socket_server {
-    int ref;
+    PA_REFCNT_DECLARE;
     int fd;
     char *filename;
     char *tcpwrap_service;
 
-    void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata);
+    pa_socket_server_on_connection_cb_t on_connection;
     void *userdata;
 
     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_GCC_UNUSED pa_io_event_flags_t f, void *userdata) {
+static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
     pa_socket_server *s = userdata;
     pa_iochannel *io;
     int nfd;
-    assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd);
+
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(s->mainloop == mainloop);
+    pa_assert(s->io_event == e);
+    pa_assert(e);
+    pa_assert(fd >= 0);
+    pa_assert(fd == s->fd);
 
     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_fd_set_cloexec(nfd, 1);
-
     if (!s->on_connection) {
         pa_close(nfd);
         goto finish;
@@ -129,12 +133,11 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U
 
     /* There should be a check for socket type here */
     if (s->type == SOCKET_SERVER_IPV4)
-        pa_socket_tcp_low_delay(fd);
+        pa_make_tcp_socket_low_delay(fd);
     else
-        pa_socket_low_delay(fd);
+        pa_make_socket_low_delay(fd);
 
-    io = pa_iochannel_new(s->mainloop, nfd, nfd);
-    assert(io);
+    pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd));
     s->on_connection(s, io, s->userdata);
 
 finish:
@@ -143,19 +146,16 @@ finish:
 
 pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) {
     pa_socket_server *s;
-    assert(m && fd >= 0);
 
-    s = pa_xmalloc(sizeof(pa_socket_server));
-    s->ref = 1;
-    s->fd = fd;
-    s->filename = NULL;
-    s->on_connection = NULL;
-    s->userdata = NULL;
-    s->tcpwrap_service = NULL;
+    pa_assert(m);
+    pa_assert(fd >= 0);
 
+    s = pa_xnew0(pa_socket_server, 1);
+    PA_REFCNT_INIT(s);
+    s->fd = fd;
     s->mainloop = m;
-    s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s);
-    assert(s->io_event);
+
+    pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s));
 
     s->type = SOCKET_SERVER_GENERIC;
 
@@ -163,8 +163,10 @@ pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) {
 }
 
 pa_socket_server* pa_socket_server_ref(pa_socket_server *s) {
-    assert(s && s->ref >= 1);
-    s->ref++;
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+    PA_REFCNT_INC(s);
     return s;
 }
 
@@ -175,22 +177,21 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file
     struct sockaddr_un sa;
     pa_socket_server *s;
 
-    assert(m && filename);
+    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_fd_set_cloexec(fd, 1);
-
+    memset(&sa, 0, sizeof(sa));
     sa.sun_family = AF_UNIX;
-    strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
-    sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
+    pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
 
-    pa_socket_low_delay(fd);
+    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;
     }
@@ -206,8 +207,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file
         goto fail;
     }
 
-    s = pa_socket_server_new(m, fd);
-    assert(s);
+    pa_assert_se(s = pa_socket_server_new(m, fd));
 
     s->filename = pa_xstrdup(filename);
     s->type = SOCKET_SERVER_UNIX;
@@ -229,27 +229,26 @@ 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;
     int on = 1;
 
-    assert(m && port);
+    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_fd_set_cloexec(fd, 1);
-
 #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
 
-    pa_socket_tcp_low_delay(fd);
+    pa_make_tcp_socket_low_delay(fd);
 
     memset(&sa, 0, sizeof(sa));
     sa.sin_family = AF_INET;
@@ -257,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) {
@@ -280,32 +290,34 @@ 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;
-    int on = 1;
+    int on;
 
-    assert(m && port);
+    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_fd_set_cloexec(fd, 1);
-
 #ifdef IPV6_V6ONLY
-    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
+    on = 1;
+    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
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+    on = 1;
+    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
 
-    pa_socket_tcp_low_delay(fd);
+    pa_make_tcp_socket_low_delay(fd);
 
     memset(&sa, 0, sizeof(sa));
     sa.sin6_family = AF_INET6;
@@ -313,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) {
@@ -335,63 +358,70 @@ fail:
 
     return NULL;
 }
+#endif
 
-pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
-    assert(m);
-    assert(port > 0);
+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) {
-    assert(m);
-    assert(port > 0);
+#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) {
-    assert(m);
-    assert(port > 0);
+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) {
-    assert(m);
-    assert(port > 0);
+#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;
 
-    assert(m);
-    assert(name);
-    assert(port > 0);
+    pa_assert(m);
+    pa_assert(name);
+    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;
 
-    assert(m);
-    assert(name);
-    assert(port > 0);
+    pa_assert(m);
+    pa_assert(name);
+    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) {
-    assert(s);
+    pa_assert(s);
 
     if (s->filename) {
         unlink(s->filename);
@@ -407,23 +437,29 @@ static void socket_server_free(pa_socket_server*s) {
 }
 
 void pa_socket_server_unref(pa_socket_server *s) {
-    assert(s && s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
-    if (!(--(s->ref)))
+    if (PA_REFCNT_DEC(s) <= 0)
         socket_server_free(s);
 }
 
-void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) {
-    assert(s && s->ref >= 1);
+void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t on_connection, void *userdata) {
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     s->on_connection = on_connection;
     s->userdata = userdata;
 }
 
 char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
-    assert(s && c && l > 0);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(c);
+    pa_assert(l > 0);
 
     switch (s->type) {
+#ifdef HAVE_IPV6
         case SOCKET_SERVER_IPV6: {
             struct sockaddr_in6 sa;
             socklen_t sa_len = sizeof(sa);
@@ -438,14 +474,16 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
                 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
                     return NULL;
 
-                snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
+                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;
 
-                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];
 
@@ -454,11 +492,12 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
                     return NULL;
                 }
 
-                snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
+                pa_snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
             }
 
             return c;
         }
+#endif
 
         case SOCKET_SERVER_IPV4: {
             struct sockaddr_in sa;
@@ -474,13 +513,15 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
                 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
                     return NULL;
 
-                snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
+                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;
 
-                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];
 
@@ -489,23 +530,23 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
                     return NULL;
                 }
 
-                snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
-
+                pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
             }
 
             return c;
         }
 
         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;
 
-            snprintf(c, l, "{%s}unix:%s", hn, s->filename);
+            pa_snprintf(c, l, "{%s}unix:%s", id, s->filename);
+            pa_xfree(id);
             return c;
         }