virtual-sink: Fix a crash when moving the sink to a new master right after setup.
[pulseaudio-raopUDP/pulseaudio-raop-alac.git] / src / pulsecore / iochannel.c
blobf89b06703b5417ae86ff41db57ca8816310e2367
1 /***
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
20 USA.
21 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <errno.h>
32 #ifdef HAVE_SYS_UN_H
33 #include <sys/un.h>
34 #endif
36 #include <pulse/xmalloc.h>
38 #include <pulsecore/core-error.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/socket.h>
41 #include <pulsecore/socket-util.h>
42 #include <pulsecore/log.h>
43 #include <pulsecore/macro.h>
45 #include "iochannel.h"
47 struct pa_iochannel {
48 int ifd, ofd;
49 int ifd_type, ofd_type;
50 pa_mainloop_api* mainloop;
52 pa_iochannel_cb_t callback;
53 void*userdata;
55 pa_bool_t readable:1;
56 pa_bool_t writable:1;
57 pa_bool_t hungup:1;
58 pa_bool_t no_close:1;
60 pa_io_event* input_event, *output_event;
63 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata);
65 static void delete_events(pa_iochannel *io) {
66 pa_assert(io);
68 if (io->input_event)
69 io->mainloop->io_free(io->input_event);
71 if (io->output_event && io->output_event != io->input_event)
72 io->mainloop->io_free(io->output_event);
74 io->input_event = io->output_event = NULL;
77 static void enable_events(pa_iochannel *io) {
78 pa_assert(io);
80 if (io->hungup) {
81 delete_events(io);
82 return;
85 if (io->ifd == io->ofd && io->ifd >= 0) {
86 pa_io_event_flags_t f = PA_IO_EVENT_NULL;
88 if (!io->readable)
89 f |= PA_IO_EVENT_INPUT;
90 if (!io->writable)
91 f |= PA_IO_EVENT_OUTPUT;
93 pa_assert(io->input_event == io->output_event);
95 if (f != PA_IO_EVENT_NULL) {
96 if (io->input_event)
97 io->mainloop->io_enable(io->input_event, f);
98 else
99 io->input_event = io->output_event = io->mainloop->io_new(io->mainloop, io->ifd, f, callback, io);
100 } else
101 delete_events(io);
103 } else {
105 if (io->ifd >= 0) {
106 if (!io->readable) {
107 if (io->input_event)
108 io->mainloop->io_enable(io->input_event, PA_IO_EVENT_INPUT);
109 else
110 io->input_event = io->mainloop->io_new(io->mainloop, io->ifd, PA_IO_EVENT_INPUT, callback, io);
111 } else if (io->input_event) {
112 io->mainloop->io_free(io->input_event);
113 io->input_event = NULL;
117 if (io->ofd >= 0) {
118 if (!io->writable) {
119 if (io->output_event)
120 io->mainloop->io_enable(io->output_event, PA_IO_EVENT_OUTPUT);
121 else
122 io->output_event = io->mainloop->io_new(io->mainloop, io->ofd, PA_IO_EVENT_OUTPUT, callback, io);
123 } else if (io->input_event) {
124 io->mainloop->io_free(io->output_event);
125 io->output_event = NULL;
131 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
132 pa_iochannel *io = userdata;
133 pa_bool_t changed = FALSE;
135 pa_assert(m);
136 pa_assert(e);
137 pa_assert(fd >= 0);
138 pa_assert(userdata);
140 if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
141 io->hungup = TRUE;
142 changed = TRUE;
145 if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
146 io->readable = TRUE;
147 changed = TRUE;
148 pa_assert(e == io->input_event);
151 if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
152 io->writable = TRUE;
153 changed = TRUE;
154 pa_assert(e == io->output_event);
157 if (changed) {
158 enable_events(io);
160 if (io->callback)
161 io->callback(io, io->userdata);
165 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
166 pa_iochannel *io;
168 pa_assert(m);
169 pa_assert(ifd >= 0 || ofd >= 0);
171 io = pa_xnew0(pa_iochannel, 1);
172 io->ifd = ifd;
173 io->ofd = ofd;
174 io->mainloop = m;
176 if (io->ifd >= 0)
177 pa_make_fd_nonblock(io->ifd);
179 if (io->ofd >= 0 && io->ofd != io->ifd)
180 pa_make_fd_nonblock(io->ofd);
182 enable_events(io);
183 return io;
186 void pa_iochannel_free(pa_iochannel*io) {
187 pa_assert(io);
189 delete_events(io);
191 if (!io->no_close) {
192 if (io->ifd >= 0)
193 pa_close(io->ifd);
194 if (io->ofd >= 0 && io->ofd != io->ifd)
195 pa_close(io->ofd);
198 pa_xfree(io);
201 pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) {
202 pa_assert(io);
204 return io->readable || io->hungup;
207 pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) {
208 pa_assert(io);
210 return io->writable && !io->hungup;
213 pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) {
214 pa_assert(io);
216 return io->hungup;
219 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
220 ssize_t r;
222 pa_assert(io);
223 pa_assert(data);
224 pa_assert(l);
225 pa_assert(io->ofd >= 0);
227 if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) {
228 io->writable = io->hungup = FALSE;
229 enable_events(io);
232 return r;
235 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
236 ssize_t r;
238 pa_assert(io);
239 pa_assert(data);
240 pa_assert(io->ifd >= 0);
242 if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
244 /* We also reset the hangup flag here to ensure that another
245 * IO callback is triggered so that we will again call into
246 * user code */
247 io->readable = io->hungup = FALSE;
248 enable_events(io);
251 return r;
254 #ifdef HAVE_CREDS
256 pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) {
257 struct {
258 struct sockaddr sa;
259 struct sockaddr_un un;
260 struct sockaddr_storage storage;
261 } sa;
263 socklen_t l;
265 pa_assert(io);
266 pa_assert(io->ifd >= 0);
267 pa_assert(io->ofd == io->ifd);
269 l = sizeof(sa);
270 if (getsockname(io->ifd, &sa.sa, &l) < 0)
271 return FALSE;
273 return sa.sa.sa_family == AF_UNIX;
276 int pa_iochannel_creds_enable(pa_iochannel *io) {
277 int t = 1;
279 pa_assert(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));
284 return -1;
287 return 0;
290 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
291 ssize_t r;
292 struct msghdr mh;
293 struct iovec iov;
294 union {
295 struct cmsghdr hdr;
296 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
297 } cmsg;
298 struct ucred *u;
300 pa_assert(io);
301 pa_assert(data);
302 pa_assert(l);
303 pa_assert(io->ofd >= 0);
305 pa_zero(iov);
306 iov.iov_base = (void*) data;
307 iov.iov_len = l;
309 pa_zero(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);
316 u->pid = getpid();
317 if (ucred) {
318 u->uid = ucred->uid;
319 u->gid = ucred->gid;
320 } else {
321 u->uid = getuid();
322 u->gid = getgid();
325 pa_zero(mh);
326 mh.msg_iov = &iov;
327 mh.msg_iovlen = 1;
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;
333 enable_events(io);
336 return r;
339 ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, pa_bool_t *creds_valid) {
340 ssize_t r;
341 struct msghdr mh;
342 struct iovec iov;
343 union {
344 struct cmsghdr hdr;
345 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
346 } cmsg;
348 pa_assert(io);
349 pa_assert(data);
350 pa_assert(l);
351 pa_assert(io->ifd >= 0);
352 pa_assert(creds);
353 pa_assert(creds_valid);
355 pa_zero(iov);
356 iov.iov_base = data;
357 iov.iov_len = l;
359 pa_zero(cmsg);
360 pa_zero(mh);
361 mh.msg_iov = &iov;
362 mh.msg_iovlen = 1;
363 mh.msg_control = &cmsg;
364 mh.msg_controllen = sizeof(cmsg);
366 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
367 struct cmsghdr *cmh;
369 *creds_valid = FALSE;
371 for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
373 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) {
374 struct ucred u;
375 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
376 memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
378 creds->gid = u.gid;
379 creds->uid = u.uid;
380 *creds_valid = TRUE;
381 break;
385 io->readable = io->hungup = FALSE;
386 enable_events(io);
389 return r;
392 #endif /* HAVE_CREDS */
394 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
395 pa_assert(io);
397 io->callback = _callback;
398 io->userdata = userdata;
401 void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) {
402 pa_assert(io);
404 io->no_close = !!b;
407 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
408 pa_assert(io);
409 pa_assert(s);
410 pa_assert(l);
412 pa_socket_peer_to_string(io->ifd, s, l);
415 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
416 pa_assert(io);
418 return pa_socket_set_rcvbuf(io->ifd, l);
421 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
422 pa_assert(io);
424 return pa_socket_set_sndbuf(io->ofd, l);
427 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
428 pa_assert(io);
430 return io->mainloop;
433 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
434 pa_assert(io);
436 return io->ifd;
439 int pa_iochannel_get_send_fd(pa_iochannel *io) {
440 pa_assert(io);
442 return io->ofd;
445 pa_bool_t pa_iochannel_socket_is_local(pa_iochannel *io) {
446 pa_assert(io);
448 if (pa_socket_is_local(io->ifd))
449 return TRUE;
451 if (io->ifd != io->ofd)
452 if (pa_socket_is_local(io->ofd))
453 return TRUE;
455 return FALSE;