[pulseaudio-discuss] [PATCH 03/11] iochannel/pstream: Support sending file descriptors

David Henningsson david.henningsson at canonical.com
Tue Apr 29 06:22:17 PDT 2014


This patch adds support to iochannel, pstream and pstream-util
to send file descriptors over a unix pipe.

Currently we don't support writing both creds and fds in the same
packet, it's either one or the other (or neither).

Signed-off-by: David Henningsson <david.henningsson at canonical.com>
---
 src/pulsecore/iochannel.c    | 43 +++++++++++++++++++++++++++++++++++++++++
 src/pulsecore/iochannel.h    |  1 +
 src/pulsecore/pstream-util.c | 31 +++++++++++++++++++++++++++--
 src/pulsecore/pstream-util.h |  1 +
 src/pulsecore/pstream.c      | 46 ++++++++++++++++++++++++++------------------
 src/pulsecore/pstream.h      |  2 +-
 6 files changed, 102 insertions(+), 22 deletions(-)

diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c
index a6efdf5..687114c 100644
--- a/src/pulsecore/iochannel.c
+++ b/src/pulsecore/iochannel.c
@@ -348,6 +348,49 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l
     return r;
 }
 
+ssize_t pa_iochannel_write_with_fds(pa_iochannel*io, const void*data, size_t l, int nfd, const int *fds) {
+    ssize_t r;
+    int *msgdata;
+    struct msghdr mh;
+    struct iovec iov;
+    union {
+        struct cmsghdr hdr;
+        uint8_t data[CMSG_SPACE(sizeof(int) * MAX_ANCIL_FDS)];
+    } cmsg;
+
+    pa_assert(io);
+    pa_assert(data);
+    pa_assert(l);
+    pa_assert(io->ofd >= 0);
+    pa_assert(fds);
+    pa_assert(nfd > 0);
+    pa_assert(nfd <= MAX_ANCIL_FDS);
+
+    pa_zero(iov);
+    iov.iov_base = (void*) data;
+    iov.iov_len = l;
+
+    pa_zero(cmsg);
+    cmsg.hdr.cmsg_level = SOL_SOCKET;
+    cmsg.hdr.cmsg_type = SCM_RIGHTS;
+
+    msgdata = (int*) CMSG_DATA(&cmsg.hdr);
+    memcpy(msgdata, fds, nfd * sizeof(int));
+    cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int) * nfd);
+
+    pa_zero(mh);
+    mh.msg_iov = &iov;
+    mh.msg_iovlen = 1;
+    mh.msg_control = &cmsg;
+    mh.msg_controllen = sizeof(cmsg);
+
+    if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
+        io->writable = io->hungup = false;
+        enable_events(io);
+    }
+    return r;
+}
+
 ssize_t pa_iochannel_read_with_ancil(pa_iochannel*io, void*data, size_t l, pa_ancil *ancil) {
     ssize_t r;
     struct msghdr mh;
diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h
index 4da8902..390f798 100644
--- a/src/pulsecore/iochannel.h
+++ b/src/pulsecore/iochannel.h
@@ -57,6 +57,7 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l);
 bool pa_iochannel_creds_supported(pa_iochannel *io);
 int pa_iochannel_creds_enable(pa_iochannel *io);
 
+ssize_t pa_iochannel_write_with_fds(pa_iochannel*io, const void*data, size_t l, int nfd, const int *fds);
 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred);
 ssize_t pa_iochannel_read_with_ancil(pa_iochannel*io, void*data, size_t l, pa_ancil *ancil);
 #endif
diff --git a/src/pulsecore/pstream-util.c b/src/pulsecore/pstream-util.c
index f84f486..ac256e2 100644
--- a/src/pulsecore/pstream-util.c
+++ b/src/pulsecore/pstream-util.c
@@ -28,7 +28,7 @@
 
 #include "pstream-util.h"
 
-void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const pa_creds *creds) {
+static void pa_pstream_send_tagstruct_with_ancil(pa_pstream *p, pa_tagstruct *t, const pa_ancil *ancil) {
     size_t length;
     uint8_t *data;
     pa_packet *packet;
@@ -38,10 +38,37 @@ void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const
 
     pa_assert_se(data = pa_tagstruct_free_data(t, &length));
     pa_assert_se(packet = pa_packet_new_dynamic(data, length));
-    pa_pstream_send_packet(p, packet, creds);
+    pa_pstream_send_packet(p, packet, ancil);
     pa_packet_unref(packet);
 }
 
+void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const pa_creds *creds) {
+    if (creds) {
+        pa_ancil a;
+
+        a.nfd = 0;
+        a.creds_valid = true;
+        a.creds = *creds;
+        pa_pstream_send_tagstruct_with_ancil(p, t, &a);
+    }
+    else
+        pa_pstream_send_tagstruct_with_ancil(p, t, NULL);
+}
+
+void pa_pstream_send_tagstruct_with_fds(pa_pstream *p, pa_tagstruct *t, int nfd, const int *fds) {
+    if (nfd > 0) {
+        pa_ancil a;
+
+        a.nfd = nfd;
+        a.creds_valid = false;
+        pa_assert(nfd <= MAX_ANCIL_FDS);
+        memcpy(a.fds, fds, sizeof(int) * nfd);
+        pa_pstream_send_tagstruct_with_ancil(p, t, &a);
+    }
+    else
+        pa_pstream_send_tagstruct_with_ancil(p, t, NULL);
+}
+
 void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) {
     pa_tagstruct *t;
 
diff --git a/src/pulsecore/pstream-util.h b/src/pulsecore/pstream-util.h
index ae0d79c..7ea89ba 100644
--- a/src/pulsecore/pstream-util.h
+++ b/src/pulsecore/pstream-util.h
@@ -29,6 +29,7 @@
 
 /* The tagstruct is freed!*/
 void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const pa_creds *creds);
