diff options
Diffstat (limited to 'src/pulse/context.c')
-rw-r--r-- | src/pulse/context.c | 261 |
1 files changed, 126 insertions, 135 deletions
diff --git a/src/pulse/context.c b/src/pulse/context.c index 5be4078b..3145d9c8 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -81,8 +81,6 @@ #include "context.h" -#define AUTOSPAWN_LOCK "autospawn.lock" - void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { @@ -99,23 +97,6 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event, [PA_COMMAND_EXTENSION] = pa_command_extension }; - -static void unlock_autospawn_lock_file(pa_context *c) { - pa_assert(c); - - if (c->autospawn_lock_fd >= 0) { - char *lf; - - if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) - pa_log_warn(_("Cannot unlock autospawn because runtime path is no more.")); - - pa_unlock_lockfile(lf, c->autospawn_lock_fd); - pa_xfree(lf); - - c->autospawn_lock_fd = -1; - } -} - static void context_free(pa_context *c); pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { @@ -174,11 +155,12 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char * c->is_local = FALSE; c->server_list = NULL; c->server = NULL; - c->autospawn_lock_fd = -1; - memset(&c->spawn_api, 0, sizeof(c->spawn_api)); - c->do_autospawn = FALSE; + c->do_shm = FALSE; + c->do_autospawn = FALSE; + memset(&c->spawn_api, 0, sizeof(c->spawn_api)); + #ifndef MSG_NOSIGNAL #ifdef SIGPIPE pa_check_signal_is_blocked(SIGPIPE); @@ -192,10 +174,10 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char * pa_client_conf_load(c->conf, NULL); pa_client_conf_env(c->conf); - if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm))) { + if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) { if (!c->conf->disable_shm) - c->mempool = pa_mempool_new(0); + c->mempool = pa_mempool_new(FALSE, c->conf->shm_size); if (!c->mempool) { context_free(c); @@ -246,8 +228,6 @@ static void context_free(pa_context *c) { context_unlink(c); - unlock_autospawn_lock_file(c); - if (c->record_streams) pa_dynarray_free(c->record_streams, NULL, NULL); if (c->playback_streams) @@ -407,11 +387,11 @@ int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, pa err = PA_ERR_UNKNOWN; if (fail) { - pa_context_fail(c, err); + pa_context_fail(c, (int) err); return -1; } - pa_context_set_error(c, err); + pa_context_set_error(c, (int) err); return 0; } @@ -433,7 +413,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t switch(c->state) { case PA_CONTEXT_AUTHORIZING: { pa_tagstruct *reply; - pa_bool_t shm_on_remote; + pa_bool_t shm_on_remote = FALSE; if (pa_tagstruct_getu32(t, &c->version) < 0 || !pa_tagstruct_eof(t)) { @@ -571,31 +551,89 @@ static void setup_context(pa_context *c, pa_iochannel *io) { pa_context_unref(c); } -static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); +static char *get_old_legacy_runtime_dir(void) { + char *p, u[128]; + struct stat st; -#ifndef OS_IS_WIN32 + if (!pa_get_user_name(u, sizeof(u))) + return NULL; -static int context_connect_spawn(pa_context *c) { - pid_t pid; - int status, r; - int fds[2] = { -1, -1} ; - pa_iochannel *io; + p = pa_sprintf_malloc("/tmp/pulse-%s", u); - if (getuid() == 0) - return -1; + if (stat(p, &st) < 0) { + pa_xfree(p); + return NULL; + } - pa_context_ref(c); + if (st.st_uid != getuid()) { + pa_xfree(p); + return NULL; + } - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - pa_log_error(_("socketpair(): %s"), pa_cstrerror(errno)); - pa_context_fail(c, PA_ERR_INTERNAL); - goto fail; + return p; +} + +static char *get_very_old_legacy_runtime_dir(void) { + char *p, h[128]; + struct stat st; + + if (!pa_get_home_dir(h, sizeof(h))) + return NULL; + + p = pa_sprintf_malloc("%s/.pulse", h); + + if (stat(p, &st) < 0) { + pa_xfree(p); + return NULL; + } + + if (st.st_uid != getuid()) { + pa_xfree(p); + return NULL; } - pa_make_fd_cloexec(fds[0]); + return p; +} - pa_make_socket_low_delay(fds[0]); - pa_make_socket_low_delay(fds[1]); + +static pa_strlist *prepend_per_user(pa_strlist *l) { + char *ufn; + static char *legacy_dir; + + /* The very old per-user instance path (< 0.9.11). This is supported only to ease upgrades */ + if ((legacy_dir = get_very_old_legacy_runtime_dir())) { + char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir); + l = pa_strlist_prepend(l, p); + pa_xfree(p); + pa_xfree(legacy_dir); + } + + /* The old per-user instance path (< 0.9.12). This is supported only to ease upgrades */ + if ((legacy_dir = get_old_legacy_runtime_dir())) { + char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir); + l = pa_strlist_prepend(l, p); + pa_xfree(p); + pa_xfree(legacy_dir); + } + + /* The per-user instance */ + if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) { + l = pa_strlist_prepend(l, ufn); + pa_xfree(ufn); + } + + return l; +} + +#ifndef OS_IS_WIN32 + +static int context_autospawn(pa_context *c) { + pid_t pid; + int status, r; + + pa_log_debug("Trying to autospawn..."); + + pa_context_ref(c); if (c->spawn_api.prefork) c->spawn_api.prefork(); @@ -611,31 +649,22 @@ static int context_connect_spawn(pa_context *c) { } else if (!pid) { /* Child */ - char t[128]; const char *state = NULL; #define MAX_ARGS 64 const char * argv[MAX_ARGS+1]; int n; - char *f; - - pa_close_all(fds[1], -1); - - f = pa_sprintf_malloc("%i", fds[1]); - pa_set_env("PULSE_PASSED_FD", f); - pa_xfree(f); if (c->spawn_api.atfork) c->spawn_api.atfork(); + pa_close_all(-1); + /* Setup argv */ n = 0; argv[n++] = c->conf->daemon_binary; - argv[n++] = "--daemonize=yes"; - - pa_snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - argv[n++] = strdup(t); + argv[n++] = "--start"; while (n < MAX_ARGS) { char *a; @@ -655,14 +684,13 @@ static int context_connect_spawn(pa_context *c) { /* Parent */ - pa_assert_se(pa_close(fds[1]) == 0); - fds[1] = -1; - - r = waitpid(pid, &status, 0); - if (c->spawn_api.postfork) c->spawn_api.postfork(); + do { + r = waitpid(pid, &status, 0); + } while (r < 0 && errno == EINTR); + if (r < 0) { pa_log(_("waitpid(): %s"), pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); @@ -672,21 +700,11 @@ static int context_connect_spawn(pa_context *c) { goto fail; } - c->is_local = TRUE; - - unlock_autospawn_lock_file(c); - - io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); - setup_context(c, io); - pa_context_unref(c); return 0; fail: - pa_close_pipe(fds); - - unlock_autospawn_lock_file(c); pa_context_unref(c); @@ -695,6 +713,8 @@ fail: #endif /* OS_IS_WIN32 */ +static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); + static int try_next_connection(pa_context *c) { char *u = NULL; int r = -1; @@ -712,8 +732,18 @@ static int try_next_connection(pa_context *c) { #ifndef OS_IS_WIN32 if (c->do_autospawn) { - r = context_connect_spawn(c); - goto finish; + + if ((r = context_autospawn(c)) < 0) + goto finish; + + /* Autospawn only once */ + c->do_autospawn = FALSE; + + /* Connect only to per-user sockets this time */ + c->server_list = prepend_per_user(c->server_list); + + /* Retry connection */ + continue; } #endif @@ -768,36 +798,12 @@ static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userd goto finish; } - unlock_autospawn_lock_file(c); setup_context(c, io); finish: pa_context_unref(c); } - -static char *get_legacy_runtime_dir(void) { - char *p, u[128]; - struct stat st; - - if (!pa_get_user_name(u, sizeof(u))) - return NULL; - - p = pa_sprintf_malloc("/tmp/pulse-%s", u); - - if (stat(p, &st) < 0) { - pa_xfree(p); - return NULL; - } - - if (st.st_uid != getuid()) { - pa_xfree(p); - return NULL; - } - - return p; -} - int pa_context_connect( pa_context *c, const char *server, @@ -825,12 +831,13 @@ int pa_context_connect( pa_context_fail(c, PA_ERR_INVALIDSERVER); goto finish; } + } else { - char *d, *ufn; - static char *legacy_dir; + char *d; /* Prepend in reverse order */ + /* Follow the X display */ if ((d = getenv("DISPLAY"))) { char *e; d = pa_xstrdup(d); @@ -843,43 +850,27 @@ int pa_context_connect( pa_xfree(d); } - c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); - c->server_list = pa_strlist_prepend(c->server_list, "tcp4:localhost"); + /* Add TCP/IP on the localhost */ + c->server_list = pa_strlist_prepend(c->server_list, "tcp6:[::1]"); + c->server_list = pa_strlist_prepend(c->server_list, "tcp4:127.0.0.1"); - /* The system wide instance */ + /* The system wide instance via PF_LOCAL */ c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET); - /* The old per-user instance path. This is supported only to ease upgrades */ - if ((legacy_dir = get_legacy_runtime_dir())) { - char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir); - c->server_list = pa_strlist_prepend(c->server_list, p); - pa_xfree(p); - pa_xfree(legacy_dir); - } + /* The user instance via PF_LOCAL */ + c->server_list = prepend_per_user(c->server_list); - /* The per-user instance */ - if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) { - c->server_list = pa_strlist_prepend(c->server_list, ufn); - pa_xfree(ufn); - } - - /* Wrap the connection attempts in a single transaction for sane autospawn locking */ + /* Set up autospawning */ if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) { - char *lf; - if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) { - pa_context_fail(c, PA_ERR_ACCESS); - goto finish; - } + if (getuid() == 0) + pa_log_debug("Not doing autospawn since we are root."); + else { + c->do_autospawn = TRUE; - pa_assert(c->autospawn_lock_fd <= 0); - c->autospawn_lock_fd = pa_lock_lockfile(lf); - pa_xfree(lf); - - if (api) - c->spawn_api = *api; - - c->do_autospawn = TRUE; + if (api) + c->spawn_api = *api; + } } } @@ -938,11 +929,11 @@ int pa_context_is_pending(pa_context *c) { static void set_dispatch_callbacks(pa_operation *o); -static void pdispatch_drain_callback(PA_GCC_UNUSED pa_pdispatch*pd, void *userdata) { +static void pdispatch_drain_callback(pa_pdispatch*pd, void *userdata) { set_dispatch_callbacks(userdata); } -static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) { +static void pstream_drain_callback(pa_pstream *s, void *userdata) { set_dispatch_callbacks(userdata); } @@ -994,7 +985,7 @@ pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *u return o; } -void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { +void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; int success = 1; @@ -1146,7 +1137,7 @@ const char* pa_context_get_server(pa_context *c) { return c->server; } -uint32_t pa_context_get_protocol_version(PA_GCC_UNUSED pa_context *c) { +uint32_t pa_context_get_protocol_version(pa_context *c) { return PA_PROTOCOL_VERSION; } |