add username to runtime directory name in /tmp/
authorLennart Poettering <lennart@poettering.net>
Thu, 11 Nov 2004 21:18:33 +0000 (21:18 +0000)
committerLennart Poettering <lennart@poettering.net>
Thu, 11 Nov 2004 21:18:33 +0000 (21:18 +0000)
rework autospawning code and x11 credential publishing
add support for IPv6
reenable LOWDELAY for tcp sockets

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@280 fefdeb5f-60dc-0310-8127-8f9354f1896f

22 files changed:
doc/todo
polyp/Makefile.am
polyp/client-conf-x11.c
polyp/module-protocol-stub.c
polyp/module-x11-publish.c
polyp/native-common.h
polyp/polyplib-context.c
polyp/polyplib-internal.h
polyp/props.c
polyp/props.h
polyp/protocol-native.c
polyp/socket-client.c
polyp/socket-client.h
polyp/socket-server.c
polyp/socket-server.h
polyp/socket-util.c
polyp/socket-util.h
polyp/strlist-test.c [new file with mode: 0644]
polyp/strlist.c [new file with mode: 0644]
polyp/strlist.h [new file with mode: 0644]
polyp/util.c
polyp/util.h

index 2ba697b8442726147e6360a2c7d650183daa0324..99e06569afc7b45f8af3b972af30e74c0f9c97f9 100644 (file)
--- a/doc/todo
+++ b/doc/todo
@@ -2,7 +2,6 @@
 
 *** 0.7 ****
 - per-channel volume
-- unix socket directories include user name
 - add sample directory
 - make mcalign merge chunks
 - option to use default fragment size on alsa drivers
@@ -13,7 +12,6 @@
 - make most buffer sizes dependant on the sample type
 
 - X11: support for the X11 synchronization extension
-- X11: save auth info in root window
 - pass meta info for hearing impaired
 - limit all resources
 - check getaddrinfo results
index cc9705c255410a6fe0dfc33e0da8b95bef02c9ae..c4f9e2d26b7bda253d3539859641ee28546f94ca 100644 (file)
@@ -39,7 +39,8 @@ noinst_PROGRAMS = \
                parec-simple \
                cpulimit-test \
                cpulimit-test2 \
-               voltest
+               voltest \
+               strlist-test
 
 polypconf_DATA=default.pa daemon.conf client.conf
 
@@ -85,21 +86,26 @@ modlib_LTLIBRARIES= \
                libpdispatch.la \
                libauthkey.la \
                libauthkey-prop.la \
+               libstrlist.la \
                libprotocol-simple.la \
                libprotocol-esound.la \
                libprotocol-native.la \
                module-cli.la \
                module-cli-protocol-tcp.la \
+               module-cli-protocol-tcp6.la \
                module-cli-protocol-unix.la \
                module-pipe-sink.la \
                module-pipe-source.la \
                module-oss.la \
                module-oss-mmap.la \
                module-simple-protocol-tcp.la \
+               module-simple-protocol-tcp6.la \
                module-simple-protocol-unix.la \
                module-esound-protocol-tcp.la \
+               module-esound-protocol-tcp6.la \
                module-esound-protocol-unix.la \
                module-native-protocol-tcp.la \
+               module-native-protocol-tcp6.la \
                module-native-protocol-unix.la \
                module-native-protocol-fd.la \
                module-sine.la \
@@ -114,16 +120,20 @@ modlib_LTLIBRARIES= \
 SYMDEF_FILES= \
                module-cli-symdef.h \
                module-cli-protocol-tcp-symdef.h \
+               module-cli-protocol-tcp6-symdef.h \
                module-cli-protocol-unix-symdef.h \
                module-pipe-sink-symdef.h \
                module-pipe-source-symdef.h \
                module-oss-symdef.h \
                module-oss-mmap-symdef.h \
                module-simple-protocol-tcp-symdef.h \
+               module-simple-protocol-tcp6-symdef.h \
                module-simple-protocol-unix-symdef.h \
                module-esound-protocol-tcp-symdef.h \
+               module-esound-protocol-tcp6-symdef.h \
                module-esound-protocol-unix-symdef.h \
                module-native-protocol-tcp-symdef.h \
+               module-native-protocol-tcp6-symdef.h \
                module-native-protocol-unix-symdef.h \
                module-native-protocol-fd-symdef.h \
                module-sine-symdef.h \
@@ -244,13 +254,17 @@ libcli_la_SOURCES = cli.c cli.h
 libcli_la_LDFLAGS = -avoid-version
 libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la
 
+libstrlist_la_SOURCES = strlist.c strlist.h
+libstrlist_la_LDFLAGS = -avoid-version
+libstrlist_la_LIBADD = $(AM_LIBADD)
+
 libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h
 libprotocol_cli_la_LDFLAGS = -avoid-version
 libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la
 
 libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h
 libprotocol_native_la_LDFLAGS = -avoid-version
-libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la
+libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la
 
 libtagstruct_la_SOURCES = tagstruct.c tagstruct.h
 libtagstruct_la_LDFLAGS = -avoid-version
@@ -273,6 +287,11 @@ module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $
 module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version
 module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la
 
+module_simple_protocol_tcp6_la_SOURCES = module-protocol-stub.c
+module_simple_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS)
+module_simple_protocol_tcp6_la_LDFLAGS = -module -avoid-version
+module_simple_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la
+
 module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c
 module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS)
 module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version
@@ -283,6 +302,11 @@ module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CF
 module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version
 module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la
 
+module_cli_protocol_tcp6_la_SOURCES = module-protocol-stub.c
+module_cli_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS)
+module_cli_protocol_tcp6_la_LDFLAGS = -module -avoid-version
+module_cli_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la
+
 module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c
 module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS)
 module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version
@@ -293,6 +317,11 @@ module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $
 module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version
 module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la
 
+module_native_protocol_tcp6_la_SOURCES = module-protocol-stub.c
+module_native_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS)
+module_native_protocol_tcp6_la_LDFLAGS = -module -avoid-version
+module_native_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la
+
 module_native_protocol_unix_la_SOURCES = module-protocol-stub.c
 module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS)
 module_native_protocol_unix_la_LDFLAGS = -module -avoid-version
@@ -308,6 +337,11 @@ module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $
 module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version
 module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la
 
+module_esound_protocol_tcp6_la_SOURCES = module-protocol-stub.c
+module_esound_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS)
+module_esound_protocol_tcp6_la_LDFLAGS = -module -avoid-version
+module_esound_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la
+
 module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c
 module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS)
 module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version
@@ -399,7 +433,9 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \
                log.c log.h \
                gcc-printf.h \
                client-conf.c client-conf.h \
-               conf-parser.c conf-parser.h
+               conf-parser.c conf-parser.h \
+               strlist.c strlist.h \
+               strbuf.c strbuf.h
 
 libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
 libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
