iochannel/pstream/pdispatch: Add support for receiving file descriptors

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@canonical.com>
This commit is contained in:
David Henningsson 2014-04-15 15:37:44 +02:00
parent cc7a317e85
commit 06bc22b220
9 changed files with 84 additions and 31 deletions

View file

@ -1780,14 +1780,14 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) {
} }
/* Called from main context */ /* 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; struct userdata *u = userdata;
pa_assert(p); pa_assert(p);
pa_assert(packet); pa_assert(packet);
pa_assert(u); 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_log("Invalid packet");
pa_module_unload_request(u->module, true); pa_module_unload_request(u->module, true);
return; return;

View file

@ -316,7 +316,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) {
pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); 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_context *c = userdata;
pa_assert(p); pa_assert(p);
@ -325,7 +325,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_c
pa_context_ref(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_fail(c, PA_ERR_PROTOCOL);
pa_context_unref(c); pa_context_unref(c);

View file

@ -348,21 +348,26 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l
return r; 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; ssize_t r;
struct msghdr mh; struct msghdr mh;
struct iovec iov; struct iovec iov;
union { union {
struct cmsghdr hdr; 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; } cmsg;
pa_assert(io); pa_assert(io);
pa_assert(data); pa_assert(data);
pa_assert(l); pa_assert(l);
pa_assert(io->ifd >= 0); pa_assert(io->ifd >= 0);
pa_assert(creds); pa_assert(ancil);
pa_assert(creds_valid);
if (io->ifd_type > 0) {
ancil->creds_valid = false;
ancil->nfd = 0;
return pa_iochannel_read(io, data, l);
}
pa_zero(iov); pa_zero(iov);
iov.iov_base = data; iov.iov_base = data;
@ -378,19 +383,34 @@ 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) { if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
struct cmsghdr *cmh; struct cmsghdr *cmh;
*creds_valid = false; ancil->creds_valid = false;
ancil->nfd = 0;
for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) { 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; struct ucred u;
pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred))); pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred)); memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
creds->gid = u.gid; ancil->creds.gid = u.gid;
creds->uid = u.uid; ancil->creds.uid = u.uid;
*creds_valid = true; ancil->creds_valid = true;
break; }
else if (cmh->cmsg_type == SCM_RIGHTS) {
int nfd = (cmh->cmsg_len - CMSG_LEN(0)) / sizeof(int);
if (nfd > MAX_ANCIL_FDS) {
int i;
pa_log("Trying to receive too many file descriptors!");
for (i = 0; i < nfd; i++)
pa_close(((int*) CMSG_DATA(cmh))[i]);
continue;
}
memcpy(ancil->fds, CMSG_DATA(cmh), nfd * sizeof(int));
ancil->nfd = nfd;
} }
} }
@ -398,6 +418,11 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr
enable_events(io); enable_events(io);
} }
if (r == -1 && errno == ENOTSOCK) {
io->ifd_type = 1;
return pa_iochannel_read_with_ancil(io, data, l, ancil);
}
return r; return r;
} }

View file

@ -58,7 +58,7 @@ bool pa_iochannel_creds_supported(pa_iochannel *io);
int pa_iochannel_creds_enable(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_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 #endif
bool pa_iochannel_is_readable(pa_iochannel*io); bool pa_iochannel_is_readable(pa_iochannel*io);

View file

@ -216,7 +216,7 @@ struct pa_pdispatch {
PA_LLIST_HEAD(struct reply_info, replies); PA_LLIST_HEAD(struct reply_info, replies);
pa_pdispatch_drain_cb_t drain_callback; pa_pdispatch_drain_cb_t drain_callback;
void *drain_userdata; void *drain_userdata;
const pa_creds *creds; const pa_ancil *ancil;
bool use_rtclock; 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); 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; uint32_t tag, command;
pa_tagstruct *ts = NULL; pa_tagstruct *ts = NULL;
int ret = -1; int ret = -1;
@ -320,7 +320,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds,
} }
#endif #endif
pd->creds = creds; pd->ancil = ancil;
if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) {
struct reply_info *r; struct reply_info *r;
@ -344,7 +344,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds,
ret = 0; ret = 0;
finish: finish:
pd->creds = NULL; pd->ancil = NULL;
if (ts) if (ts)
pa_tagstruct_free(ts); pa_tagstruct_free(ts);
@ -437,5 +437,21 @@ const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
pa_assert(pd); pa_assert(pd);
pa_assert(PA_REFCNT_VALUE(pd) >= 1); 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;
} }

View file

@ -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); void pa_pdispatch_unref(pa_pdispatch *pd);
pa_pdispatch* pa_pdispatch_ref(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); 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 pa_creds * pa_pdispatch_creds(pa_pdispatch *pd);
const int * pa_pdispatch_fds(pa_pdispatch *pd, int *nfd);
#endif #endif

View file

@ -4816,14 +4816,14 @@ static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command,
/*** pstream callbacks ***/ /*** 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_native_connection *c = PA_NATIVE_CONNECTION(userdata);
pa_assert(p); pa_assert(p);
pa_assert(packet); pa_assert(packet);
pa_native_connection_assert_ref(c); 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."); pa_log("invalid packet.");
native_connection_unlink(c); native_connection_unlink(c);
} }

View file

@ -165,8 +165,9 @@ struct pa_pstream {
pa_mempool *mempool; pa_mempool *mempool;
#ifdef HAVE_CREDS #ifdef HAVE_CREDS
pa_creds read_creds, write_creds; pa_ancil read_ancil;
bool read_creds_valid, send_creds_now; pa_creds write_creds;
bool send_creds_now;
#endif #endif
}; };
@ -646,12 +647,20 @@ static int do_read(pa_pstream *p) {
#ifdef HAVE_CREDS #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; 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 #else
if ((r = pa_iochannel_read(p->io, d, l)) <= 0) 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) if (p->receive_packet_callback)
#ifdef HAVE_CREDS #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 #else
p->receive_packet_callback(p, p->read.packet, NULL, p->receive_packet_callback_userdata); p->receive_packet_callback(p, p->read.packet, NULL, p->receive_packet_callback_userdata);
#endif #endif
@ -860,7 +869,8 @@ frame_done:
p->read.data = NULL; p->read.data = NULL;
#ifdef HAVE_CREDS #ifdef HAVE_CREDS
p->read_creds_valid = false; p->read_ancil.creds_valid = false;
p->read_ancil.nfd = 0;
#endif #endif
return 0; return 0;

View file

@ -37,7 +37,7 @@
typedef struct pa_pstream pa_pstream; 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_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_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); typedef void (*pa_pstream_block_id_cb_t)(pa_pstream *p, uint32_t block_id, void *userdata);