add username to runtime directory name in /tmp/

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
This commit is contained in:
Lennart Poettering 2004-11-11 21:18:33 +00:00
parent dbaa83c607
commit c005bd4666
22 changed files with 874 additions and 215 deletions

View file

@ -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

View 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

View file

@ -40,6 +40,9 @@ int pa_client_conf_from_x11(struct pa_client_conf *c, const char *dname) {
int ret = -1;
char t[1024];
if (!dname && !getenv("DISPLAY"))
goto finish;
if (!(d = XOpenDisplay(dname))) {
pa_log(__FILE__": XOpenDisplay() failed\n");
goto finish;

View file

@ -38,10 +38,14 @@
#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>"
@ -53,10 +57,12 @@
#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
@ -68,10 +74,12 @@
#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
@ -83,10 +91,12 @@
#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
@ -103,6 +113,8 @@
#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;
@ -142,29 +154,38 @@ static struct pa_socket_server *create_socket_server(struct pa_core *c, struct p
return NULL;
}
if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port, TCPWRAP_SERVICE)))
#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];
p = pa_modargs_get_value(ma, "socket", UNIX_SOCKET);
assert(p);
v = pa_modargs_get_value(ma, "socket", UNIX_SOCKET);
assert(v);
if (pa_unix_socket_make_secure_dir(p) < 0) {
pa_runtime_path(v, tmp, sizeof(tmp));
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

View 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;
if (!pa_get_user_name(un, sizeof(un)))
s = pa_strlist_tostring(l);
pa_x11_set_prop(u->display, "POLYP_SERVER", s);
pa_xfree(s);
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)))

View 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

View 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);
@ -134,6 +152,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);
static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata);
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);
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,11 +465,84 @@ fail:
if (fds[1] != -1)
close(fds[1]);
unlock_autospawn_lock_file(c);
pa_context_unref(c);
return -1;
}
static int try_next_connection(struct pa_context *c) {
char *u = NULL;
int r = -1;
assert(c && !c->client);
for (;;) {
if (u)
pa_xfree(u);
u = NULL;
c->server_list = pa_strlist_pop(c->server_list, &u);
if (!u) {
if (c->do_autospawn) {
r = context_connect_spawn(c);
goto finish;
}
pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
goto finish;
}
/* 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);
return r;
}
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_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;
}
pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
goto finish;
}
unlock_autospawn_lock_file(c);
setup_context(c, io);
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);
@ -477,59 +550,46 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons
if (!server)
server = c->conf->default_server;
if (!server && spawn && c->conf->autospawn) {
int lock_fd = pa_lock_lockfile(AUTOSPAWN_LOCK);
if (!default_server_is_running()) {
int r = context_connect_spawn(c, api);
if (lock_fd >= 0)
pa_unlock_lockfile(lock_fd);
return r;
}
if (lock_fd >= 0)
pa_unlock_lockfile(lock_fd);
}
if (!server)
server = PA_NATIVE_DEFAULT_SERVER_UNIX;
pa_context_ref(c);
assert(!c->client);
assert(!c->server_list);
if (*server == '/') {
if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
goto finish;
}
c->local = 1;
} else {
struct sockaddr* sa;
size_t sa_len;
if (!(sa = pa_resolve_server(server, &sa_len, PA_NATIVE_DEFAULT_PORT))) {
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];
c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
pa_xfree(sa);
/* Prepend in reverse order */
if (!c->client) {
pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
goto finish;
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)));
/* Wrap the connection attempts in a single transaction for sane autospwan locking */
if (spawn && c->conf->autospawn) {
char lf[PATH_MAX];
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);

View 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;
};

View 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);
}

View 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);

View 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)))
@ -2072,6 +2075,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,8 +2093,22 @@ 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);

View 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;
}

View file

@ -28,17 +28,19 @@
#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

View 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;
}
}

View 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

View 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;

View 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

39
polyp/strlist-test.c Normal file
View file

@ -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);
}

137
polyp/strlist.c Normal file
View file

@ -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;
}

47
polyp/strlist.h Normal file
View file

@ -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

View 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,9 +247,7 @@ 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) {
@ -244,12 +264,15 @@ char *pa_get_user_name(char *s, size_t l) {
}
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;
}

View 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