@@ -449,11 +485,15 @@ voltest_SOURCES = voltest.c sample.c
 voltest_CFLAGS = $(AM_CFLAGS)
 voltest_LDADD = $(AM_LDADD)
 
-cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c
+strlist_test_SOURCES = strlist-test.c strlist.c strlist.h strbuf.c strbuf.h util.c util.h xmalloc.c xmalloc.h log.c log.h
+strlist_test_CFLAGS = $(AM_CFLAGS)
+strlist_test_LDADD = $(AM_LDADD)
+
+cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h
 cpulimit_test_CFLAGS = $(AM_CFLAGS)
 cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la
 
-cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c
+cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h
 cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2
 cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la
 
@@ -487,7 +527,7 @@ module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA
 module_x11_publish_la_SOURCES = module-x11-publish.c
 module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
 module_x11_publish_la_LDFLAGS = -module -avoid-version
-module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la
+module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la
 
 bin_PROGRAMS+= \
                pax11publish
index 54c3b06a838d86256dce40438a0a6c84eae14ea2..f667bd784b2176eb742cf11d3a8e19b664c3a04f 100644 (file)
@@ -39,7 +39,10 @@ int pa_client_conf_from_x11(struct pa_client_conf *c, const char *dname) {
     Display *d = NULL;
     int ret = -1;
     char t[1024];
-            
+
+    if (!dname && !getenv("DISPLAY"))
+        goto finish;
+    
     if (!(d = XOpenDisplay(dname))) {
         pa_log(__FILE__": XOpenDisplay() failed\n");
         goto finish;
index 6ff7d774396409f0e5db1e8941667a5f71b2c0ab..6a0f88a28b8e8d5274670d4d13bb11142f7ab714 100644 (file)
 #include "modargs.h"
 #include "log.h"
 #include "native-common.h"
+#include "util.h"
 
 #ifdef USE_TCP_SOCKETS
 #define SOCKET_DESCRIPTION "(TCP sockets)"
 #define SOCKET_USAGE "port=<TCP port number> loopback=<listen on loopback device only?>"
+#elif defined(USE_TCP6_SOCKETS)
+#define SOCKET_DESCRIPTION "(TCP/IPv6 sockets)"
+#define SOCKET_USAGE "port=<TCP port number> loopback=<listen on loopback device only?>"
 #else
 #define SOCKET_DESCRIPTION "(UNIX sockets)"
 #define SOCKET_USAGE "socket=<path to UNIX socket>"
   #define protocol_free pa_protocol_simple_free
   #define TCPWRAP_SERVICE "polypaudio-simple"
   #define IPV4_PORT 4711
-  #define UNIX_SOCKET "/tmp/polypaudio/simple"
+  #define UNIX_SOCKET "simple"
   #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record",
-  #ifdef USE_TCP_SOCKETS
+  #if defined(USE_TCP_SOCKETS)
     #include "module-simple-protocol-tcp-symdef.h"
+  #elif defined(USE_TCP6_SOCKETS)
+    #include "module-simple-protocol-tcp6-symdef.h"
   #else
     #include "module-simple-protocol-unix-symdef.h"
   #endif
   #define protocol_free pa_protocol_cli_free
   #define TCPWRAP_SERVICE "polypaudio-cli"
   #define IPV4_PORT 4712
-  #define UNIX_SOCKET "/tmp/polypaudio/cli"
+  #define UNIX_SOCKET "cli"
   #define MODULE_ARGUMENTS 
   #ifdef USE_TCP_SOCKETS
     #include "module-cli-protocol-tcp-symdef.h"
+  #elif defined(USE_TCP6_SOCKETS)
+    #include "module-cli-protocol-tcp6-symdef.h"
   #else
     #include "module-cli-protocol-unix-symdef.h"
   #endif
   #define protocol_free pa_protocol_native_free
   #define TCPWRAP_SERVICE "polypaudio-native"
   #define IPV4_PORT PA_NATIVE_DEFAULT_PORT
-  #define UNIX_SOCKET PA_NATIVE_DEFAULT_SERVER_UNIX
+  #define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET
   #define MODULE_ARGUMENTS "public", "cookie",
   #ifdef USE_TCP_SOCKETS
     #include "module-native-protocol-tcp-symdef.h"
+  #elif defined(USE_TCP6_SOCKETS)
+    #include "module-native-protocol-tcp6-symdef.h"
   #else
     #include "module-native-protocol-unix-symdef.h"
   #endif
   #define MODULE_ARGUMENTS "sink", "source", "public", "cookie",
   #ifdef USE_TCP_SOCKETS
     #include "module-esound-protocol-tcp-symdef.h"
+  #elif defined(USE_TCP6_SOCKETS)
+    #include "module-esound-protocol-tcp6-symdef.h"
   #else
     #include "module-esound-protocol-unix-symdef.h"
   #endif
@@ -117,7 +129,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION)
 
 static const char* const valid_modargs[] = {
     MODULE_ARGUMENTS
-#ifdef USE_TCP_SOCKETS
+#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS)
     "port",
     "loopback",
 #else
@@ -128,7 +140,7 @@ static const char* const valid_modargs[] = {
 
 static struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) {
     struct pa_socket_server *s;
-#ifdef USE_TCP_SOCKETS
+#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS)
     int loopback = 1;
     uint32_t port = IPV4_PORT;
 
@@ -141,30 +153,39 @@ static struct pa_socket_server *create_socket_server(struct pa_core *c, struct p
         pa_log(__FILE__": port= expects a numerical argument between 1 and 65535.\n");
         return NULL;
     }
-    
+
+#ifdef USE_TCP6_SOCKETS
+    if (!(s = pa_socket_server_new_ipv6(c->mainloop, loopback ? (uint8_t*) &in6addr_loopback : (uint8_t*) &in6addr_any, port)))
+        return NULL;
+#else
     if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port, TCPWRAP_SERVICE)))
         return NULL;
+#endif
+    
 #else
     int r;
-    const char *p;
+    const char *v;
+    char tmp[PATH_MAX];
+
+    v = pa_modargs_get_value(ma, "socket", UNIX_SOCKET);
+    assert(v);
 
-    p = pa_modargs_get_value(ma, "socket", UNIX_SOCKET);
-    assert(p);
+    pa_runtime_path(v, tmp, sizeof(tmp));
 
