Revert "resamplers: Optimize trivial resampler"
[profile/ivi/pulseaudio-panda.git] / src / pulsecore / iochannel.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
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 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <errno.h>
30
31 #ifdef HAVE_SYS_UN_H
32 #include <sys/un.h>
33 #endif
34
35 #include <pulse/xmalloc.h>
36
37 #include <pulsecore/core-error.h>
38 #include <pulsecore/core-util.h>
39 #include <pulsecore/socket.h>
40 #include <pulsecore/socket-util.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/macro.h>
43
44 #include "iochannel.h"
45
46 struct pa_iochannel {
47     int ifd, ofd;
48     int ifd_type, ofd_type;
49     pa_mainloop_api* mainloop;
50
51     pa_iochannel_cb_t callback;
52     void*userdata;
53
54     pa_bool_t readable:1;
55     pa_bool_t writable:1;
56     pa_bool_t hungup:1;
57     pa_bool_t no_close:1;
58
59     pa_io_event* input_event, *output_event;
60 };
61
62 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata);
63
64 static void delete_events(pa_iochannel *io) {
65     pa_assert(io);
66
67     if (io->input_event)
68         io->mainloop->io_free(io->input_event);
69
70     if (io->output_event && io->output_event != io->input_event)
71         io->mainloop->io_free(io->output_event);
72
73     io->input_event = io->output_event = NULL;
74 }
75
76 static void enable_events(pa_iochannel *io) {
77     pa_assert(io);
78
79     if (io->hungup) {
80         delete_events(io);
81         return;
82     }
83
84     if (io->ifd == io->ofd && io->ifd >= 0) {
85         pa_io_event_flags_t f = PA_IO_EVENT_NULL;
86
87         if (!io->readable)
88             f |= PA_IO_EVENT_INPUT;
89         if (!io->writable)
90             f |= PA_IO_EVENT_OUTPUT;
91
92         pa_assert(io->input_event == io->output_event);
93
94         if (f != PA_IO_EVENT_NULL) {
95             if (io->input_event)
96                 io->mainloop->io_enable(io->input_event, f);
97             else
98                 io->input_event = io->output_event = io->mainloop->io_new(io->mainloop, io->ifd, f, callback, io);
99         } else
100             delete_events(io);
101
102     } else {
103
104         if (io->ifd >= 0) {
105             if (!io->readable) {
106                 if (io->input_event)
107                     io->mainloop->io_enable(io->input_event, PA_IO_EVENT_INPUT);
108                 else
109                     io->input_event = io->mainloop->io_new(io->mainloop, io->ifd, PA_IO_EVENT_INPUT, callback, io);
110             } else if (io->input_event) {
111                 io->mainloop->io_free(io->input_event);
112                 io->input_event = NULL;
113             }
114         }
115
116         if (io->ofd >= 0) {
117             if (!io->writable) {
118                 if (io->output_event)
119                     io->mainloop->io_enable(io->output_event, PA_IO_EVENT_OUTPUT);
120                 else
121                     io->output_event = io->mainloop->io_new(io->mainloop, io->ofd, PA_IO_EVENT_OUTPUT, callback, io);
122             } else if (io->input_event) {
123                 io->mainloop->io_free(io->output_event);
124                 io->output_event = NULL;
125             }
126         }
127     }
128 }
129
130 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
131     pa_iochannel *io = userdata;
132     pa_bool_t changed = FALSE;
133
134     pa_assert(m);
135     pa_assert(e);
136     pa_assert(fd >= 0);
137     pa_assert(userdata);
138
139     if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
140         io->hungup = TRUE;
141         changed = TRUE;
142     }
143
144     if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
145         io->readable = TRUE;
146         changed = TRUE;
147         pa_assert(e == io->input_event);
148     }
149
150     if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
151         io->writable = TRUE;
152         changed = TRUE;
153         pa_assert(e == io->output_event);
154     }
155
156     if (changed) {
157         enable_events(io);
158
159         if (io->callback)
160             io->callback(io, io->userdata);
161     }
162 }
163
164 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
165     pa_iochannel *io;
166
167     pa_assert(m);
168     pa_assert(ifd >= 0 || ofd >= 0);
169
170     io = pa_xnew0(pa_iochannel, 1);
171     io->ifd = ifd;
172     io->ofd = ofd;
173     io->mainloop = m;
174
175     if (io->ifd >= 0)
176         pa_make_fd_nonblock(io->ifd);
177
178     if (io->ofd >= 0 && io->ofd != io->ifd)
179         pa_make_fd_nonblock(io->ofd);
180
181     enable_events(io);
182     return io;
183 }
184
185 void pa_iochannel_free(pa_iochannel*io) {
186     pa_assert(io);
187
188     delete_events(io);
189
190     if (!io->no_close) {
191         if (io->ifd >= 0)
192             pa_close(io->ifd);
193         if (io->ofd >= 0 && io->ofd != io->ifd)
194             pa_close(io->ofd);
195     }
196
197     pa_xfree(io);
198 }
199
200 pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) {
201     pa_assert(io);
202
203     return io->readable || io->hungup;
204 }
205
206 pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) {
207     pa_assert(io);
208
209     return io->writable && !io->hungup;
210 }
211
212 pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) {
213     pa_assert(io);
214
215     return io->hungup;
216 }
217
218 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
219     ssize_t r;
220
221     pa_assert(io);
222     pa_assert(data);
223     pa_assert(l);
224     pa_assert(io->ofd >= 0);
225
226     if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) {
227         io->writable = io->hungup = FALSE;
228         enable_events(io);
229     }
230
231     return r;
232 }
233
234 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
235     ssize_t r;
236
237     pa_assert(io);
238     pa_assert(data);
239     pa_assert(io->ifd >= 0);
240
241     if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
242
243         /* We also reset the hangup flag here to ensure that another
244          * IO callback is triggered so that we will again call into
245          * user code */
246         io->readable = io->hungup = FALSE;
247         enable_events(io);
248     }
249
250     return r;
251 }
252
253 #ifdef HAVE_CREDS
254
255 pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) {
256     struct {
257         struct sockaddr sa;
258 #ifdef HAVE_SYS_UN_H
259         struct sockaddr_un un;
260 #endif
261         struct sockaddr_storage storage;
262     } sa;
263
264     socklen_t l;
265
266     pa_assert(io);
267     pa_assert(io->ifd >= 0);
268     pa_assert(io->ofd == io->ifd);
269
270     l = sizeof(sa);
271     if (getsockname(io->ifd, &sa.sa, &l) < 0)
272         return FALSE;
273
274     return sa.sa.sa_family == AF_UNIX;
275 }
276
277 int pa_iochannel_creds_enable(pa_iochannel *io) {
278     int t = 1;
279
280     pa_assert(io);
281     pa_assert(io->ifd >= 0);
282
283     if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
284         pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
285         return -1;
286     }
287
288     return 0;
289 }
290
291 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
292     ssize_t r;
293     struct msghdr mh;
294     struct iovec iov;
295     union {
296         struct cmsghdr hdr;
297         uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
298     } cmsg;
299     struct ucred *u;
300
301     pa_assert(io);
302     pa_assert(data);
303     pa_assert(l);
304     pa_assert(io->ofd >= 0);
305
306     pa_zero(iov);
307     iov.iov_base = (void*) data;
308     iov.iov_len = l;
309
310     pa_zero(cmsg);
311     cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct ucred));
312     cmsg.hdr.cmsg_level = SOL_SOCKET;
313     cmsg.hdr.cmsg_type = SCM_CREDENTIALS;
314
315     u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
316
317     u->pid = getpid();
318     if (ucred) {
319         u->uid = ucred->uid;
320         u->gid = ucred->gid;
321     } else {
322         u->uid = getuid();
323         u->gid = getgid();
324     }
325
326     pa_zero(mh);
327     mh.msg_iov = &iov;
328     mh.msg_iovlen = 1;
329     mh.msg_control = &cmsg;
330     mh.msg_controllen = sizeof(cmsg);
331
332     if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
333         io->writable = io->hungup = FALSE;
334         enable_events(io);
335     }
336
337     return r;
338 }
339
340 ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, pa_bool_t *creds_valid) {
341     ssize_t r;
342     struct msghdr mh;
343     struct iovec iov;
344     union {
345         struct cmsghdr hdr;
346         uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
347     } cmsg;
348
349     pa_assert(io);
350     pa_assert(data);
351     pa_assert(l);
352     pa_assert(io->ifd >= 0);
353     pa_assert(creds);
354     pa_assert(creds_valid);
355
356     pa_zero(iov);
357     iov.iov_base = data;
358     iov.iov_len = l;
359
360     pa_zero(cmsg);
361     pa_zero(mh);
362     mh.msg_iov = &iov;
363     mh.msg_iovlen = 1;
364     mh.msg_control = &cmsg;
365     mh.msg_controllen = sizeof(cmsg);
366
367     if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
368         struct cmsghdr *cmh;
369
370         *creds_valid = FALSE;
371
372         for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
373
374             if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) {
375                 struct ucred u;
376                 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
377                 memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
378
379                 creds->gid = u.gid;
380                 creds->uid = u.uid;
381                 *creds_valid = TRUE;
382                 break;
383             }
384         }
385
386         io->readable = io->hungup = FALSE;
387         enable_events(io);
388     }
389
390     return r;
391 }
392
393 #endif /* HAVE_CREDS */
394
395 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
396     pa_assert(io);
397
398     io->callback = _callback;
399     io->userdata = userdata;
400 }
401
402 void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) {
403     pa_assert(io);
404
405     io->no_close = !!b;
406 }
407
408 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
409     pa_assert(io);
410     pa_assert(s);
411     pa_assert(l);
412
413     pa_socket_peer_to_string(io->ifd, s, l);
414 }
415
416 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
417     pa_assert(io);
418
419     return pa_socket_set_rcvbuf(io->ifd, l);
420 }
421
422 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
423     pa_assert(io);
424
425     return pa_socket_set_sndbuf(io->ofd, l);
426 }
427
428 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
429     pa_assert(io);
430
431     return io->mainloop;
432 }
433
434 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
435     pa_assert(io);
436
437     return io->ifd;
438 }
439
440 int pa_iochannel_get_send_fd(pa_iochannel *io) {
441     pa_assert(io);
442
443     return io->ofd;
444 }
445
446 pa_bool_t pa_iochannel_socket_is_local(pa_iochannel *io) {
447     pa_assert(io);
448
449     if (pa_socket_is_local(io->ifd))
450         return TRUE;
451
452     if (io->ifd != io->ofd)
453         if (pa_socket_is_local(io->ofd))
454             return TRUE;
455
456     return FALSE;
457 }