]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/protocol-native.c
add new native protocol function for moving sink inputs between sinks
[pulseaudio] / src / pulsecore / protocol-native.c
index 2775d7745b5733c7216fb11e221684b4287329e7..f14aa8730de1aec04162e933ed60dffa339a94b9 100644 (file)
@@ -57,6 +57,7 @@
 #include <pulsecore/llist.h>
 #include <pulsecore/creds.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/ipacl.h>
 
 #include "protocol-native.h"
 
@@ -139,6 +140,7 @@ struct pa_protocol_native {
 #ifdef HAVE_CREDS
     char *auth_group;
 #endif
+    pa_ip_acl *auth_ip_acl;
 };
 
 static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk);
@@ -187,6 +189,7 @@ static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32
 static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void command_move_stream(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_ERROR] = NULL,
@@ -255,7 +258,10 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info,
     [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list,
     [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload,
-    [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload
+    [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload,
+
+    [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
+    [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream
 };
 
 /* structure management */
@@ -942,7 +948,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t
         }
 #endif
 
-        if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
+        if (!success && memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
             success = 1;
 
         if (!success) {
@@ -1099,7 +1105,7 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
     pa_tagstruct_put_usec(reply, latency);
     
     pa_tagstruct_put_usec(reply, 0);
-    pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq));
+    pa_tagstruct_put_boolean(reply, s->sink_input->state == PA_SINK_INPUT_RUNNING);
     pa_tagstruct_put_timeval(reply, &tv);
     pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
     pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
@@ -2107,6 +2113,45 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC
     pa_pstream_send_tagstruct(c->pstream, reply);
 }
 
+static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+    struct connection *c = userdata;
+    uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
+    pa_sink_input *si = NULL;
+    pa_sink *sink = NULL;
+    const char *name = NULL;
+    
+    assert(c);
+    assert(t);
+
+    if (pa_tagstruct_getu32(t, &idx) < 0 ||
+        pa_tagstruct_getu32(t, &idx_device) < 0 ||
+        pa_tagstruct_gets(t, &name) < 0 ||
+        !pa_tagstruct_eof(t)) {
+        protocol_error(c);
+        return;
+    }
+    
+    CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+    CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
+    CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
+
+    si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
+    
+    if (idx_device != PA_INVALID_INDEX)
+        sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
+    else
+        sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
+    
+    CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
+
+    if (pa_sink_input_move_to(si, sink, 0) < 0) {
+        pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
+        return;
+    }
+
+    pa_pstream_send_simple_ack(c->pstream, tag);
+}
+
 /*** pstream callbacks ***/
 
 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
@@ -2239,8 +2284,13 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo
 
     c = pa_xmalloc(sizeof(struct connection));
 
-    c->authorized =!! p->public;
+    c->authorized = !!p->public;
 
+    if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
+        pa_log_info(__FILE__": Client authenticated by IP ACL.");
+        c->authorized = 1;
+    }
+    
     if (!c->authorized) {
         struct timeval tv;
         pa_gettimeofday(&tv);
@@ -2319,7 +2369,10 @@ static int load_key(pa_protocol_native*p, const char*fn) {
 static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) {
     pa_protocol_native *p;
     int public = 0;
-    assert(c && ma);
+    const char *acl;
+    
+    assert(c);
+    assert(ma);
 
     if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) {
         pa_log(__FILE__": auth-anonymous= expects a boolean argument.");
@@ -2331,7 +2384,8 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo
     p->module = m;
     p->public = public;
     p->server = NULL;
-
+    p->auth_ip_acl = NULL;
+    
 #ifdef HAVE_CREDS
     {
         int a = 1;
@@ -2345,16 +2399,32 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo
             pa_log_info(__FILE__": Allowing access to group '%s'.", p->auth_group);
     }
 #endif
-    
-    if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) {
-        pa_xfree(p);
-        return NULL;
+
+
+    if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
+
+        if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) {
+            pa_log(__FILE__": Failed to parse IP ACL '%s'", acl);
+            goto fail;
+        }
     }
 
+    if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0)
+        goto fail;
+
     p->connections = pa_idxset_new(NULL, NULL);
     assert(p->connections);
 
     return p;
+
+fail:
+#ifdef HAVE_CREDS
+    pa_xfree(p->auth_group);
+#endif
+    if (p->auth_ip_acl)
+        pa_ip_acl_free(p->auth_ip_acl);
+    pa_xfree(p);
+    return NULL;
 }
 
 pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
@@ -2405,6 +2475,9 @@ void pa_protocol_native_free(pa_protocol_native *p) {
     if (p->auth_cookie_in_property)
         pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
 
+    if (p->auth_ip_acl)
+        pa_ip_acl_free(p->auth_ip_acl);
+    
 #ifdef HAVE_CREDS
     pa_xfree(p->auth_group);
 #endif