make O_CLOEXEC, O_NONBLOCK and socket low latency fd ops more uniform: always return...
[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-2007 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 <fcntl.h>
31 #include <unistd.h>
32 #include <errno.h>
33
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 #ifdef HAVE_SYS_UN_H
38 #include <sys/un.h>
39 #endif
40
41 #include "winsock.h"
42
43 #include <pulse/xmalloc.h>
44
45 #include <pulsecore/core-error.h>
46 #include <pulsecore/core-util.h>
47 #include <pulsecore/socket-util.h>
48 #include <pulsecore/log.h>
49 #include <pulsecore/macro.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     pa_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         pa_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     pa_assert(m);
96     pa_assert(e);
97     pa_assert(fd >= 0);
98     pa_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         pa_assert(e == io->input_event);
109     }
110
111     if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
112         io->writable = 1;
113         changed = 1;
114         pa_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     pa_assert(m);
129     pa_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         pa_assert(ifd >= 0);
148         pa_make_fd_nonblock(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_fd_nonblock(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_fd_nonblock(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     pa_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             pa_close(io->ifd);
178         if (io->ofd >= 0 && io->ofd != io->ifd)
179             pa_close(io->ofd);
180     }
181
182     pa_xfree(io);
183 }
184
185 int pa_iochannel_is_readable(pa_iochannel*io) {
186     pa_assert(io);
187
188     return io->readable || io->hungup;
189 }
190
191 int pa_iochannel_is_writable(pa_iochannel*io) {
192     pa_assert(io);
193
194     return io->writable && !io->hungup;
195 }
196
197 int pa_iochannel_is_hungup(pa_iochannel*io) {
198     pa_assert(io);
199
200     return io->hungup;
201 }
202
203 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
204     ssize_t r;
205
206     pa_assert(io);
207     pa_assert(data);
208     pa_assert(l);
209     pa_assert(io->ofd >= 0);
210
211     r = pa_write(io->ofd, data, l, &io->ofd_type);
212     if (r >= 0) {
213         io->writable = 0;
214         enable_mainloop_sources(io);
215     }
216
217     return r;
218 }
219
220 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
221     ssize_t r;
222
223     pa_assert(io);
224     pa_assert(data);
225     pa_assert(io->ifd >= 0);
226
227     r = pa_read(io->ifd, data, l, &io->ifd_type);
228     if (r >= 0) {
229         io->readable = 0;
230         enable_mainloop_sources(io);
231     }
232
233     return r;
234 }
235
236 #ifdef HAVE_CREDS
237
238 int pa_iochannel_creds_supported(pa_iochannel *io) {
239     struct sockaddr_un sa;
240     socklen_t l;
241
242     pa_assert(io);
243     pa_assert(io->ifd >= 0);
244     pa_assert(io->ofd == io->ifd);
245
246     l = sizeof(sa);
247
248     if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0)
249         return 0;
250
251     return sa.sun_family == AF_UNIX;
252 }
253
254 int pa_iochannel_creds_enable(pa_iochannel *io) {
255     int t = 1;
256
257     pa_assert(io);
258     pa_assert(io->ifd >= 0);
259
260     if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
261         pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
262         return -1;
263     }
264
265     return 0;
266 }
267
268 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
269     ssize_t r;
270     struct msghdr mh;
271     struct iovec iov;
272     uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))];
273     struct ucred *u;
274     struct cmsghdr *cmsg;
275
276     pa_assert(io);
277     pa_assert(data);
278     pa_assert(l);
279     pa_assert(io->ofd >= 0);
280
281     memset(&iov, 0, sizeof(iov));
282     iov.iov_base = (void*) data;
283     iov.iov_len = l;
284
285     memset(cmsg_data, 0, sizeof(cmsg_data));
286     cmsg = (struct cmsghdr*)  cmsg_data;
287     cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
288     cmsg->cmsg_level = SOL_SOCKET;
289     cmsg->cmsg_type = SCM_CREDENTIALS;
290
291     u = (struct ucred*) CMSG_DATA(cmsg);
292
293     u->pid = getpid();
294     if (ucred) {
295         u->uid = ucred->uid;
296         u->gid = ucred->gid;
297     } else {
298         u->uid = getuid();
299         u->gid = getgid();
300     }
301
302     memset(&mh, 0, sizeof(mh));
303     mh.msg_name = NULL;
304     mh.msg_namelen = 0;
305     mh.msg_iov = &iov;
306     mh.msg_iovlen = 1;
307     mh.msg_control = cmsg_data;
308     mh.msg_controllen = sizeof(cmsg_data);
309     mh.msg_flags = 0;
310
311     if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
312         io->writable = 0;
313         enable_mainloop_sources(io);
314     }
315
316     return r;
317 }
318
319 ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, int *creds_valid) {
320     ssize_t r;
321     struct msghdr mh;
322     struct iovec iov;
323     uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))];
324
325     pa_assert(io);
326     pa_assert(data);
327     pa_assert(l);
328     pa_assert(io->ifd >= 0);
329     pa_assert(creds);
330     pa_assert(creds_valid);
331
332     memset(&iov, 0, sizeof(iov));
333     iov.iov_base = data;
334     iov.iov_len = l;
335
336     memset(cmsg_data, 0, sizeof(cmsg_data));
337
338     memset(&mh, 0, sizeof(mh));
339     mh.msg_name = NULL;
340     mh.msg_namelen = 0;
341     mh.msg_iov = &iov;
342     mh.msg_iovlen = 1;
343     mh.msg_control = cmsg_data;
344     mh.msg_controllen = sizeof(cmsg_data);
345     mh.msg_flags = 0;
346
347     if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
348         struct cmsghdr *cmsg;
349
350         *creds_valid = 0;
351
352         for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
353
354             if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
355                 struct ucred u;
356                 pa_assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
357                 memcpy(&u, CMSG_DATA(cmsg), sizeof(struct ucred));
358
359                 creds->gid = u.gid;
360                 creds->uid = u.uid;
361                 *creds_valid = 1;
362                 break;
363             }
364         }
365
366         io->readable = 0;
367         enable_mainloop_sources(io);
368     }
369
370     return r;
371 }
372
373 #endif /* HAVE_CREDS */
374
375 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
376     pa_assert(io);
377
378     io->callback = _callback;
379     io->userdata = userdata;
380 }
381
382 void pa_iochannel_set_noclose(pa_iochannel*io, int b) {
383     pa_assert(io);
384
385     io->no_close = b;
386 }
387
388 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
389     pa_assert(io);
390     pa_assert(s);
391     pa_assert(l);
392
393     pa_socket_peer_to_string(io->ifd, s, l);
394 }
395
396 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
397     pa_assert(io);
398
399     return pa_socket_set_rcvbuf(io->ifd, l);
400 }
401
402 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
403     pa_assert(io);
404
405     return pa_socket_set_sndbuf(io->ofd, l);
406 }
407
408 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
409     pa_assert(io);
410
411     return io->mainloop;
412 }
413
414 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
415     pa_assert(io);
416
417     return io->ifd;
418 }