-    if (pa_unix_socket_make_secure_dir(p) < 0) {
+    if (pa_make_secure_parent_dir(tmp) < 0) {
         pa_log(__FILE__": Failed to create secure socket directory.\n");
         return NULL;
     }
 
-    if ((r = pa_unix_socket_remove_stale(p)) < 0) {
-        pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s\n", p, strerror(errno));
+    if ((r = pa_unix_socket_remove_stale(tmp)) < 0) {
+        pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s\n", tmp, strerror(errno));
         return NULL;
     }
     
     if (r)
-        pa_log(__FILE__": Removed stale UNIX socket '%s'.", p);
+        pa_log(__FILE__": Removed stale UNIX socket '%s'.", tmp);
     
-    if (!(s = pa_socket_server_new_unix(c->mainloop, p)))
+    if (!(s = pa_socket_server_new_unix(c->mainloop, tmp)))
         return NULL;
     
 #endif
index 6e100153f4c0b1347cab26c28ff576d1a9d6a826..60284bd64a1c015b2ba8805273655aa2249d35dc 100644 (file)
@@ -46,6 +46,8 @@
 #include "authkey-prop.h"
 #include "authkey.h"
 #include "x11prop.h"
+#include "strlist.h"
+#include "props.h"
 
 PA_MODULE_AUTHOR("Lennart Poettering")
 PA_MODULE_DESCRIPTION("X11 Credential Publisher")
@@ -101,6 +103,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
     char hn[256], un[128];
     char hx[PA_NATIVE_COOKIE_LENGTH*2+1];
     const char *t;
+    char *s;
+    struct pa_strlist *l;
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log(__FILE__": failed to parse module arguments\n");
@@ -120,15 +124,17 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
 
     u->display = pa_x11_wrapper_get_display(u->x11_wrapper);
 
-    if (!pa_get_fqdn(hn, sizeof(hn)))
+    if (!(l = pa_property_get(c, PA_NATIVE_SERVER_PROPERTY_NAME)))
         goto fail;
+
+    s = pa_strlist_tostring(l);
+    pa_x11_set_prop(u->display, "POLYP_SERVER", s);
+    pa_xfree(s);
     
-    if (!pa_get_user_name(un, sizeof(un)))
+    if (!pa_get_fqdn(hn, sizeof(hn)) || !pa_get_user_name(un, sizeof(un)))
         goto fail;
     
     u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid());
-
-    pa_x11_set_prop(u->display, "POLYP_SERVER", hn);
     pa_x11_set_prop(u->display, "POLYP_ID", u->id);
 
     if ((t = pa_modargs_get_value(ma, "source", NULL)))
index 597bb56b0687d07bc005926839ab8b118507263b..28a471d002d68b28a9f4e8989d0d9af97242ec93 100644 (file)
@@ -99,8 +99,9 @@ enum {
 #define PA_NATIVE_DEFAULT_PORT 4713
 
 #define PA_NATIVE_COOKIE_PROPERTY_NAME "protocol-native-cookie"
+#define PA_NATIVE_SERVER_PROPERTY_NAME "protocol-native-server"
 
-#define PA_NATIVE_DEFAULT_SERVER_UNIX "/tmp/polypaudio/native"
+#define PA_NATIVE_DEFAULT_UNIX_SOCKET "native"
 
 
 PA_C_DECL_END
index 36512a8a309fbfbf795684cc5ac41bc5156b2902..a477031302153f99847b08587839c17d4bf93b44 100644 (file)
@@ -54,7 +54,9 @@
 #include "client-conf-x11.h"
 #endif
 
-#define AUTOSPAWN_LOCK "/tmp/polypaudio/autospawn.lock"
+#define AUTOSPAWN_LOCK "autospawn.lock"
+
+
 
 static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_REQUEST] = { pa_command_request },
@@ -63,6 +65,16 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_SUBSCRIBE_EVENT] = { pa_command_subscribe_event },
 };
 
+static void unlock_autospawn_lock_file(struct pa_context *c) {
+    assert(c);
+    
+    if (c->autospawn_lock_fd >= 0) {
+        pa_unlock_lockfile(c->autospawn_lock_fd);
+        c->autospawn_lock_fd = -1;
+    }
+    
+}
+
 struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
     struct pa_context *c;
     assert(mainloop && name);
@@ -93,6 +105,10 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *
 
     c->memblock_stat = pa_memblock_stat_new();
     c->local = -1;
+    c->server_list = NULL;
+    c->autospawn_lock_fd = -1;
+    memset(&c->spawn_api, 0, sizeof(c->spawn_api));
+    c->do_autospawn = 0;
     
     pa_check_signal_is_blocked(SIGPIPE);
 
@@ -109,6 +125,8 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *
 static void context_free(struct pa_context *c) {
     assert(c);
 
+    unlock_autospawn_lock_file(c);
+
     while (c->operations)
         pa_operation_cancel(c->operations);
 
@@ -133,6 +151,8 @@ static void context_free(struct pa_context *c) {
 
     if (c->conf)
         pa_client_conf_free(c->conf);
+
+    pa_strlist_free(c->server_list);
     
     pa_xfree(c->name);
     pa_xfree(c);
@@ -337,38 +357,9 @@ finish:
     pa_context_unref(c);
 }
 
-static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(client && c && c->state == PA_CONTEXT_CONNECTING);
-
-    pa_context_ref(c);
-    
-    pa_socket_client_unref(client);
-    c->client = NULL;
-
-    if (!io) {
-        pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
-        goto finish;
-    }
-
-    setup_context(c, io);
+static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata);
 
-finish:
-    pa_context_unref(c);
-}
-
-static int default_server_is_running(void) {
-    struct stat st;
-    
-    if (PA_NATIVE_DEFAULT_SERVER_UNIX[0] != '/')
-        return 1;
-
-    if (stat(PA_NATIVE_DEFAULT_SERVER_UNIX, &st) < 0)
-        return 0;
-
-    return 1;
-}
-static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api *api) {
+static int context_connect_spawn(struct pa_context *c) {
     pid_t pid;
     int status, r;
     int fds[2] = { -1, -1} ;
@@ -382,15 +373,20 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api
         goto fail;
     }
 
-    if (api && api->prefork)
-        api->prefork();
+    pa_fd_set_cloexec(fds[0], 1);
+    
+    pa_socket_low_delay(fds[0]);
+    pa_socket_low_delay(fds[1]);
+
+    if (c->spawn_api.prefork)
+        c->spawn_api.prefork();
 
     if ((pid = fork()) < 0) {
         pa_log(__FILE__": fork() failed: %s\n", strerror(errno));
         pa_context_fail(c, PA_ERROR_INTERNAL);
 
-        if (api && api->postfork)
-            api->postfork();
+        if (c->spawn_api.postfork)
+            c->spawn_api.postfork();
         
         goto fail;
     } else if (!pid) {
@@ -402,10 +398,11 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api
         char *argv[MAX_ARGS+1];
         int n;
 
+        /* Not required, since fds[0] has CLOEXEC enabled anyway */
         close(fds[0]);
         
-        if (api && api->atfork)
-            api->atfork();
+        if (c->spawn_api.atfork)
+            c->spawn_api.atfork();
 
         /* Setup argv */
 
@@ -430,14 +427,15 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api
 
         execv(argv[0], argv);
         _exit(1);
+#undef MAX_ARGS
     } 
 
     /* Parent */
 
     r = waitpid(pid, &status, 0);
 
-    if (api && api->postfork)
-        api->postfork();
+    if (c->spawn_api.postfork)
+        c->spawn_api.postfork();
         
     if (r < 0) {
         pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno));
