diff options
| author | Lennart Poettering <lennart@poettering.net> | 2004-11-11 21:18:33 +0000 | 
|---|---|---|
| committer | Lennart Poettering <lennart@poettering.net> | 2004-11-11 21:18:33 +0000 | 
| commit | c005bd466651d8720aef3198d73bc0a3d459f953 (patch) | |
| tree | eb4bc36858b0e9a504b022a7f66b5fa21ff13f65 /polyp/polyplib-context.c | |
| parent | dbaa83c60730633315aa13d74907c6572985c050 (diff) | |
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
Diffstat (limited to 'polyp/polyplib-context.c')
| -rw-r--r-- | polyp/polyplib-context.c | 212 | 
1 files changed, 136 insertions, 76 deletions
| diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 36512a8a..a4770313 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -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); @@ -133,6 +151,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); - -    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); +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata); -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,71 +465,131 @@ fail:      if (fds[1] != -1)          close(fds[1]); +    unlock_autospawn_lock_file(c); +      pa_context_unref(c);      return -1;  } -int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) { +static int try_next_connection(struct pa_context *c) { +    char *u = NULL;      int r = -1; -    assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); - -    if (!server) -        server = c->conf->default_server; +    assert(c && !c->client); -    if (!server && spawn && c->conf->autospawn) { -        int lock_fd = pa_lock_lockfile(AUTOSPAWN_LOCK); +    for (;;) { +        if (u) +            pa_xfree(u); +        u = NULL; +         +        c->server_list = pa_strlist_pop(c->server_list, &u); -        if (!default_server_is_running()) { -            int r = context_connect_spawn(c, api); +        if (!u) { -            if (lock_fd >= 0) -                pa_unlock_lockfile(lock_fd); -            return r; +            if (c->do_autospawn) { +                r = context_connect_spawn(c); +                goto finish; +            } +             +            pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); +            goto finish;          } - -        if (lock_fd >= 0) -            pa_unlock_lockfile(lock_fd); +         +/*          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); -    if (!server) -        server = PA_NATIVE_DEFAULT_SERVER_UNIX; +    return r; +} -    pa_context_ref(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); -    assert(!c->client); +    pa_context_ref(c); -    if (*server == '/') { -        if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { -            pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); +    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;          } -        c->local = 1; -    } else { -        struct sockaddr* sa; -        size_t sa_len; +        pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); +        goto finish; +    } + +    unlock_autospawn_lock_file(c); +    setup_context(c, io); -        if (!(sa = pa_resolve_server(server, &sa_len, PA_NATIVE_DEFAULT_PORT))) { +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); + +    if (!server) +        server = c->conf->default_server; + + +    pa_context_ref(c); + +    assert(!c->server_list); +     +    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]; + +        /* Prepend in reverse order */ +         +        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))); -        c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); -        pa_xfree(sa); +        /* Wrap the connection attempts in a single transaction for sane autospwan locking */ +        if (spawn && c->conf->autospawn) { +            char lf[PATH_MAX]; -        if (!c->client) { -            pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); -            goto finish; +            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); | 
