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