+void pa_pstream_send_tagstruct_with_fds(pa_pstream *p, pa_tagstruct *t, int nfd, const int *fds);
 
 #define pa_pstream_send_tagstruct(p, t) pa_pstream_send_tagstruct_with_creds((p), (t), NULL)
 
diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c
index a3afed5..22ea250 100644
--- a/src/pulsecore/pstream.c
+++ b/src/pulsecore/pstream.c
@@ -94,8 +94,8 @@ struct item_info {
     /* packet info */
     pa_packet *packet;
 #ifdef HAVE_CREDS
-    bool with_creds;
-    pa_creds creds;
+    bool with_ancil;
+    pa_ancil ancil;
 #endif
 
     /* memblock info */
@@ -165,9 +165,8 @@ struct pa_pstream {
     pa_mempool *mempool;
 
 #ifdef HAVE_CREDS
-    pa_ancil read_ancil;
-    pa_creds write_creds;
-    bool send_creds_now;
+    pa_ancil read_ancil, write_ancil;
+    bool send_ancil_now;
 #endif
 };
 
@@ -298,7 +297,7 @@ static void pstream_free(pa_pstream *p) {
     pa_xfree(p);
 }
 
-void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds) {
+void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_ancil *ancil) {
     struct item_info *i;
 
     pa_assert(p);
@@ -315,8 +314,13 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre
     i->packet = pa_packet_ref(packet);
 
 #ifdef HAVE_CREDS
-    if ((i->with_creds = !!creds))
-        i->creds = *creds;
+    if ((i->with_ancil = !!ancil)) {
+        i->ancil = *ancil;
+        if (ancil->creds_valid)
+            pa_assert(ancil->nfd == 0);
+        else
+            pa_assert(ancil->nfd > 0);
+    }
 #endif
 
     pa_queue_push(p->send_queue, i);
@@ -358,7 +362,7 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa
         i->offset = offset;
         i->seek_mode = seek_mode;
 #ifdef HAVE_CREDS
-        i->with_creds = false;
+        i->with_ancil = false;
 #endif
 
         pa_queue_push(p->send_queue, i);
@@ -385,7 +389,7 @@ void pa_pstream_send_release(pa_pstream *p, uint32_t block_id) {
     item->type = PA_PSTREAM_ITEM_SHMRELEASE;
     item->block_id = block_id;
 #ifdef HAVE_CREDS
-    item->with_creds = false;
+    item->with_ancil = false;
 #endif
 
     pa_queue_push(p->send_queue, item);
@@ -422,7 +426,7 @@ void pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id) {
     item->type = PA_PSTREAM_ITEM_SHMREVOKE;
     item->block_id = block_id;
 #ifdef HAVE_CREDS
-    item->with_creds = false;
+    item->with_ancil = false;
 #endif
 
     pa_queue_push(p->send_queue, item);
@@ -536,8 +540,8 @@ static void prepare_next_write_item(pa_pstream *p) {
     }
 
 #ifdef HAVE_CREDS
-    if ((p->send_creds_now = p->write.current->with_creds))
-        p->write_creds = p->write.current->creds;
+    if ((p->send_ancil_now = p->write.current->with_ancil))
+        p->write_ancil = p->write.current->ancil;
 #endif
 }
 
@@ -579,12 +583,16 @@ static int do_write(pa_pstream *p) {
     pa_assert(l > 0);
 
 #ifdef HAVE_CREDS
-    if (p->send_creds_now) {
-
-        if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_creds)) < 0)
-            goto fail;
-
-        p->send_creds_now = false;
+    if (p->send_ancil_now) {
+        if (p->write_ancil.creds_valid) {
+            pa_assert(p->write_ancil.nfd == 0);
+            if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_ancil.creds)) < 0)
+                goto fail;
+        }
+        else
+            if ((r = pa_iochannel_write_with_fds(p->io, d, l, p->write_ancil.nfd, p->write_ancil.fds)) < 0)
+                goto fail;
+        p->send_ancil_now = false;
     } else
 #endif
 
diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h
index 9316d92..4961570 100644
--- a/src/pulsecore/pstream.h
+++ b/src/pulsecore/pstream.h
@@ -49,7 +49,7 @@ void pa_pstream_unref(pa_pstream*p);
 
 void pa_pstream_unlink(pa_pstream *p);
 
-void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds);
+void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_ancil *ancil);
 void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk);
 void pa_pstream_send_release(pa_pstream *p, uint32_t block_id);
 void pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id);
-- 
1.9.1



More information about the pulseaudio-discuss mailing list