2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
33 #include <pulse/xmalloc.h>
35 #include <pulsecore/core-error.h>
36 #include <pulsecore/core-util.h>
37 #include <pulsecore/socket.h>
38 #include <pulsecore/socket-util.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/macro.h>
42 #include "iochannel.h"
46 int ifd_type, ofd_type;
47 pa_mainloop_api* mainloop;
49 pa_iochannel_cb_t callback;
57 pa_io_event* input_event, *output_event;
60 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata);
62 static void delete_events(pa_iochannel *io) {
66 io->mainloop->io_free(io->input_event);
68 if (io->output_event && io->output_event != io->input_event)
69 io->mainloop->io_free(io->output_event);
71 io->input_event = io->output_event = NULL;
74 static void enable_events(pa_iochannel *io) {
82 if (io->ifd == io->ofd && io->ifd >= 0) {
83 pa_io_event_flags_t f = PA_IO_EVENT_NULL;
86 f |= PA_IO_EVENT_INPUT;
88 f |= PA_IO_EVENT_OUTPUT;
90 pa_assert(io->input_event == io->output_event);
92 if (f != PA_IO_EVENT_NULL) {
94 io->mainloop->io_enable(io->input_event, f);
96 io->input_event = io->output_event = io->mainloop->io_new(io->mainloop, io->ifd, f, callback, io);
105 io->mainloop->io_enable(io->input_event, PA_IO_EVENT_INPUT);
107 io->input_event = io->mainloop->io_new(io->mainloop, io->ifd, PA_IO_EVENT_INPUT, callback, io);
108 } else if (io->input_event) {
109 io->mainloop->io_free(io->input_event);
110 io->input_event = NULL;
116 if (io->output_event)
117 io->mainloop->io_enable(io->output_event, PA_IO_EVENT_OUTPUT);
119 io->output_event = io->mainloop->io_new(io->mainloop, io->ofd, PA_IO_EVENT_OUTPUT, callback, io);
120 } else if (io->output_event) {
121 io->mainloop->io_free(io->output_event);
122 io->output_event = NULL;
128 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
129 pa_iochannel *io = userdata;
130 bool changed = false;
137 if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
142 if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
145 pa_assert(e == io->input_event);
148 if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
151 pa_assert(e == io->output_event);
158 io->callback(io, io->userdata);
162 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
166 pa_assert(ifd >= 0 || ofd >= 0);
168 io = pa_xnew0(pa_iochannel, 1);
174 pa_make_fd_nonblock(io->ifd);
176 if (io->ofd >= 0 && io->ofd != io->ifd)
177 pa_make_fd_nonblock(io->ofd);
183 void pa_iochannel_free(pa_iochannel*io) {
191 if (io->ofd >= 0 && io->ofd != io->ifd)
198 bool pa_iochannel_is_readable(pa_iochannel*io) {
201 return io->readable || io->hungup;
204 bool pa_iochannel_is_writable(pa_iochannel*io) {
207 return io->writable && !io->hungup;
210 bool pa_iochannel_is_hungup(pa_iochannel*io) {
216 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
222 pa_assert(io->ofd >= 0);
224 r = pa_write(io->ofd, data, l, &io->ofd_type);
227 return r; /* Fast path - we almost always successfully write everything */
236 /* Partial write - let's get a notification when we can write more */
237 io->writable = io->hungup = false;
243 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
248 pa_assert(io->ifd >= 0);
250 if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
252 /* We also reset the hangup flag here to ensure that another
253 * IO callback is triggered so that we will again call into
255 io->readable = io->hungup = false;
264 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
265 typedef struct cmsgcred pa_ucred_t;
266 #define SCM_CREDENTIALS SCM_CREDS
268 typedef struct ucred pa_ucred_t;
271 bool pa_iochannel_creds_supported(pa_iochannel *io) {
275 struct sockaddr_un un;
277 struct sockaddr_storage storage;
283 pa_assert(io->ifd >= 0);
284 pa_assert(io->ofd == io->ifd);
287 if (getsockname(io->ifd, &sa.sa, &l) < 0)
290 return sa.sa.sa_family == AF_UNIX;
293 int pa_iochannel_creds_enable(pa_iochannel *io) {
294 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
299 pa_assert(io->ifd >= 0);
301 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
302 if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
303 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
311 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
317 uint8_t data[CMSG_SPACE(sizeof(pa_ucred_t))];
324 pa_assert(io->ofd >= 0);
327 iov.iov_base = (void*) data;
331 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(pa_ucred_t));
332 cmsg.hdr.cmsg_level = SOL_SOCKET;
333 cmsg.hdr.cmsg_type = SCM_CREDENTIALS;
335 u = (pa_ucred_t*) CMSG_DATA(&cmsg.hdr);
337 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
338 // the kernel fills everything
353 mh.msg_control = &cmsg;
354 mh.msg_controllen = sizeof(cmsg);
356 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
357 io->writable = io->hungup = false;
364 /* For more details on FD passing, check the cmsg(3) manpage
365 * and IETF RFC #2292: "Advanced Sockets API for IPv6" */
366 ssize_t pa_iochannel_write_with_fds(pa_iochannel*io, const void*data, size_t l, int nfd, const int *fds) {
373 uint8_t data[CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)];
379 pa_assert(io->ofd >= 0);
382 pa_assert(nfd <= MAX_ANCIL_DATA_FDS);
385 iov.iov_base = (void*) data;
389 cmsg.hdr.cmsg_level = SOL_SOCKET;
390 cmsg.hdr.cmsg_type = SCM_RIGHTS;
392 msgdata = (int*) CMSG_DATA(&cmsg.hdr);
393 memcpy(msgdata, fds, nfd * sizeof(int));
394 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int) * nfd);
399 mh.msg_control = &cmsg;
401 /* If we followed the example on the cmsg man page, we'd use
402 * sizeof(cmsg.data) here, but if nfd < MAX_ANCIL_DATA_FDS, then the data
403 * buffer is larger than needed, and the kernel doesn't like it if we set
404 * msg_controllen to a larger than necessary value. The commit message for
405 * commit 451d1d6762 contains a longer explanation. */
406 mh.msg_controllen = CMSG_SPACE(sizeof(int) * nfd);
408 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
409 io->writable = io->hungup = false;
415 ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l, pa_cmsg_ancil_data *ancil_data) {
421 uint8_t data[CMSG_SPACE(sizeof(pa_ucred_t)) + CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)];
427 pa_assert(io->ifd >= 0);
428 pa_assert(ancil_data);
430 if (io->ifd_type > 0) {
431 ancil_data->creds_valid = false;
433 return pa_iochannel_read(io, data, l);
442 mh.msg_control = &cmsg;
443 mh.msg_controllen = sizeof(cmsg);
445 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
448 ancil_data->creds_valid = false;
451 for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
453 if (cmh->cmsg_level != SOL_SOCKET)
456 if (cmh->cmsg_type == SCM_CREDENTIALS) {
458 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(pa_ucred_t)));
459 memcpy(&u, CMSG_DATA(cmh), sizeof(pa_ucred_t));
460 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
461 ancil_data->creds.gid = u.cmcred_gid;
462 ancil_data->creds.uid = u.cmcred_uid;
464 ancil_data->creds.gid = u.gid;
465 ancil_data->creds.uid = u.uid;
467 ancil_data->creds_valid = true;
469 else if (cmh->cmsg_type == SCM_RIGHTS) {
470 int nfd = (cmh->cmsg_len - CMSG_LEN(0)) / sizeof(int);
471 if (nfd > MAX_ANCIL_DATA_FDS) {
473 pa_log("Trying to receive too many file descriptors!");
474 for (i = 0; i < nfd; i++)
475 pa_close(((int*) CMSG_DATA(cmh))[i]);
478 memcpy(ancil_data->fds, CMSG_DATA(cmh), nfd * sizeof(int));
479 ancil_data->nfd = nfd;
480 ancil_data->close_fds_on_cleanup = true;
484 io->readable = io->hungup = false;
488 if (r == -1 && errno == ENOTSOCK) {
490 return pa_iochannel_read_with_ancil_data(io, data, l, ancil_data);
496 #endif /* HAVE_CREDS */
498 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
501 io->callback = _callback;
502 io->userdata = userdata;
505 void pa_iochannel_set_noclose(pa_iochannel*io, bool b) {
511 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
516 pa_socket_peer_to_string(io->ifd, s, l);
519 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
522 return pa_socket_set_rcvbuf(io->ifd, l);
525 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
528 return pa_socket_set_sndbuf(io->ofd, l);
531 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
537 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
543 int pa_iochannel_get_send_fd(pa_iochannel *io) {
549 bool pa_iochannel_socket_is_local(pa_iochannel *io) {
552 if (pa_socket_is_local(io->ifd))
555 if (io->ifd != io->ofd)
556 if (pa_socket_is_local(io->ofd))