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