]> code.delx.au - pulseaudio/blobdiff - src/polyp/context.c
* split pa_cstrerror() into its own file polypcore/core-error.[ch]
[pulseaudio] / src / polyp / context.c
index 59079cb074135cba12c1de62b375be0d3150dd34..68fb4bf3e091564234294d1022a599f06a4c642c 100644 (file)
@@ -47,7 +47,9 @@
 
 #include "../polypcore/winsock.h"
 
+#include <polypcore/core-error.h>
 #include <polyp/version.h>
+#include <polyp/xmalloc.h>
 
 #include <polypcore/native-common.h>
 #include <polypcore/pdispatch.h>
@@ -55,8 +57,7 @@
 #include <polypcore/dynarray.h>
 #include <polypcore/socket-client.h>
 #include <polypcore/pstream-util.h>
-#include <polypcore/util.h>
-#include <polypcore/xmalloc.h>
+#include <polypcore/core-util.h>
 #include <polypcore/log.h>
 #include <polypcore/socket-util.h>
 
@@ -141,7 +142,7 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
     pa_client_conf_from_x11(c->conf, NULL);
 #endif
     pa_client_conf_env(c->conf);
-    
+
     return c;
 }
 
@@ -155,7 +156,7 @@ static void context_free(pa_context *c) {
 
     while (c->streams)
         pa_stream_set_state(c->streams, PA_STREAM_TERMINATED);
-    
+
     if (c->client)
         pa_socket_client_unref(c->client);
     if (c->pdispatch)
@@ -207,6 +208,10 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) {
 
     pa_context_ref(c);
 
+    c->state = st;
+    if (c->state_callback)
+        c->state_callback(c, c->state_userdata);
+
     if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) {
         pa_stream *s;
         
@@ -233,10 +238,6 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) {
         c->client = NULL;
     }
 
-    c->state = st;
-    if (c->state_callback)
-        c->state_callback(c, c->state_userdata);
-
     pa_context_unref(c);
 }
 
@@ -294,12 +295,14 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
     assert(c->ref >= 1);
 
     pa_context_ref(c);
-    
+
     if ((s = pa_dynarray_get(c->record_streams, channel))) {
 
+        assert(seek == PA_SEEK_RELATIVE && offset == 0);
+
         pa_memblockq_seek(s->record_memblockq, offset, seek);
         pa_memblockq_push_align(s->record_memblockq, chunk);
-
+        
         if (s->read_callback) {
             size_t l;
 
@@ -354,10 +357,23 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
     switch(c->state) {
         case PA_CONTEXT_AUTHORIZING: {
             pa_tagstruct *reply;
+
+            if (pa_tagstruct_getu32(t, &c->version) < 0 ||
+                !pa_tagstruct_eof(t)) {
+                pa_context_fail(c, PA_ERR_PROTOCOL);
+                goto finish;
+            }
+
+            /* Minimum supported version */
+            if (c->version < 8) {
+                pa_context_fail(c, PA_ERR_VERSION);
+                goto finish;
+            }
+
             reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
             pa_tagstruct_puts(reply, c->name);
             pa_pstream_send_tagstruct(c->pstream, reply);
-            pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
+            pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
 
             pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
             break;
@@ -400,9 +416,10 @@ static void setup_context(pa_context *c, pa_iochannel *io) {
     }
 
     t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag);
+    pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION);
     pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie));
     pa_pstream_send_tagstruct_with_creds(c->pstream, t, 1);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
 
     pa_context_set_state(c, PA_CONTEXT_AUTHORIZING);
 
@@ -424,7 +441,7 @@ static int context_connect_spawn(pa_context *c) {
     pa_context_ref(c);
     
     if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
-        pa_log(__FILE__": socketpair() failed: %s", strerror(errno));
+        pa_log(__FILE__": socketpair(): %s", pa_cstrerror(errno));
         pa_context_fail(c, PA_ERR_INTERNAL);
         goto fail;
     }
@@ -438,7 +455,7 @@ static int context_connect_spawn(pa_context *c) {
         c->spawn_api.prefork();
 
     if ((pid = fork()) < 0) {
-        pa_log(__FILE__": fork() failed: %s", strerror(errno));
+        pa_log(__FILE__": fork(): %s", pa_cstrerror(errno));
         pa_context_fail(c, PA_ERR_INTERNAL);
 
         if (c->spawn_api.postfork)
@@ -494,7 +511,7 @@ static int context_connect_spawn(pa_context *c) {
         c->spawn_api.postfork();
         
     if (r < 0) {
-        pa_log(__FILE__": waitpid() failed: %s", strerror(errno));
+        pa_log(__FILE__": waitpid(): %s", pa_cstrerror(errno));
         pa_context_fail(c, PA_ERR_INTERNAL);
         goto fail;
     } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
@@ -714,9 +731,12 @@ int pa_context_is_pending(pa_context *c) {
     assert(c);
     assert(c->ref >= 1);
 
-/*     pa_log("pstream: %i", pa_pstream_is_pending(c->pstream)); */
-/*     pa_log("pdispatch: %i", pa_pdispatch_is_pending(c->pdispatch)); */
-    
+    PA_CHECK_VALIDITY(c,
+                      c->state == PA_CONTEXT_CONNECTING ||
+                      c->state == PA_CONTEXT_AUTHORIZING ||
+                      c->state == PA_CONTEXT_SETTING_NAME ||
+                      c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+
     return (c->pstream && pa_pstream_is_pending(c->pstream)) ||
         (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) ||
         c->client;
@@ -754,18 +774,15 @@ static void set_dispatch_callbacks(pa_operation *o) {
         done = 0;
     }
 
-    if (!done)
-        pa_operation_ref(o);
-    else {
+    if (done) {
         if (o->callback) {
             pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback;
             cb(o->context, o->userdata);
         }
         
         pa_operation_done(o);
-    }   
-
-    pa_operation_unref(o);
+        pa_operation_unref(o);
+    }
 }
 
 pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
@@ -790,7 +807,9 @@ void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_U
     assert(pd);
     assert(o);
     assert(o->ref >= 1);
-    assert(o->context);
+
+    if (!o->context)
+        goto finish;
 
     if (command != PA_COMMAND_REPLY) {
         if (pa_context_handle_error(o->context, command, t) < 0)
@@ -826,7 +845,7 @@ pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb,
 
     t = pa_tagstruct_command(c, PA_COMMAND_EXIT, &tag);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o));
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
 
     return o;
 }
@@ -845,7 +864,7 @@ pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa
 
     t = pa_tagstruct_command(c, command, &tag);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o));
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
 
     return o;
 }
@@ -865,7 +884,7 @@ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_co
     t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag);
     pa_tagstruct_puts(t, name);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT,  pa_context_simple_ack_callback, pa_operation_ref(o));
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT,  pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
 
     return o;
 }
@@ -885,7 +904,7 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_
     t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag);
     pa_tagstruct_puts(t, name);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT,  pa_context_simple_ack_callback, pa_operation_ref(o));
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT,  pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
 
     return o;
 }
@@ -912,7 +931,7 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su
     t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
     pa_tagstruct_puts(t, name);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT,  pa_context_simple_ack_callback, pa_operation_ref(o));
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT,  pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
 
     return o;
 }
@@ -936,6 +955,17 @@ 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) {
+    return PA_PROTOCOL_VERSION;
+}
+
+uint32_t pa_context_get_server_protocol_version(pa_context *c) {
+    assert(c);
+    assert(c->ref >= 1);
+
+    return c->version;
+}
+
 pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) {
     pa_tagstruct *t;