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;
63 pa_io_event* input_event, *output_event;
66 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata);
68 static void delete_events(pa_iochannel *io) {
72 io->mainloop->io_free(io->input_event);
74 if (io->output_event && io->output_event != io->input_event)
75 io->mainloop->io_free(io->output_event);
77 io->input_event = io->output_event = NULL;
80 static void enable_events(pa_iochannel *io) {
88 if (io->ifd == io->ofd && io->ifd >= 0) {
89 pa_io_event_flags_t f = PA_IO_EVENT_NULL;
92 f |= PA_IO_EVENT_INPUT;
94 f |= PA_IO_EVENT_OUTPUT;
96 pa_assert(io->input_event == io->output_event);
98 if (f != PA_IO_EVENT_NULL) {
100 io->mainloop->io_enable(io->input_event, f);
102 io->input_event = io->output_event = io->mainloop->io_new(io->mainloop, io->ifd, f, callback, io);
111 io->mainloop->io_enable(io->input_event, PA_IO_EVENT_INPUT);
113 io->input_event = io->mainloop->io_new(io->mainloop, io->ifd, PA_IO_EVENT_INPUT, callback, io);
114 } else if (io->input_event) {
115 io->mainloop->io_free(io->input_event);
116 io->input_event = NULL;
122 if (io->output_event)
123 io->mainloop->io_enable(io->output_event, PA_IO_EVENT_OUTPUT);
125 io->output_event = io->mainloop->io_new(io->mainloop, io->ofd, PA_IO_EVENT_OUTPUT, callback, io);
126 } else if (io->input_event) {
127 io->mainloop->io_free(io->output_event);
128 io->output_event = NULL;
134 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
135 pa_iochannel *io = userdata;
136 pa_bool_t changed = FALSE;
143 if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
148 if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
151 pa_assert(e == io->input_event);
154 if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
157 pa_assert(e == io->output_event);
164 io->callback(io, io->userdata);
168 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
172 pa_assert(ifd >= 0 || ofd >= 0);
174 io = pa_xnew0(pa_iochannel, 1);
180 pa_make_fd_nonblock(io->ifd);
182 if (io->ofd >= 0 && io->ofd != io->ifd)
183 pa_make_fd_nonblock(io->ofd);
189 void pa_iochannel_free(pa_iochannel*io) {
197 if (io->ofd >= 0 && io->ofd != io->ifd)
204 pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) {
207 return io->readable || io->hungup;
210 pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) {
213 return io->writable && !io->hungup;
216 pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) {
222 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
228 pa_assert(io->ofd >= 0);
230 if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) {
231 io->writable = io->hungup = FALSE;
238 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
243 pa_assert(io->ifd >= 0);
245 if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
247 /* We also reset the hangup flag here to ensure that another
248 * IO callback is triggered so that we will again call into
250 io->readable = io->hungup = FALSE;
259 pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) {
262 struct sockaddr_un un;
263 struct sockaddr_storage storage;
269 pa_assert(io->ifd >= 0);
270 pa_assert(io->ofd == io->ifd);
273 if (getsockname(io->ifd, &sa.sa, &l) < 0)
276 return sa.sa.sa_family == AF_UNIX;
279 int pa_iochannel_creds_enable(pa_iochannel *io) {
283 pa_assert(io->ifd >= 0);
285 if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
286 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
293 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
299 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
306 pa_assert(io->ofd >= 0);
309 iov.iov_base = (void*) data;
313 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct ucred));
314 cmsg.hdr.cmsg_level = SOL_SOCKET;
315 cmsg.hdr.cmsg_type = SCM_CREDENTIALS;
317 u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
331 mh.msg_control = &cmsg;
332 mh.msg_controllen = sizeof(cmsg);
334 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
335 io->writable = io->hungup = FALSE;
342 ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, pa_bool_t *creds_valid) {
348 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
354 pa_assert(io->ifd >= 0);
356 pa_assert(creds_valid);
366 mh.msg_control = &cmsg;
367 mh.msg_controllen = sizeof(cmsg);
369 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
372 *creds_valid = FALSE;
374 for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
376 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) {
378 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
379 memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
388 io->readable = io->hungup = FALSE;
395 #endif /* HAVE_CREDS */
397 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
400 io->callback = _callback;
401 io->userdata = userdata;
404 void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) {
410 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
415 pa_socket_peer_to_string(io->ifd, s, l);
418 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
421 return pa_socket_set_rcvbuf(io->ifd, l);
424 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
427 return pa_socket_set_sndbuf(io->ofd, l);
430 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
436 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
442 int pa_iochannel_get_send_fd(pa_iochannel *io) {
448 pa_bool_t pa_iochannel_socket_is_local(pa_iochannel *io) {
451 if (pa_socket_is_local(io->ifd))
454 if (io->ifd != io->ofd)
455 if (pa_socket_is_local(io->ofd))