diff options
Diffstat (limited to 'src/pulse/context.c')
| -rw-r--r-- | src/pulse/context.c | 318 | 
1 files changed, 110 insertions, 208 deletions
diff --git a/src/pulse/context.c b/src/pulse/context.c index f1aa4987..154e5faf 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -54,7 +54,6 @@  #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> @@ -98,26 +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(pa_context *c) { -    pa_assert(c); - -    if (c->autospawn_fd >= 0) { - -        if (c->autospawn_locked) -            pa_autospawn_lock_release(); - -        if (c->autospawn_event) -            c->mainloop->io_free(c->autospawn_event); - -        pa_autospawn_lock_done(FALSE); -    } - -    c->autospawn_locked = FALSE; -    c->autospawn_fd = -1; -    c->autospawn_event = NULL; -} -  static void context_free(pa_context *c);  pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { @@ -180,9 +159,6 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *      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 @@ -252,8 +228,6 @@ static void context_free(pa_context *c) {      context_unlink(c); -    unlock_autospawn(c); -      if (c->record_streams)          pa_dynarray_free(c->record_streams, NULL, NULL);      if (c->playback_streams) @@ -577,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; +    } + +    return p; +} + + +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);      } -    pa_make_fd_cloexec(fds[0]); +    /* 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; +} -    pa_make_socket_low_delay(fds[0]); -    pa_make_socket_low_delay(fds[1]); +#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(); @@ -617,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; @@ -661,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); @@ -678,21 +700,11 @@ static int context_connect_spawn(pa_context *c) {          goto fail;      } -    c->is_local = TRUE; - -    unlock_autospawn(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(c);      pa_context_unref(c); @@ -701,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; @@ -718,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 @@ -774,91 +798,12 @@ static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userd          goto finish;      } -    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; -    } - -finish: - -    pa_context_unref(c); -} - -static char *get_old_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; -} - -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, @@ -888,11 +833,11 @@ int pa_context_connect(          }      } 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); @@ -905,70 +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 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 user instance via PF_LOCAL */ +        c->server_list = prepend_per_user(c->server_list); -        /* 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); -            pa_xfree(legacy_dir); -        } - -        /* 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) { -            int k; - -            pa_assert(c->autospawn_fd < 0); -            pa_assert(!c->autospawn_locked); -            /* Start the locking procedure */ -            if ((c->autospawn_fd = pa_autospawn_lock_init()) < 0) { -                pa_context_fail(c, PA_ERR_ACCESS); -                goto finish; -            } - -            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; +            if (getuid() == 0) +                pa_log_debug("Not doing autospawn since we are root.");              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); +                c->do_autospawn = TRUE; -                pa_context_set_state(c, PA_CONTEXT_CONNECTING); -                r = 0; -                goto finish; +                if (api) +                    c->spawn_api = *api;              } -          }      }  | 
