[pulseaudio-discuss] [PATCH 02/12] iochannel/pstream/pdispatch: Add support for receiving file descriptors

David Henningsson david.henningsson at canonical.com
Fri May 30 04:59:21 PDT 2014


The file descriptors are read from the iochannel just like the creds are.
So instead of passing just creds (and creds_valid), we now pass the
entire pa_ancil struct.

Signed-off-by: David Henningsson <david.henningsson at canonical.com>
---
 src/modules/module-tunnel.c     |  4 ++--
 src/pulse/context.c             |  4 ++--
 src/pulsecore/iochannel.c       | 42 +++++++++++++++++++++++++++++++----------
 src/pulsecore/iochannel.h       |  2 +-
 src/pulsecore/pdispatch.c       | 26 ++++++++++++++++++++-----
 src/pulsecore/pdispatch.h       |  4 +++-
 src/pulsecore/protocol-native.c |  4 ++--
 src/pulsecore/pstream.c         | 24 ++++++++++++++++-------
 src/pulsecore/pstream.h         |  2 +-
 9 files changed, 81 insertions(+), 31 deletions(-)

diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c
index f0f0e31..193d091 100644
--- a/src/modules/module-tunnel.c
+++ b/src/modules/module-tunnel.c
@@ -1780,14 +1780,14 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) {
 }
 
 /* Called from main context */
-static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
+static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_ancil *ancil, void *userdata) {
     struct userdata *u = userdata;
 
     pa_assert(p);
     pa_assert(packet);
     pa_assert(u);
 
-    if (pa_pdispatch_run(u->pdispatch, packet, creds, u) < 0) {
+    if (pa_pdispatch_run(u->pdispatch, packet, ancil, u) < 0) {
         pa_log("Invalid packet");
         pa_module_unload_request(u->module, true);
         return;
diff --git a/src/pulse/context.c b/src/pulse/context.c
index ce19d91..f3adf4c 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -323,7 +323,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) {
     pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED);
 }
 
-static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
+static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_ancil *ancil, void *userdata) {
     pa_context *c = userdata;
 
     pa_assert(p);
@@ -332,7 +332,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_c
 
     pa_context_ref(c);
 
-    if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0)
+    if (pa_pdispatch_run(c->pdispatch, packet, ancil, c) < 0)
         pa_context_fail(c, PA_ERR_PROTOCOL);
 
     pa_context_unref(c);
diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c
index dce6734..4f9eca7 100644
--- a/src/pulsecore/iochannel.c
+++ b/src/pulsecore/iochannel.c
@@ -348,21 +348,26 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l
     return r;
 }
 
-ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, bool *creds_valid) {
+ssize_t pa_iochannel_read_with_ancil(pa_iochannel*io, void*data, size_t l, pa_ancil *ancil) {
     ssize_t r;
     struct msghdr mh;
     struct iovec iov;
     union {
         struct cmsghdr hdr;
-        uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
+        uint8_t data[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * MAX_ANCIL_FDS)];
     } cmsg;
 
     pa_assert(io);
     pa_assert(data);
     pa_assert(l);
     pa_assert(io->ifd >= 0);
-    pa_assert(creds);
-    pa_assert(creds_valid);
+    pa_assert(ancil);
+
+    if (io->ifd_type > 0) {
+        ancil->creds_valid = false;
+        ancil->nfd = 0;
+        return pa_iochannel_read(io, data, l);
+    }
 
     pa_zero(iov);
     iov.iov_base = data;
@@ -378,19 +383,31 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr
     if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
         struct cmsghdr *cmh;
 
-        *creds_valid = false;
+        ancil->creds_valid = false;
+        ancil->nfd = 0;
 
         for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
 
-            if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) {
+            if (cmh->cmsg_level != SOL_SOCKET)
+                continue;
+
+            if (cmh->cmsg_type == SCM_CREDENTIALS) {
                 struct ucred u;
                 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
                 memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
 
-                creds->gid = u.gid;
-                creds->uid = u.uid;
-                *creds_valid = true;
-                break;
+                ancil->creds.gid = u.gid;
+                ancil->creds.uid = u.uid;
+                ancil->creds_valid = true;
+            }
+            else if (cmh->cmsg_type == SCM_RIGHTS) {
+                int nfd = (cmh->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+                if (nfd > MAX_ANCIL_FDS) {
+                    pa_log("Trying to receive too many file descriptors!");
+                    continue;
+                }
+                memcpy(ancil->fds, CMSG_DATA(cmh), nfd * sizeof(int));
+                ancil->nfd = nfd;
             }
         }
 
@@ -398,6 +415,11 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr
         enable_events(io);
     }
 
+    if (r == -1 && errno == ENOTSOCK) {
+        io->ifd_type = 1;
+        return pa_iochannel_read_with_ancil(io, data, l, ancil);
+    }
+
     return r;
 }
 
diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h
index e95f46f..4da8902 100644
--- a/src/pulsecore/iochannel.h
+++ b/src/pulsecore/iochannel.h
@@ -58,7 +58,7 @@ bool pa_iochannel_creds_supported(pa_iochannel *io);
 int pa_iochannel_creds_enable(pa_iochannel *io);
 
 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_creds(pa_iochannel*io, void*data, size_t l, pa_creds *ucred, bool *creds_valid);
+ssize_t pa_iochannel_read_with_ancil(pa_iochannel*io, void*data, size_t l, pa_ancil *ancil);
 #endif
 
 bool pa_iochannel_is_readable(pa_iochannel*io);
diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c
index 1766d6d..483ce6b 100644
--- a/src/pulsecore/pdispatch.c
+++ b/src/pulsecore/pdispatch.c
@@ -216,7 +216,7 @@ struct pa_pdispatch {
     PA_LLIST_HEAD(struct reply_info, replies);
     pa_pdispatch_drain_cb_t drain_callback;
     void *drain_userdata;
-    const pa_creds *creds;
+    const pa_ancil *ancil;
     bool use_rtclock;
 };
 
@@ -286,7 +286,7 @@ static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command,
     pa_pdispatch_unref(pd);
 }
 
-int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, void *userdata) {
+int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_ancil *ancil, void *userdata) {
     uint32_t tag, command;
     pa_tagstruct *ts = NULL;
     int ret = -1;
@@ -320,7 +320,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds,
 }
 #endif
 
-    pd->creds = creds;
+    pd->ancil = ancil;
 
     if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) {
         struct reply_info *r;
@@ -344,7 +344,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds,
     ret = 0;
 
 finish:
-    pd->creds = NULL;
+    pd->ancil = NULL;
 
     if (ts)
         pa_tagstruct_free(ts);
@@ -437,5 +437,21 @@ const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
     pa_assert(pd);
     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
 
-    return pd->creds;
+    if (pd->ancil && pd->ancil->creds_valid)
+         return &pd->ancil->creds;
+    return NULL;
+}
+
+const int * pa_pdispatch_fds(pa_pdispatch *pd, int *nfd) {
+    pa_assert(pd);
+    pa_assert(PA_REFCNT_VALUE(pd) >= 1);
+    pa_assert(nfd);
+
+    if (pd->ancil) {
+         *nfd = pd->ancil->nfd;
+         return pd->ancil->fds;
+    }
+
+    *nfd = 0;
+    return NULL;
 }
diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h
index 797ddca..038f90d 100644
--- a/src/pulsecore/pdispatch.h
+++ b/src/pulsecore/pdispatch.h
@@ -41,7 +41,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, bool use_rtclock, const pa_pd
 void pa_pdispatch_unref(pa_pdispatch *pd);
 pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd);
 
-int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const pa_creds *creds, void *userdata);
+int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const pa_ancil *ancil, void *userdata);
 
 void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata, pa_free_cb_t free_cb);
 
@@ -54,4 +54,6 @@ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata);
 
 const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd);
 
+const int * pa_pdispatch_fds(pa_pdispatch *pd, int *nfd);
+
 #endif
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 606bf25..7262944 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -4816,14 +4816,14 @@ static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command,
 
 /*** pstream callbacks ***/
 
-static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
+static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_ancil *ancil, void *userdata) {
     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
 
     pa_assert(p);
     pa_assert(packet);
     pa_native_connection_assert_ref(c);
 
-    if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
+    if (pa_pdispatch_run(c->pdispatch, packet, ancil, c) < 0) {
         pa_log("invalid packet.");
         native_connection_unlink(c);
     }
diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c
index 2c1444f..a3afed5 100644
--- a/src/pulsecore/pstream.c
+++ b/src/pulsecore/pstream.c
@@ -165,8 +165,9 @@ struct pa_pstream {
     pa_mempool *mempool;
 
 #ifdef HAVE_CREDS
-    pa_creds read_creds, write_creds;
-    bool read_creds_valid, send_creds_now;
+    pa_ancil read_ancil;
+    pa_creds write_creds;
+    bool send_creds_now;
 #endif
 };
 
@@ -646,12 +647,20 @@ static int do_read(pa_pstream *p) {
 
 #ifdef HAVE_CREDS
     {
-        bool b = 0;
+        pa_ancil b;
 
-        if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->read_creds, &b)) <= 0)
+        if ((r = pa_iochannel_read_with_ancil(p->io, d, l, &b)) <= 0)
             goto fail;
 
-        p->read_creds_valid = p->read_creds_valid || b;
+        if (b.creds_valid) {
+            p->read_ancil.creds_valid = true;
+            p->read_ancil.creds = b.creds;
+        }
+        if (b.nfd > 0) {
+            pa_assert(b.nfd <= MAX_ANCIL_FDS);
+            p->read_ancil.nfd = b.nfd;
+            memcpy(p->read_ancil.fds, b.fds, sizeof(int) * b.nfd);
+        }
     }
 #else
     if ((r = pa_iochannel_read(p->io, d, l)) <= 0)
@@ -799,7 +808,7 @@ static int do_read(pa_pstream *p) {
 
                 if (p->receive_packet_callback)
 #ifdef HAVE_CREDS
-                    p->receive_packet_callback(p, p->read.packet, p->read_creds_valid ? &p->read_creds : NULL, p->receive_packet_callback_userdata);
+                    p->receive_packet_callback(p, p->read.packet, &p->read_ancil, p->receive_packet_callback_userdata);
 #else
                     p->receive_packet_callback(p, p->read.packet, NULL, p->receive_packet_callback_userdata);
 #endif
@@ -860,7 +869,8 @@ frame_done:
     p->read.data = NULL;
 
 #ifdef HAVE_CREDS
-    p->read_creds_valid = false;
+    p->read_ancil.creds_valid = false;
+    p->read_ancil.nfd = 0;
 #endif
 
     return 0;
diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h
index deb2bc3..9316d92 100644
--- a/src/pulsecore/pstream.h
+++ b/src/pulsecore/pstream.h
@@ -37,7 +37,7 @@
 
 typedef struct pa_pstream pa_pstream;
 
-typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata);
+typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const pa_ancil *ancil, void *userdata);
 typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata);
 typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata);
 typedef void (*pa_pstream_block_id_cb_t)(pa_pstream *p, uint32_t block_id, void *userdata);
-- 
1.9.1



More information about the pulseaudio-discuss mailing list