@@ -453,7 +451,9 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api
     c->local = 1;
     
     io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);
+
     setup_context(c, io);
+    unlock_autospawn_lock_file(c);
 
     pa_context_unref(c);
 
@@ -465,71 +465,131 @@ fail:
     if (fds[1] != -1)
         close(fds[1]);
 
+    unlock_autospawn_lock_file(c);
+
     pa_context_unref(c);
 
     return -1;
 }
 
-int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) {
+static int try_next_connection(struct pa_context *c) {
+    char *u = NULL;
     int r = -1;
-    assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED);
-
-    if (!server)
-        server = c->conf->default_server;
+    assert(c && !c->client);
 
-    if (!server && spawn && c->conf->autospawn) {
-        int lock_fd = pa_lock_lockfile(AUTOSPAWN_LOCK);
+    for (;;) {
+        if (u)
+            pa_xfree(u);
+        u = NULL;
+        
+        c->server_list = pa_strlist_pop(c->server_list, &u);
         
-        if (!default_server_is_running()) {
-            int r = context_connect_spawn(c, api);
+        if (!u) {
 
-            if (lock_fd >= 0)
-                pa_unlock_lockfile(lock_fd);
-            return r;
+            if (c->do_autospawn) {
+                r = context_connect_spawn(c);
+                goto finish;
+            }
+            
+            pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
+            goto finish;
         }
-
-        if (lock_fd >= 0)
-            pa_unlock_lockfile(lock_fd);
+        
+/*          pa_log(__FILE__": Trying to connect to %s...\n", u);  */
+        
+        if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT)))
+            continue;
+        
+        c->local = pa_socket_client_is_local(c->client);
+        pa_socket_client_set_callback(c->client, on_connection, c);
+        break;
     }
+
+    r = 0;
+
+finish:
+    if (u)
+        pa_xfree(u);
     
-    if (!server)
-        server = PA_NATIVE_DEFAULT_SERVER_UNIX;
+    return r;
+}
 
-    pa_context_ref(c);
+static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
+    struct pa_context *c = userdata;
+    assert(client && c && c->state == PA_CONTEXT_CONNECTING);
 
-    assert(!c->client);
+    pa_context_ref(c);
     
-    if (*server == '/') {
-        if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
-            pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
+    pa_socket_client_unref(client);
+    c->client = NULL;
+
+    if (!io) {
+        pa_log("failure: %s\n", strerror(errno));
+        
+        /* Try the item in the list */
+        if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) {
+            try_next_connection(c);
             goto finish;
         }
 
-        c->local = 1;
-    } else {
-        struct sockaddr* sa;
-        size_t sa_len;
+        pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
+        goto finish;
+    }
+
+    unlock_autospawn_lock_file(c);
+    setup_context(c, io);
 
-        if (!(sa = pa_resolve_server(server, &sa_len, PA_NATIVE_DEFAULT_PORT))) {
+finish:
+    pa_context_unref(c);
+}
+
+int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) {
+    int r = -1;
+    assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED);
+
+    if (!server)
+        server = c->conf->default_server;
+
+
+    pa_context_ref(c);
+
+    assert(!c->server_list);
+    
+    if (server) {
+        if (!(c->server_list = pa_strlist_parse(server))) {
             pa_context_fail(c, PA_ERROR_INVALIDSERVER);
             goto finish;
         }
+    } else {
+        char *d;
+        char ufn[PATH_MAX];
+
+        /* Prepend in reverse order */
+        
+        if ((d = getenv("DISPLAY")))
+            c->server_list = pa_strlist_prepend(c->server_list, d);
+        
+        c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost");
+        c->server_list = pa_strlist_prepend(c->server_list, "localhost");
+        c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn)));
 
-        c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
-        pa_xfree(sa);
+        /* Wrap the connection attempts in a single transaction for sane autospwan locking */
+        if (spawn && c->conf->autospawn) {
+            char lf[PATH_MAX];
 
-        if (!c->client) {
-            pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
-            goto finish;
+            pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf));
+            assert(c->autospawn_lock_fd <= 0);
+            c->autospawn_lock_fd = pa_lock_lockfile(lf);
+
+            if (api)
+                c->spawn_api = *api;
+            c->do_autospawn = 1;
         }
 
-        c->local = 0;
     }
 
-    pa_socket_client_set_callback(c->client, on_connection, c);
     pa_context_set_state(c, PA_CONTEXT_CONNECTING);
-
-    r = 0;
+    r = try_next_connection(c);
     
 finish:
     pa_context_unref(c);
index 4e6553a8f9af35304b2f84bbecba3b4f4f049a7e..589388f84e72dad0c0ebb3454fc5896b10f43c5f 100644 (file)
@@ -34,6 +34,7 @@
 #include "llist.h"
 #include "native-common.h"
 #include "client-conf.h"
+#include "strlist.h"
 
 #define DEFAULT_TLENGTH (44100*2*2/2)  //(10240*8)
 #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2)
@@ -70,6 +71,11 @@ struct pa_context {
     struct pa_memblock_stat *memblock_stat;
 
     int local;
+    int do_autospawn;
+    int autospawn_lock_fd;
+    struct pa_spawn_api spawn_api;
+    
+    struct pa_strlist *server_list;
 
     struct pa_client_conf *conf;
 };
index 014059ec0581d4aca34f169976ded790b25b5640..596133bc4d2fafb880134d70c7fa95f1646b89b3 100644 (file)
@@ -110,3 +110,10 @@ void pa_property_dump(struct pa_core *c, struct pa_strbuf *s) {
     while ((p = pa_hashmap_iterate(c->properties, &state, NULL)))
         pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data);
 }
+
+int pa_property_replace(struct pa_core *c, const char *name, void *data) {
+    assert(c && name);
+
+    pa_property_remove(c, name);
+    return pa_property_set(c, name, data);
+}
index f19e9260f8184152e56f4195824f1ccb1b294695..954d2540489ca10015bae28a395e3944c7bb4c57 100644 (file)
@@ -43,6 +43,9 @@ int pa_property_set(struct pa_core *c, const char *name, void *data);
 /* Remove the specified property. Return non-zero on failure */
 int pa_property_remove(struct pa_core *c, const char *name);
 
+/* A combination of pa_property_remove() and pa_property_set() */
+int pa_property_replace(struct pa_core *c, const char *name, void *data);
+
 /* Free all memory used by the property system */
 void pa_property_cleanup(struct pa_core *c);
 
index fade2a2ff89ba0486b242470dbf68a8acc4f6efb..0102e0caf33f118fa475359254ce2817f1e19cd0 100644 (file)
@@ -47,6 +47,8 @@
 #include "log.h"
 #include "autoload.h"
 #include "authkey-prop.h"
+#include "strlist.h"
+#include "props.h"
 
 struct connection;
 struct pa_protocol_native;
