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