4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as
11 published by the Free Software Foundation; either version 2.1 of the
12 License, or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
43 #include <pulse/xmalloc.h>
45 #include <pulsecore/core-error.h>
46 #include <pulsecore/core-util.h>
47 #include <pulsecore/socket-util.h>
48 #include <pulsecore/log.h>
49 #include <pulsecore/macro.h>
51 #include "iochannel.h"
55 int ifd_type, ofd_type;
56 pa_mainloop_api* mainloop;
58 pa_iochannel_cb_t callback;
67 pa_io_event* input_event, *output_event;
70 static void enable_mainloop_sources(pa_iochannel *io) {
73 if (io->input_event == io->output_event && io->input_event) {
74 pa_io_event_flags_t f = PA_IO_EVENT_NULL;
75 pa_assert(io->input_event);
78 f |= PA_IO_EVENT_INPUT;
80 f |= PA_IO_EVENT_OUTPUT;
82 io->mainloop->io_enable(io->input_event, f);
85 io->mainloop->io_enable(io->input_event, io->readable ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT);
87 io->mainloop->io_enable(io->output_event, io->writable ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT);
91 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
92 pa_iochannel *io = userdata;
93 pa_bool_t changed = FALSE;
100 if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
105 if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
108 pa_assert(e == io->input_event);
111 if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
114 pa_assert(e == io->output_event);
118 enable_mainloop_sources(io);
121 io->callback(io, io->userdata);
125 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
129 pa_assert(ifd >= 0 || ofd >= 0);
131 io = pa_xnew(pa_iochannel, 1);
134 io->ifd_type = io->ofd_type = 0;
139 io->readable = FALSE;
140 io->writable = FALSE;
142 io->no_close = FALSE;
144 io->input_event = io->output_event = NULL;
148 pa_make_fd_nonblock(io->ifd);
149 io->input_event = io->output_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT|PA_IO_EVENT_OUTPUT, callback, io);
153 pa_make_fd_nonblock(io->ifd);
154 io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io);
158 pa_make_fd_nonblock(io->ofd);
159 io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io);
166 void pa_iochannel_free(pa_iochannel*io) {
170 io->mainloop->io_free(io->input_event);
172 if (io->output_event && (io->output_event != io->input_event))
173 io->mainloop->io_free(io->output_event);
178 if (io->ofd >= 0 && io->ofd != io->ifd)
185 pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) {
188 return io->readable || io->hungup;
191 pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) {
194 return io->writable && !io->hungup;
197 pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) {
203 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
209 pa_assert(io->ofd >= 0);
211 if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) {
212 io->writable = FALSE;
213 enable_mainloop_sources(io);
219 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
224 pa_assert(io->ifd >= 0);
226 if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
227 io->readable = FALSE;
228 enable_mainloop_sources(io);
236 pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) {
237 struct sockaddr_un sa;
241 pa_assert(io->ifd >= 0);
242 pa_assert(io->ofd == io->ifd);
246 if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0)
249 return sa.sun_family == AF_UNIX;
252 int pa_iochannel_creds_enable(pa_iochannel *io) {
256 pa_assert(io->ifd >= 0);
258 if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
259 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
266 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
270 uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))];
272 struct cmsghdr *cmsg;
277 pa_assert(io->ofd >= 0);
279 memset(&iov, 0, sizeof(iov));
280 iov.iov_base = (void*) data;
283 memset(cmsg_data, 0, sizeof(cmsg_data));
284 cmsg = (struct cmsghdr*) cmsg_data;
285 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
286 cmsg->cmsg_level = SOL_SOCKET;
287 cmsg->cmsg_type = SCM_CREDENTIALS;
289 u = (struct ucred*) CMSG_DATA(cmsg);
300 memset(&mh, 0, sizeof(mh));
305 mh.msg_control = cmsg_data;
306 mh.msg_controllen = sizeof(cmsg_data);
309 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
310 io->writable = FALSE;
311 enable_mainloop_sources(io);
317 ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, pa_bool_t *creds_valid) {
321 uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))];
326 pa_assert(io->ifd >= 0);
328 pa_assert(creds_valid);
330 memset(&iov, 0, sizeof(iov));
334 memset(cmsg_data, 0, sizeof(cmsg_data));
336 memset(&mh, 0, sizeof(mh));
341 mh.msg_control = cmsg_data;
342 mh.msg_controllen = sizeof(cmsg_data);
345 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
346 struct cmsghdr *cmsg;
350 for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
352 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
354 pa_assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
355 memcpy(&u, CMSG_DATA(cmsg), sizeof(struct ucred));
364 io->readable = FALSE;
365 enable_mainloop_sources(io);
371 #endif /* HAVE_CREDS */
373 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
376 io->callback = _callback;
377 io->userdata = userdata;
380 void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) {
386 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
391 pa_socket_peer_to_string(io->ifd, s, l);
394 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
397 return pa_socket_set_rcvbuf(io->ifd, l);
400 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
403 return pa_socket_set_sndbuf(io->ofd, l);
406 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
412 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
418 int pa_iochannel_get_send_fd(pa_iochannel *io) {