@@ -2064,6 +2066,7 @@ static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struc
 }
 
 struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) {
+    char t[256];
     struct pa_protocol_native *p;
 
     if (!(p = protocol_new_internal(core, m, ma)))
@@ -2071,6 +2074,13 @@ struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct p
     
     p->server = server;
     pa_socket_server_set_callback(p->server, on_connection, p);
+
+    if (pa_socket_server_get_address(p->server, t, sizeof(t))) {
+        struct pa_strlist *l;
+        l = pa_property_get(core, PA_NATIVE_SERVER_PROPERTY_NAME);
+        l = pa_strlist_prepend(l, t);
+        pa_property_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l);
+    }
     
     return p;
 }
@@ -2083,12 +2093,26 @@ void pa_protocol_native_free(struct pa_protocol_native *p) {
         connection_free(c);
     pa_idxset_free(p->connections, NULL, NULL);
 
-    if (p->server)
+    if (p->server) {
+        char t[256];
+        
+        if (pa_socket_server_get_address(p->server, t, sizeof(t))) {
+            struct pa_strlist *l;
+            l = pa_property_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME);
+            l = pa_strlist_remove(l, t);
+
+            if (l)
+                pa_property_replace(p->core, PA_NATIVE_SERVER_PROPERTY_NAME, l);
+            else
+                pa_property_remove(p->core, PA_NATIVE_SERVER_PROPERTY_NAME);
+        }
+        
         pa_socket_server_unref(p->server);
+    }
 
     if (p->auth_cookie_in_property)
         pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
-        
+
     pa_xfree(p);
 }
 
index fbc259ff55961351aa77d49bc32e11b6cd6d9be1..9b80d8098553e4a10e87dc79037773b3451aa067 100644 (file)
@@ -32,6 +32,7 @@
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <netdb.h>
 
 #include "socket-client.h"
 #include "socket-util.h"
@@ -47,6 +48,7 @@ struct pa_socket_client {
     struct pa_defer_event *defer_event;
     void (*callback)(struct pa_socket_client*c, struct pa_iochannel *io, void *userdata);
     void *userdata;
+    int local;
 };
 
 static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) {
@@ -61,6 +63,7 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) {
     c->defer_event = NULL;
     c->callback = NULL;
     c->userdata = NULL;
+    c->local = 0;
     return c;
 }
 
@@ -85,6 +88,7 @@ static void do_call(struct pa_socket_client *c) {
 
     if (error != 0) {
 /*         pa_log(__FILE__": connect(): %s\n", strerror(error)); */
+        errno = error;
         goto finish;
     }
         
@@ -141,63 +145,27 @@ static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, soc
 }
 
 struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) {
-    struct pa_socket_client *c;
     struct sockaddr_in sa;
-    assert(m && address && port);
-
-    c = pa_socket_client_new(m);
-    assert(c);
-
-    if ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-        pa_log(__FILE__": socket(): %s\n", strerror(errno));
-        goto fail;
-    }
-
-    pa_fd_set_cloexec(c->fd, 1);
-    pa_socket_tcp_low_delay(c->fd);
+    assert(m && port > 0);
 
+    memset(&sa, 0, sizeof(sa));
     sa.sin_family = AF_INET;
     sa.sin_port = htons(port);
     sa.sin_addr.s_addr = htonl(address);
 
-    if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0)
-        goto fail;
-    
-    return c;
-
-fail:
-    pa_socket_client_unref(c);
-    return NULL;
+    return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
 }
 
 struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) {
-    struct pa_socket_client *c;
     struct sockaddr_un sa;
     assert(m && filename);
     
-    c = pa_socket_client_new(m);
-    assert(c);
-
-    if ((c->fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
-        pa_log(__FILE__": socket(): %s\n", strerror(errno));
-        goto fail;
-    }
-
-    pa_fd_set_cloexec(c->fd, 1);
-    pa_socket_low_delay(c->fd);
-
+    memset(&sa, 0, sizeof(sa));
     sa.sun_family = AF_LOCAL;
     strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
     sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
-    
-    if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0)
-        goto fail;
-    
-    return c;
 
-fail:
-    pa_socket_client_unref(c);
-    return NULL;
+    return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
 }
 
 struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) {
@@ -206,13 +174,30 @@ struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m
     c = pa_socket_client_new(m);
     assert(c);
 
+    switch (sa->sa_family) {
+        case AF_UNIX:
+            c->local = 1;
+            break;
+            
+        case AF_INET:
+            c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
+            break;
+            
+        case AF_INET6:
+            c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
+            break;
+            
+        default:
+            c->local = 0;
+    }
+    
     if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) {
         pa_log(__FILE__": socket(): %s\n", strerror(errno));
         goto fail;
     }
 
     pa_fd_set_cloexec(c->fd, 1);
-    if (sa->sa_family == AF_INET)
+    if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)
         pa_socket_tcp_low_delay(c->fd);
     else
         pa_socket_low_delay(c->fd);
@@ -257,3 +242,125 @@ void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connect
     c->callback = on_connection;
     c->userdata = userdata;
 }
