mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
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:
parent
dbaa83c607
commit
c005bd4666
22 changed files with 874 additions and 215 deletions
2
doc/todo
2
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
39
polyp/strlist-test.c
Normal 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
137
polyp/strlist.c
Normal 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
47
polyp/strlist.h
Normal 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
|
||||
61
polyp/util.c
61
polyp/util.c
|
|
@ -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) {
|
||||
|
|
@ -249,7 +269,10 @@ char *pa_get_user_name(char *s, size_t 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue