diff options
Diffstat (limited to 'src/pulse/context.c')
| -rw-r--r-- | src/pulse/context.c | 200 | 
1 files changed, 163 insertions, 37 deletions
diff --git a/src/pulse/context.c b/src/pulse/context.c index f56cb241..99a47a18 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -53,6 +53,8 @@  #include <pulse/xmalloc.h>  #include <pulse/utf8.h>  #include <pulse/util.h> +#include <pulse/i18n.h> +#include <pulse/lock-autospawn.h>  #include <pulsecore/winsock.h>  #include <pulsecore/core-error.h> @@ -80,7 +82,7 @@  #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] = {      [PA_COMMAND_REQUEST] = pa_command_request, @@ -93,23 +95,27 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {      [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = pa_command_stream_suspended,      [PA_COMMAND_RECORD_STREAM_SUSPENDED] = pa_command_stream_suspended,      [PA_COMMAND_STARTED] = pa_command_stream_started, -    [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event +    [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event, +    [PA_COMMAND_EXTENSION] = pa_command_extension  }; -static void unlock_autospawn_lock_file(pa_context *c) { +static void unlock_autospawn(pa_context *c) {      pa_assert(c); -    if (c->autospawn_lock_fd >= 0) { -        char *lf; +    if (c->autospawn_fd >= 0) { -        if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) -            pa_log_warn("Cannot unlock autospawn because runtime path is no more."); +        if (c->autospawn_locked) +            pa_autospawn_lock_release(); -        pa_unlock_lockfile(lf, c->autospawn_lock_fd); -        pa_xfree(lf); +        if (c->autospawn_event) +            c->mainloop->io_free(c->autospawn_event); -        c->autospawn_lock_fd = -1; +        pa_autospawn_lock_done(FALSE);      } + +    c->autospawn_locked = FALSE; +    c->autospawn_fd = -1; +    c->autospawn_event = NULL;  }  static void context_free(pa_context *c); @@ -126,6 +132,9 @@ static void reset_callbacks(pa_context *c) {      c->subscribe_callback = NULL;      c->subscribe_userdata = NULL; + +    c->ext_stream_restore.callback = NULL; +    c->ext_stream_restore.userdata = NULL;  }  pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) { @@ -133,6 +142,8 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *      pa_assert(mainloop); +    pa_init_i18n(); +      if (!name && !pa_proplist_contains(p, PA_PROP_APPLICATION_NAME))          return NULL; @@ -165,11 +176,15 @@ 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; +    c->autospawn_fd = -1; +    c->autospawn_locked = FALSE; +    c->autospawn_event = NULL; +    memset(&c->spawn_api, 0, sizeof(c->spawn_api)); +  #ifndef MSG_NOSIGNAL  #ifdef SIGPIPE      pa_check_signal_is_blocked(SIGPIPE); @@ -237,7 +252,7 @@ static void context_free(pa_context *c) {      context_unlink(c); -    unlock_autospawn_lock_file(c); +    unlock_autospawn(c);      if (c->record_streams)          pa_dynarray_free(c->record_streams, NULL, NULL); @@ -398,11 +413,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;  } @@ -424,7 +439,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)) { @@ -524,7 +539,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) {      c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);      if (!c->conf->cookie_valid) -        pa_log_info("No cookie loaded. Attempting to connect without."); +        pa_log_info(_("No cookie loaded. Attempting to connect without."));      t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); @@ -578,7 +593,7 @@ static int context_connect_spawn(pa_context *c) {      pa_context_ref(c);      if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { -        pa_log_error("socketpair(): %s", pa_cstrerror(errno)); +        pa_log_error(_("socketpair(): %s"), pa_cstrerror(errno));          pa_context_fail(c, PA_ERR_INTERNAL);          goto fail;      } @@ -592,7 +607,7 @@ static int context_connect_spawn(pa_context *c) {          c->spawn_api.prefork();      if ((pid = fork()) < 0) { -        pa_log_error("fork(): %s", pa_cstrerror(errno)); +        pa_log_error(_("fork(): %s"), pa_cstrerror(errno));          pa_context_fail(c, PA_ERR_INTERNAL);          if (c->spawn_api.postfork) @@ -655,7 +670,7 @@ static int context_connect_spawn(pa_context *c) {          c->spawn_api.postfork();      if (r < 0) { -        pa_log("waitpid(): %s", pa_cstrerror(errno)); +        pa_log(_("waitpid(): %s"), pa_cstrerror(errno));          pa_context_fail(c, PA_ERR_INTERNAL);          goto fail;      } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { @@ -665,7 +680,7 @@ static int context_connect_spawn(pa_context *c) {      c->is_local = TRUE; -    unlock_autospawn_lock_file(c); +    unlock_autospawn(c);      io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);      setup_context(c, io); @@ -677,7 +692,7 @@ static int context_connect_spawn(pa_context *c) {  fail:      pa_close_pipe(fds); -    unlock_autospawn_lock_file(c); +    unlock_autospawn(c);      pa_context_unref(c); @@ -759,15 +774,48 @@ static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userd          goto finish;      } -    unlock_autospawn_lock_file(c); +    unlock_autospawn(c);      setup_context(c, io);  finish:      pa_context_unref(c);  } +static void autospawn_cb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { +    pa_context *c = userdata; +    int k; + +    pa_assert(a); +    pa_assert(e); +    pa_assert(fd >= 0); +    pa_assert(events == PA_IO_EVENT_INPUT); +    pa_assert(c); +    pa_assert(e == c->autospawn_event); +    pa_assert(fd == c->autospawn_fd); + +    pa_context_ref(c); + +    /* Check whether we can get the lock right now*/ +    if ((k = pa_autospawn_lock_acquire(FALSE)) < 0) { +        pa_context_fail(c, PA_ERR_ACCESS); +        goto finish; +    } + +    if (k > 0) { +        /* So we got it, rock on! */ +        c->autospawn_locked = TRUE; +        try_next_connection(c); + +        c->mainloop->io_free(c->autospawn_event); +        c->autospawn_event = NULL; +    } -static char *get_legacy_runtime_dir(void) { +finish: + +    pa_context_unref(c); +} + +static char *get_old_legacy_runtime_dir(void) {      char *p, u[128];      struct stat st; @@ -789,6 +837,28 @@ static char *get_legacy_runtime_dir(void) {      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; +    } + +    return p; +} +  int pa_context_connect(          pa_context *c,          const char *server, @@ -816,6 +886,7 @@ int pa_context_connect(              pa_context_fail(c, PA_ERR_INVALIDSERVER);              goto finish;          } +      } else {          char *d, *ufn;          static char *legacy_dir; @@ -840,8 +911,16 @@ int pa_context_connect(          /* The system wide instance */          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())) { +        /* 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); +            c->server_list = pa_strlist_prepend(c->server_list, 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);              c->server_list = pa_strlist_prepend(c->server_list, p);              pa_xfree(p); @@ -856,21 +935,40 @@ int pa_context_connect(          /* Wrap the connection attempts in a single transaction for sane autospawn locking */          if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) { -            char *lf; +            int k; + +            pa_assert(c->autospawn_fd < 0); +            pa_assert(!c->autospawn_locked); -            if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) { +            /* Start the locking procedure */ +            if ((c->autospawn_fd = pa_autospawn_lock_init()) < 0) {                  pa_context_fail(c, PA_ERR_ACCESS);                  goto finish;              } -            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; + +            /* Check whether we can get the lock right now*/ +            if ((k = pa_autospawn_lock_acquire(FALSE)) < 0) { +                pa_context_fail(c, PA_ERR_ACCESS); +                goto finish; +            } + +            if (k > 0) +                /* So we got it, rock on! */ +                c->autospawn_locked = TRUE; +            else { +                /* Hmm, we didn't get it, so let's wait for it */ +                c->autospawn_event = c->mainloop->io_new(c->mainloop, c->autospawn_fd, PA_IO_EVENT_INPUT, autospawn_cb, c); + +                pa_context_set_state(c, PA_CONTEXT_CONNECTING); +                r = 0; +                goto finish; +            } +          }      } @@ -929,11 +1027,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);  } @@ -985,7 +1083,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; @@ -1137,7 +1235,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;  } @@ -1230,3 +1328,31 @@ pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[]      return o;  } + +void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +    pa_context *c = userdata; +    uint32_t idx; +    const char *name; + +    pa_assert(pd); +    pa_assert(command == PA_COMMAND_EXTENSION); +    pa_assert(t); +    pa_assert(c); +    pa_assert(PA_REFCNT_VALUE(c) >= 1); + +    pa_context_ref(c); + +    if (pa_tagstruct_getu32(t, &idx) < 0 || +        pa_tagstruct_gets(t, &name) < 0) { +        pa_context_fail(c, PA_ERR_PROTOCOL); +        goto finish; +    } + +    if (!strcmp(name, "module-stream-restore")) +        pa_ext_stream_restore_command(c, tag, t); +    else +        pa_log(_("Received message for unknown extension '%s'"), name); + +finish: +    pa_context_unref(c); +}  | 
