483300795941661ecd1d1f19587e65a85fe9cfab
[profile/ivi/pulseaudio.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 <fcntl.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_SYS_UN_H
35 #include <sys/un.h>
36 #endif
37
38 #include "winsock.h"
39
40 #include <pulse/xmalloc.h>
41
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>
47
48 #include "iochannel.h"
49
50 struct pa_iochannel {
51     int ifd, ofd;
52     int ifd_type, ofd_type;
53     pa_mainloop_api* mainloop;
54
55     pa_iochannel_cb_t callback;
56     void*userdata;
57
58     pa_bool_t readable;
59     pa_bool_t writable;
60     pa_bool_t hungup;
61
62     pa_bool_t no_close;
63
64     pa_io_event* input_event, *output_event;
65 };
66
67 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata);
68
69 static void delete_events(pa_iochannel *io) {
70     pa_assert(io);
71
72     if (io->input_event)
73         io->mainloop->io_free(io->input_event);
74
75     if (io->output_event && io->output_event != io->input_event)
76         io->mainloop->io_free(io->output_event);
77
78     io->input_event = io->output_event = NULL;
79 }
80
81 static void enable_events(pa_iochannel *io) {
82     pa_assert(io);
83
84     if (io->hungup) {
85         delete_events(io);
86         return;
87     }
88
89     if (io->ifd == io->ofd && io->ifd >= 0) {
90         pa_io_event_flags_t f = PA_IO_EVENT_NULL;
91
92         if (!io->readable)
93             f |= PA_IO_EVENT_INPUT;
94         if (!io->writable)
95             f |= PA_IO_EVENT_OUTPUT;
96
97         pa_assert(io->input_event == io->output_event);
98
99         if (f != PA_IO_EVENT_NULL) {
100             if (io->input_event)
101                 io->mainloop->io_enable(io->input_event, f);
102             else
103                 io->input_event = io->output_event = io->mainloop->io_new(io->mainloop, io->ifd, f, callback, io);
104         } else
105             delete_events(io);
106
107     } else {
108
109         if (io->ifd >= 0) {
110             if (!io->readable) {
111                 if (io->input_event)
112                     io->mainloop->io_enable(io->input_event, PA_IO_EVENT_INPUT);
113                 else
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;
118             }
119         }
120
121         if (io->ofd >= 0) {
122             if (!io->writable) {
123                 if (io->output_event)
124                     io->mainloop->io_enable(io->output_event, PA_IO_EVENT_OUTPUT);
125                 else
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;
130             }
131         }
132     }
133 }
134
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;
138
139     pa_assert(m);
140     pa_assert(e);
141     pa_assert(fd >= 0);
142     pa_assert(userdata);
143
144     if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
145         io->hungup = TRUE;
146         changed = TRUE;
147     }
148
149     if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
150         io->readable = TRUE;
151         changed = TRUE;
152         pa_assert(e == io->input_event);
153     }
154
155     if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
156         io->writable = TRUE;
157         changed = TRUE;
158         pa_assert(e == io->output_event);
159     }
160
161     if (changed) {
162         enable_events(io);
163
164         if (io->callback)
165             io->callback(io, io->userdata);
166     }
167 }
168
169 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
170     pa_iochannel *io;
171
172     pa_assert(m);
173     pa_assert(ifd >= 0 || ofd >= 0);
174
175     io = pa_xnew0(pa_iochannel, 1);
176     io->ifd = ifd;
177     io->ofd = ofd;
178     io->mainloop = m;
179
180     if (io->ifd >= 0)
181         pa_make_fd_nonblock(io->ifd);
182
183     if (io->ofd >= 0 && io->ofd != io->ifd)
184         pa_make_fd_nonblock(io->ofd);
185
186     enable_events(io);
187     return io;
188 }
189
190 void pa_iochannel_free(pa_iochannel*io) {
191     pa_assert(io);
192
193     delete_events(io);
194
195     if (!io->no_close) {
196         if (io->ifd >= 0)
197             pa_close(io->ifd);
198         if (io->ofd >= 0 && io->ofd != io->ifd)
199             pa_close(io->ofd);
200     }
201
202     pa_xfree(io);
203 }
204
205 pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) {
206     pa_assert(io);
207
208     return io->readable || io->hungup;
209 }
210
211 pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) {
212     pa_assert(io);
213
214     return io->writable && !io->hungup;
215 }
216
217 pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) {
218     pa_assert(io);
219
220     return io->hungup;
221 }
222
223 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
224     ssize_t r;
225
226     pa_assert(io);
227     pa_assert(data);
228     pa_assert(l);
229     pa_assert(io->ofd >= 0);
230
231     if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) {
232         io->writable = io->hungup = FALSE;
233         enable_events(io);
234     }
235
236     return r;
237 }
238
239 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
240     ssize_t r;
241
242     pa_assert(io);
243     pa_assert(data);
244     pa_assert(io->ifd >= 0);
245
246     if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
247
248         /* We also reset the hangup flag here to ensure that another
249          * IO callback is triggered so that we will again call into
250          * user code */
251         io->readable = io->hungup = FALSE;
252         enable_events(io);
253     }
254
255     return r;
256 }
257
258 #ifdef HAVE_CREDS
259
260 pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) {
261     struct sockaddr_un sa;
262     socklen_t l;
263
264     pa_assert(io);
265     pa_assert(io->ifd >= 0);
266     pa_assert(io->ofd == io->ifd);
267
268     l = sizeof(sa);
269
270     if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0)
271         return 0;
272
273     return sa.sun_family == AF_UNIX;
274 }
275
276 int pa_iochannel_creds_enable(pa_iochannel *io) {
277     int t = 1;
278
279     pa_assert(io);
280     pa_assert(io->ifd >= 0);
281
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;
285     }
286
287     return 0;
288 }
289
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;
299
300     pa_assert(io);
301     pa_assert(data);
302     pa_assert(l);
303     pa_assert(io->ofd >= 0);
304
305     memset(&iov, 0, sizeof(iov));
306     iov.iov_base = (void*) data;
307     iov.iov_len = l;
308
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;
313
314     u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
315
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();
323     }
324
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);
330
331     if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
332         io->writable = io->hungup = FALSE;
333         enable_events(io);
334     }
335
336     return r;
337 }
338
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;
347
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);
354
355     memset(&iov, 0, sizeof(iov));
356     iov.iov_base = data;
357     iov.iov_len = l;
358
359     memset(&cmsg, 0, sizeof(cmsg));
360
361     memset(&mh, 0, sizeof(mh));
362     mh.msg_name = NULL;
363     mh.msg_namelen = 0;
364     mh.msg_iov = &iov;
365     mh.msg_iovlen = 1;
366     mh.msg_control = &cmsg;
367     mh.msg_controllen = sizeof(cmsg);
368     mh.msg_flags = 0;
369
370     if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
371         struct cmsghdr *cmh;
372
373         *creds_valid = 0;
374
375         for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
376
377             if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) {
378                 struct ucred u;
379                 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
380                 memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
381
382                 creds->gid = u.gid;
383                 creds->uid = u.uid;
384                 *creds_valid = TRUE;
385                 break;
386             }
387         }
388
389         io->readable = io->hungup = FALSE;
390         enable_events(io);
391     }
392
393     return r;
394 }
395
396 #endif /* HAVE_CREDS */
397
398 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
399     pa_assert(io);
400
401     io->callback = _callback;
402     io->userdata = userdata;
403 }
404
405 void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) {
406     pa_assert(io);
407
408     io->no_close = !!b;
409 }
410
411 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
412     pa_assert(io);
413     pa_assert(s);
414     pa_assert(l);
415
416     pa_socket_peer_to_string(io->ifd, s, l);
417 }
418
419 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
420     pa_assert(io);
421
422     return pa_socket_set_rcvbuf(io->ifd, l);
423 }
424
425 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
426     pa_assert(io);
427
428     return pa_socket_set_sndbuf(io->ofd, l);
429 }
430
431 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
432     pa_assert(io);
433
434     return io->mainloop;
435 }
436
437 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
438     pa_assert(io);
439
440     return io->ifd;
441 }
442
443 int pa_iochannel_get_send_fd(pa_iochannel *io) {
444     pa_assert(io);
445
446     return io->ofd;
447 }
448
449 pa_bool_t pa_iochannel_socket_is_local(pa_iochannel *io) {
450     pa_assert(io);
451
452     if (pa_socket_is_local(io->ifd))
453         return TRUE;
454
455     if (io->ifd != io->ofd)
456         if (pa_socket_is_local(io->ofd))
457             return TRUE;
458
459     return FALSE;
460 }