+
+struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port) {
+    struct sockaddr_in6 sa;
+    
+    memset(&sa, 0, sizeof(sa));
+    sa.sin6_family = AF_INET6;
+    sa.sin6_port = htons(port);
+    memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr));
+
+    return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
+}
+
+/* Parse addresses in one of the following forms:
+ *    HOSTNAME
+ *    HOSTNAME:PORT
+ *    [HOSTNAME]
+ *    [HOSTNAME]:PORT
+ *
+ *  Return a newly allocated string of the hostname and fill in *port if specified  */
+
+static char *parse_address(const char *s, uint16_t *port) {
+    assert(s && port);
+    if (*s == '[') {
+        char *e;
+        if (!(e = strchr(s+1, ']')))
+            return NULL;
+
+        if (e[1] == ':')
+            *port = atoi(e+2);
+        else if (e[1] != 0)
+            return NULL;
+        
+        return pa_xstrndup(s+1, e-s-1);
+    } else {
+        char *e;
+        
+        if (!(e = strrchr(s, ':')))
+            return pa_xstrdup(s);
+
+        *port = atoi(e+1);
+        return pa_xstrndup(s, e-s);
+    }
+}
+
+struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char*name, uint16_t default_port) {
+    const char *p;
+    struct pa_socket_client *c = NULL;
+    enum { KIND_UNIX, KIND_TCP_AUTO, KIND_TCP4, KIND_TCP6 } kind = KIND_TCP_AUTO;
+    assert(m && name);
+
+    if (*name == '{') {
+        char hn[256], *pfx;
+        /* The URL starts with a host specification for detecting local connections */
+        
+        if (!pa_get_host_name(hn, sizeof(hn)))
+            return NULL;
+                
+        pfx = pa_sprintf_malloc("{%s}", hn);
+        if (!pa_startswith(name, pfx))
+            /* Not local */
+            return NULL;
+        
+        p = name + strlen(pfx);
+    } else
+        p = name;
+    
+    if (*p == '/')
+        kind = KIND_UNIX;
+    else if (pa_startswith(p, "unix:")) {
+        kind = KIND_UNIX;
+        p += sizeof("unix:")-1;
+    } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) {
+        kind = KIND_TCP4;
+        p += sizeof("tcp:")-1;
+    } else if (pa_startswith(p, "tcp6:")) {
+        kind = KIND_TCP6;
+        p += sizeof("tcp6:")-1;
+    }
+
+    switch (kind) {
+        case KIND_UNIX:
+            return pa_socket_client_new_unix(m, p);
+
+        case KIND_TCP_AUTO:  /* Fallthrough */
+        case KIND_TCP4: 
+        case KIND_TCP6: {
+            uint16_t port = default_port;
+            char *h;
+            struct addrinfo hints, *res;
+
+            if (!(h = parse_address(p, &port)))
+                return NULL;
+
+            memset(&hints, 0, sizeof(hints));
+            hints.ai_family = kind == KIND_TCP4 ? AF_INET : (kind == KIND_TCP6 ? AF_INET6 : AF_UNSPEC);
+            
+            if (getaddrinfo(h, NULL, &hints, &res) < 0 || !res)
+                return NULL;
+
+            if (res->ai_addr->sa_family == AF_INET)
+                ((struct sockaddr_in*) res->ai_addr)->sin_port = htons(port);
+            else if (res->ai_addr->sa_family == AF_INET6)
+                ((struct sockaddr_in6*) res->ai_addr)->sin6_port = htons(port);
+            else
+                return NULL;
+            
+            c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen);
+            freeaddrinfo(res);
+            return c;
+        }
+    }
+
+    /* Should never be reached */
+    assert(0);
+    return NULL;
+    
+}
+
+int pa_socket_client_is_local(struct pa_socket_client *c) {
+    assert(c);
+    return c->local;
+}
index 1957355c60f46accc8ee5cfeaebe86b2dde28b53..262fbac3ccc9c4a86d6f9d20504a5443ec8e4179 100644 (file)
 #include "mainloop-api.h"
 #include "iochannel.h"
 
-/* It is safe to destroy the calling socket_client object from the callback */
-
 struct pa_socket_client;
 
 struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port);
+struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port);
 struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename);
 struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen);
+struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char *a, uint16_t default_port);
 
 void pa_socket_client_unref(struct pa_socket_client *c);
 struct pa_socket_client* pa_socket_client_ref(struct pa_socket_client *c);
 
 void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata);
 
+int pa_socket_client_is_local(struct pa_socket_client *c);
+
 #endif
index c170bf6ee6c629bf2e5823ecfdce84daaf441997..a37b3e34eff98fbb7020290d38d019bae5d4d376 100644 (file)
@@ -56,7 +56,7 @@ struct pa_socket_server {
 
     struct pa_io_event *io_event;
     struct pa_mainloop_api *mainloop;
-    enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX } type;
+    enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type;
 };
 
 static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) {
@@ -202,6 +202,7 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui
 
     pa_socket_tcp_low_delay(fd);
     
+    memset(&sa, sizeof(sa), 0);
     sa.sin_family = AF_INET;
     sa.sin_port = htons(port);
     sa.sin_addr.s_addr = htonl(address);
@@ -230,6 +231,53 @@ fail:
     return NULL;
 }
 
+struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port) {
+    struct pa_socket_server *ss;
+    int fd = -1;
+    struct sockaddr_in6 sa;
+    int on = 1;
+
+    assert(m && port);
+
+    if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
+        pa_log(__FILE__": socket(): %s\n", strerror(errno));
+        goto fail;
+    }
+
+    pa_fd_set_cloexec(fd, 1);
+
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+        pa_log(__FILE__": setsockopt(): %s\n", strerror(errno));
+
+    pa_socket_tcp_low_delay(fd);
+
+    memset(&sa, sizeof(sa), 0);
+    sa.sin6_family = AF_INET6;
+    sa.sin6_port = htons(port);
+    memcpy(sa.sin6_addr.s6_addr, address, 16);
+
+    if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+        pa_log(__FILE__": bind(): %s\n", strerror(errno));
+        goto fail;
+    }
+
+    if (listen(fd, 5) < 0) {
+        pa_log(__FILE__": listen(): %s\n", strerror(errno));
+        goto fail;
+    }
+
+    if ((ss = pa_socket_server_new(m, fd)))
+        ss->type = SOCKET_SERVER_IPV6;
+
+    return ss;
+    
+fail:
+    if (fd >= 0)
+        close(fd);
+
+    return NULL;
+}
+
 static void socket_server_free(struct pa_socket_server*s) {
     assert(s);
     close(s->fd);
@@ -258,3 +306,98 @@ void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connecti
     s->on_connection = on_connection;
     s->userdata = userdata;
 }
+
+
+char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l) {
+    assert(s && c && l > 0);
+    
+    switch (s->type) {
+        case SOCKET_SERVER_IPV6: {
+            struct sockaddr_in6 sa;
+            socklen_t l = sizeof(sa);
+
+            if (getsockname(s->fd, (struct sockaddr*) &sa, &l) < 0) {
+                pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno));
+                return NULL;
+            }
+
+            if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) {
+                char fqdn[256];
+                if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
+                    return NULL;
+                
+                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)))
+                    return NULL;
+                
+                snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port));
+            } else {
+                char ip[INET6_ADDRSTRLEN];
+                
+                if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
+                    pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno));
+                    return NULL;
+                }
+                
+                snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
+            }
+
+            return c;
+        }
+
+        case SOCKET_SERVER_IPV4: {
+            struct sockaddr_in sa;
+            socklen_t l = sizeof(sa);
+
+            if (getsockname(s->fd, &sa, &l) < 0) {
+                pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno));
+                return NULL;
+            }
+
+            if (sa.sin_addr.s_addr == INADDR_ANY) {
+                char fqdn[256];
+                if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
+                    return NULL;
+                
+                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)))
+                    return NULL;
+                
+                snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port));
+            } else {
+                char ip[INET_ADDRSTRLEN];
+
+                if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
+                    pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno));
+                    return NULL;
+                }
+                
+                snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
+
+            }
+            
+            return c;
+        }
+
+        case SOCKET_SERVER_UNIX: {
+            char hn[256];
+
+            if (!s->filename)
+                return NULL;
+            
+            if (!pa_get_host_name(hn, sizeof(hn)))
+                return NULL;
+
+            snprintf(c, l, "{%s}unix:%s", hn, s->filename);
+            return c;
+        }
+
+        default:
+            return NULL;
+    }
+}
index f5877e55723897261633ed88b6fa64e66fa936a0..cc5524d1ed94129c5b9fa0024b51047ab6f5c5e4 100644 (file)
@@ -33,10 +33,13 @@ struct pa_socket_server;
 struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd);
 struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename);
 struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service);
+struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port);
 
 void pa_socket_server_unref(struct pa_socket_server*s);
 struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s);
 
 void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata);
 
+char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l);
+
 #endif
index 96ea2c6076fabcb7bca8c95c578056dfcb7cc575..e0540179a195f2e1eac4fbeff125e1174c38340c 100644 (file)
@@ -114,7 +114,7 @@ int pa_socket_tcp_low_delay(int fd) {
     ret = pa_socket_low_delay(fd);
     
     on = 1;
-/*
+
 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
 #if defined(SOL_TCP)
     if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
@@ -123,7 +123,6 @@ int pa_socket_tcp_low_delay(int fd) {
 #endif
         ret = -1;
 #endif
-*/
 
 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \
        defined(IPPROTO_IP))
@@ -204,42 +203,6 @@ int pa_unix_socket_remove_stale(const char *fn) {
     return 0;
 }
 
-int pa_unix_socket_make_secure_dir(const char *fn) {
-    int ret = -1;
-    char *slash, *dir = pa_xstrdup(fn);
-    
-    if (!(slash = strrchr(dir, '/')))
-        goto finish;
-    *slash = 0;
-    
-    if (pa_make_secure_dir(dir) < 0)
-        goto finish;
-
-    ret = 0;
-    
-finish:
-    pa_xfree(dir);
-    return ret;
-}
-
-int pa_unix_socket_remove_secure_dir(const char *fn) {
-    int ret = -1;
-    char *slash, *dir = pa_xstrdup(fn);
-    
-    if (!(slash = strrchr(dir, '/')))
-        goto finish;
-    *slash = 0;
-
-    if (rmdir(dir) < 0)
-        goto finish;
-    
-    ret = 0;
-    
-finish:
-    pa_xfree(dir);
-    return ret;
-}
-
 struct sockaddr *pa_resolve_server(const char *server, size_t *len, uint16_t nport) {
     struct sockaddr *sa;
     struct addrinfo hints, *result = NULL;
index 46fcfdc97da44cd331a112725092dad7b06b7fe3..aa2de8a52f7295062f09c685eecf77acdb0a989a 100644 (file)
@@ -35,9 +35,6 @@ int pa_socket_set_rcvbuf(int fd, size_t l);
 int pa_unix_socket_is_stale(const char *fn);
 int pa_unix_socket_remove_stale(const char *fn);
 
-int pa_unix_socket_make_secure_dir(const char *fn);
-int pa_unix_socket_remove_secure_dir(const char *fn);
-
 struct sockaddr *pa_resolve_server(const char *server, size_t *len, uint16_t port);
 
 #endif
diff --git a/polyp/strlist-test.c b/polyp/strlist-test.c
new file mode 100644 (file)
index 0000000..01dcdf1
--- /dev/null
@@ -0,0 +1,39 @@
+#include <stdio.h>
+
+#include "strlist.h"
+#include "xmalloc.h"
+
+int main(int argc, char* argv[]) {
+    char *t, *u;
+    struct pa_strlist *l = NULL;
+
+    l = pa_strlist_prepend(l, "e");
+    l = pa_strlist_prepend(l, "d");
+    l = pa_strlist_prepend(l, "c");
+    l = pa_strlist_prepend(l, "b");
+    l = pa_strlist_prepend(l, "a");
+
+    t = pa_strlist_tostring(l);
+    pa_strlist_free(l);
+    
+    fprintf(stderr, "1: %s\n", t);
+
+    l = pa_strlist_parse(t);
+    pa_xfree(t);
+
+    t = pa_strlist_tostring(l);
+    fprintf(stderr, "2: %s\n", t);
+    pa_xfree(t);
+
+    l = pa_strlist_pop(l, &u);
+    fprintf(stderr, "3: %s\n", u);
+    pa_xfree(u);
+    
+    l = pa_strlist_remove(l, "c");
+    
+    t = pa_strlist_tostring(l);
+    fprintf(stderr, "4: %s\n", t);
+    pa_xfree(t);
+
+    pa_strlist_free(l);
+}
diff --git a/polyp/strlist.c b/polyp/strlist.c
new file mode 100644 (file)
index 0000000..df7278d
--- /dev/null
@@ -0,0 +1,137 @@
+/* $Id$ */
+
+/***
+  This file is part of polypaudio.
+  polypaudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+  polypaudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+  You should have received a copy of the GNU General Public License
+  along with polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <assert.h>
+
+#include "strlist.h"
+#include "xmalloc.h"
+#include "strbuf.h"
+#include "util.h"
+
+struct pa_strlist {
+    struct pa_strlist *next;
+    char *str;
+};
+
+struct pa_strlist* pa_strlist_prepend(struct pa_strlist *l, const char *s) {
+    struct pa_strlist *n;
+    assert(s);
+    n = pa_xmalloc(sizeof(struct pa_strlist));
+    n->str = pa_xstrdup(s);
+    n->next = l;
+    return  n;
+}
+
+char *pa_strlist_tostring(struct pa_strlist *l) {
+    int first = 1;
+    struct pa_strbuf *b;
+
+    b = pa_strbuf_new();
+    for (; l; l = l->next) {
+        if (!first)
+            pa_strbuf_puts(b, " ");
+        first = 0;
+        pa_strbuf_puts(b, l->str);
+    }
+
+    return pa_strbuf_tostring_free(b);
+}
+
+struct pa_strlist* pa_strlist_remove(struct pa_strlist *l, const char *s) {
+    struct pa_strlist *ret = l, *prev = NULL;
+    assert(l && s);
+
+    while (l) {
+        if (!strcmp(l->str, s)) {
+            struct pa_strlist *n = l->next;
+            
+            if (!prev) {
+                assert(ret == l);
+                ret = n;
+            } else
+                prev->next = n;
+
+            pa_xfree(l->str);
+            pa_xfree(l);
+
+            l = n;
+            
+        } else {
+            prev = l;
+            l = l->next;
+        }
+    }
+
+    return ret;
+}
+
+void pa_strlist_free(struct pa_strlist *l) {
+    while (l) {
+        struct pa_strlist *c = l;
+        l = l->next;
+
+        pa_xfree(c->str);
+        pa_xfree(c);
+    }
+}
+
+struct pa_strlist* pa_strlist_pop(struct pa_strlist *l, char **s) {
+    struct pa_strlist *r;
+    assert(s);
+    
+    if (!l) {
+        *s = NULL;
+        return NULL;
+    }
+        
+    *s = l->str;
+    r = l->next;
+    pa_xfree(l);
+    return r;
+}
+
+struct pa_strlist* pa_strlist_parse(const char *s) {
+    struct pa_strlist *head = NULL, *p = NULL;
+    const char *state = NULL;
+    char *r;
+
+    while ((r = pa_split_spaces(s, &state))) {
+        struct pa_strlist *n;
+
+        n = pa_xmalloc(sizeof(struct pa_strlist));
+        n->str = r;
+        n->next = NULL;
+
+        if (p)
+            p->next = n;
+        else
+            head = n;
+
+        p = n;
+    }
+
+    return head;
+}
diff --git a/polyp/strlist.h b/polyp/strlist.h
new file mode 100644 (file)
index 0000000..2a209db
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef foostrlisthfoo
+#define foostrlisthfoo
+
+/* $Id$ */
+
+/***
+  This file is part of polypaudio.
+  polypaudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+  polypaudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+  You should have received a copy of the GNU General Public License
+  along with polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+struct pa_strlist;
+
+/* Add the specified server string to the list, return the new linked list head */
+struct pa_strlist* pa_strlist_prepend(struct pa_strlist *l, const char *s);
+
+/* Remove the specified string from the list, return the new linked list head */
+struct pa_strlist* pa_strlist_remove(struct pa_strlist *l, const char *s);
+
+/* Make a whitespace separated string of all server stringes. Returned memory has to be freed with pa_xfree() */
+char *pa_strlist_tostring(struct pa_strlist *l);
+
+/* Free the entire list */
+void pa_strlist_free(struct pa_strlist *l);
+
+/* Return the next entry in the list in *string and remove it from
+ * the list. Returns the new list head. The memory *string points to
+ * has to be freed with pa_xfree() */
+struct pa_strlist* pa_strlist_pop(struct pa_strlist *l, char **s);
+
+/* Parse a whitespace separated server list */
+struct pa_strlist* pa_strlist_parse(const char *s);
+
+#endif
index ad91a30781e4786d67bcdd8dc9a592b9a22b3532..4db92cf44127addffaa0fce211fea061af8a923c 100644 (file)
@@ -51,6 +51,8 @@
 #include "xmalloc.h"
 #include "log.h"
 
+#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-"
+
 /** Make a file descriptor nonblock. Doesn't do any error checking */
 void pa_make_nonblock_fd(int fd) {
     int v;
@@ -83,6 +85,26 @@ fail:
     return -1;
 }
 
+/* Creates a the parent directory of the specified path securely */
+int pa_make_secure_parent_dir(const char *fn) {
+    int ret = -1;
+    char *slash, *dir = pa_xstrdup(fn);
+    
+    if (!(slash = strrchr(dir, '/')))
+        goto finish;
+    *slash = 0;
+    
+    if (pa_make_secure_dir(dir) < 0)
+        goto finish;
+
+    ret = 0;
+    
+finish:
+    pa_xfree(dir);
+    return ret;
+}
+
+
 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
  * unless EOF is reached or an error occured */
 ssize_t pa_loop_read(int fd, void*data, size_t size) {
@@ -225,31 +247,32 @@ char *pa_get_user_name(char *s, size_t l) {
     char *p;
     assert(s && l > 0);
 
-    if (!(p = getenv("USER")))
-        if (!(p = getenv("LOGNAME")))
-            if (!(p = getenv("USERNAME"))) {
-                
+    if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) {
+        
 #ifdef HAVE_GETPWUID_R
-                if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
+        if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
 #else
-               /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
-                * that do not support getpwuid_r. */
-               if ((r = getpwuid(getuid())) == NULL) {
+            /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
+             * that do not support getpwuid_r. */
+            if ((r = getpwuid(getuid())) == NULL) {
 #endif
-                    snprintf(s, l, "%lu", (unsigned long) getuid());
-                    return s;
-                }
-                
-                p = r->pw_name;
+                snprintf(s, l, "%lu", (unsigned long) getuid());
+                return s;
             }
+            
+            p = r->pw_name;
+        }
 
     return pa_strlcpy(s, p, l);
-}
+    }
 
 /* Return the current hostname in the specified buffer. */
 char *pa_get_host_name(char *s, size_t l) {
     assert(s && l > 0);
-    gethostname(s, l);
+    if (gethostname(s, l) < 0) {
+        pa_log(__FILE__": gethostname(): %s\n", strerror(errno));
+        return NULL;
+    }
     s[l-1] = 0;
     return s;
 }
@@ -264,8 +287,10 @@ char *pa_get_home_dir(char *s, size_t l) {
     if ((e = getenv("HOME")))
         return pa_strlcpy(s, e, l);
 
-    if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r)
+    if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
+        pa_log(__FILE__": getpwuid_r() failed\n");
         return NULL;
+    }
 
     return pa_strlcpy(s, r->pw_dir, l);
 }
