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

@ -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,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) {
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) {
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);
}
if (r == -1 && errno == ENOTSOCK) {
io->ifd_type = 1;
return pa_iochannel_read_with_ancil(io, data, l, ancil);
}
return r;
}