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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
40 #include <pulse/xmalloc.h>
42 #include <pulsecore/core-error.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/socket-util.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/macro.h>
48 #include "iochannel.h"
52 int ifd_type, ofd_type;
53 pa_mainloop_api* mainloop;
55 pa_iochannel_cb_t callback;
64 pa_io_event* input_event, *output_event;
67 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata);
69 static void delete_events(pa_iochannel *io) {
73 io->mainloop->io_free(io->input_event);
75 if (io->output_event && io->output_event != io->input_event)
76 io->mainloop->io_free(io->output_event);
78 io->input_event = io->output_event = NULL;
81 static void enable_events(pa_iochannel *io) {
89 if (io->ifd == io->ofd && io->ifd >= 0) {
90 pa_io_event_flags_t f = PA_IO_EVENT_NULL;
93 f |= PA_IO_EVENT_INPUT;
95 f |= PA_IO_EVENT_OUTPUT;
97 pa_assert(io->input_event == io->output_event);
99 if (f != PA_IO_EVENT_NULL) {
101 io->mainloop->io_enable(io->input_event, f);
103 io->input_event = io->output_event = io->mainloop->io_new(io->mainloop, io->ifd, f, callback, io);
112 io->mainloop->io_enable(io->input_event, PA_IO_EVENT_INPUT);
114 io->input_event = io->mainloop->io_new(io->mainloop, io->ifd, PA_IO_EVENT_INPUT, callback, io);
115 } else if (io->input_event) {
116 io->mainloop->io_free(io->input_event);
117 io->input_event = NULL;
123 if (io->output_event)
124 io->mainloop->io_enable(io->output_event, PA_IO_EVENT_OUTPUT);
126 io->output_event = io->mainloop->io_new(io->mainloop, io->ofd, PA_IO_EVENT_OUTPUT, callback, io);
127 } else if (io->input_event) {
128 io->mainloop->io_free(io->output_event);
129 io->output_event = NULL;
135 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
136 pa_iochannel *io = userdata;
137 pa_bool_t changed = FALSE;
144 if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
149 if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
152 pa_assert(e == io->input_event);
155 if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
158 pa_assert(e == io->output_event);
165 io->callback(io, io->userdata);
169 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
173 pa_assert(ifd >= 0 || ofd >= 0);
175 io = pa_xnew0(pa_iochannel, 1);
181 pa_make_fd_nonblock(io->ifd);
183 if (io->ofd >= 0 && io->ofd != io->ifd)
184 pa_make_fd_nonblock(io->ofd);
190 void pa_iochannel_free(pa_iochannel*io) {
198 if (io->ofd >= 0 && io->ofd != io->ifd)
205 pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) {
208 return io->readable || io->hungup;
211 pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) {
214 return io->writable && !io->hungup;
217 pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) {
223 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
229 pa_assert(io->ofd >= 0);
231 if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) {
232 io->writable = io->hungup = FALSE;
239 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
244 pa_assert(io->ifd >= 0);
246 if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
248 /* We also reset the hangup flag here to ensure that another
249 * IO callback is triggered so that we will again call into
251 io->readable = io->hungup = FALSE;
260 pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) {
261 struct sockaddr_un sa;
265 pa_assert(io->ifd >= 0);
266 pa_assert(io->ofd == io->ifd);
270 if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0)
273 return sa.sun_family == AF_UNIX;
276 int pa_iochannel_creds_enable(pa_iochannel *io) {
280 pa_assert(io->ifd >= 0);
282 if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
283 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
290 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
296 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
303 pa_assert(io->ofd >= 0);
305 memset(&iov, 0, sizeof(iov));
306 iov.iov_base = (void*) data;
309 memset(&cmsg, 0, sizeof(cmsg));
310 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct ucred));
311 cmsg.hdr.cmsg_level = SOL_SOCKET;
312 cmsg.hdr.cmsg_type = SCM_CREDENTIALS;
314 u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
328 mh.msg_control = &cmsg;
329 mh.msg_controllen = sizeof(cmsg);
331 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
332 io->writable = io->hungup = FALSE;
339 ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, pa_bool_t *creds_valid) {
345 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
351 pa_assert(io->ifd >= 0);
353 pa_assert(creds_valid);
355 memset(&iov, 0, sizeof(iov));
359 memset(&cmsg, 0, sizeof(cmsg));
361 memset(&mh, 0, sizeof(mh));
366 mh.msg_control = &cmsg;
367 mh.msg_controllen = sizeof(cmsg);
370 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
375 for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
377 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) {
379 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
380 memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
389 io->readable = io->hungup = FALSE;
396 #endif /* HAVE_CREDS */
398 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
401 io->callback = _callback;
402 io->userdata = userdata;
405 void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) {
411 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
416 pa_socket_peer_to_string(io->ifd, s, l);
419 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
422 return pa_socket_set_rcvbuf(io->ifd, l);
425 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
428 return pa_socket_set_sndbuf(io->ofd, l);
431 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
437 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
443 int pa_iochannel_get_send_fd(pa_iochannel *io) {
449 pa_bool_t pa_iochannel_socket_is_local(pa_iochannel *io) {
452 if (pa_socket_is_local(io->ifd))
455 if (io->ifd != io->ofd)
456 if (pa_socket_is_local(io->ofd))