@@ -479,7 +504,7 @@ char *pa_split_spaces(const char *c, const char **state) {
     const char *current = *state ? *state : c;
     size_t l;
 
-    if (!*current)
+    if (!*current || *c == 0)
         return NULL;
 
     current += strspn(current, WHITESPACE);
@@ -768,13 +793,13 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
             return (size_t) -1;
 
         d[j] |= (uint8_t) b;
-
         j++;
     }
 
     return j;
 }
 
+/* Return the fully qualified domain name in *s */
 char *pa_get_fqdn(char *s, size_t l) {
     char hn[256];
     struct addrinfo *a, hints;
@@ -793,3 +818,25 @@ char *pa_get_fqdn(char *s, size_t l) {
     freeaddrinfo(a);
     return s;
 }
+
+/* Returns nonzero when *s starts with *pfx */
+int pa_startswith(const char *s, const char *pfx) {
+    size_t l;
+    assert(s && pfx);
+    l = strlen(pfx);
+
+    return strlen(s) >= l && strncmp(s, pfx, l) == 0;
+}
+
+/* if fn is null return the polypaudio run time path in s (/tmp/polypaudio)
+ * if fn is non-null and starts with / return fn in s
+ * otherwise append fn to the run time path and return it in s */
+char *pa_runtime_path(const char *fn, char *s, size_t l) {
+    char u[256];
+
+    if (fn && *fn == '/')
+        return pa_strlcpy(s, fn, l);
+    
+    snprintf(s, l, PA_RUNTIME_PATH_PREFIX"%s%s%s", pa_get_user_name(u, sizeof(u)), fn ? "/" : "", fn ? fn : "");
+    return s;
+}
index 3f09a9a70c9ff1e26ace3ba07ac6aa14ec47a450..e9d938cea3946b7e79138dc6bf7c26011e607379 100644 (file)
@@ -33,6 +33,7 @@
 void pa_make_nonblock_fd(int fd);
 
 int pa_make_secure_dir(const char* dir);
+int pa_make_secure_parent_dir(const char *fn);
 
 ssize_t pa_loop_read(int fd, void*data, size_t size);
 ssize_t pa_loop_write(int fd, const void*data, size_t size);
@@ -85,4 +86,8 @@ FILE *pa_open_config_file(const char *env, const char *global, const char *local
 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength);
 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength);
 
+int pa_startswith(const char *s, const char *pfx);
+
+char *pa_runtime_path(const char *fn, char *s, size_t l);
+
 #endif