]> code.delx.au - pulseaudio/blob - src/pulsecore/iochannel.c
remap: Change remapping function argument type from void to int16_t / float as approp...
[pulseaudio] / 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 bool readable:1;
55 bool writable:1;
56 bool hungup:1;
57 bool 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->output_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 bool 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 bool pa_iochannel_is_readable(pa_iochannel*io) {
201 pa_assert(io);
202
203 return io->readable || io->hungup;
204 }
205
206 bool pa_iochannel_is_writable(pa_iochannel*io) {
207 pa_assert(io);
208
209 return io->writable && !io->hungup;
210 }
211
212 bool 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 r = pa_write(io->ofd, data, l, &io->ofd_type);
227
228 if ((size_t) r == l)
229 return r; /* Fast path - we almost always successfully write everything */
230
231 if (r < 0) {
232 if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
233 r = 0;
234 else
235 return r;
236 }
237
238 /* Partial write - let's get a notification when we can write more */
239 io->writable = io->hungup = false;
240 enable_events(io);
241
242 return r;
243 }
244
245 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
246 ssize_t r;
247
248 pa_assert(io);
249 pa_assert(data);
250 pa_assert(io->ifd >= 0);
251
252 if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
253
254 /* We also reset the hangup flag here to ensure that another
255 * IO callback is triggered so that we will again call into
256 * user code */
257 io->readable = io->hungup = false;
258 enable_events(io);
259 }
260
261 return r;
262 }
263
264 #ifdef HAVE_CREDS
265
266 bool pa_iochannel_creds_supported(pa_iochannel *io) {
267 struct {
268 struct sockaddr sa;
269 #ifdef HAVE_SYS_UN_H
270 struct sockaddr_un un;
271 #endif
272 struct sockaddr_storage storage;
273 } sa;
274
275 socklen_t l;
276
277 pa_assert(io);
278 pa_assert(io->ifd >= 0);
279 pa_assert(io->ofd == io->ifd);
280
281 l = sizeof(sa);
282 if (getsockname(io->ifd, &sa.sa, &l) < 0)
283 return false;
284
285 return sa.sa.sa_family == AF_UNIX;
286 }
287
288 int pa_iochannel_creds_enable(pa_iochannel *io) {
289 int t = 1;
290
291 pa_assert(io);
292 pa_assert(io->ifd >= 0);
293
294 if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
295 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
296 return -1;
297 }
298
299 return 0;
300 }
301
302 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
303 ssize_t r;
304 struct msghdr mh;
305 struct iovec iov;
306 union {
307 struct cmsghdr hdr;
308 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
309 } cmsg;
310 struct ucred *u;
311
312 pa_assert(io);
313 pa_assert(data);
314 pa_assert(l);
315 pa_assert(io->ofd >= 0);
316
317 pa_zero(iov);
318 iov.iov_base = (void*) data;
319 iov.iov_len = l;
320
321 pa_zero(cmsg);
322 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct ucred));
323 cmsg.hdr.cmsg_level = SOL_SOCKET;
324 cmsg.hdr.cmsg_type = SCM_CREDENTIALS;
325
326 u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
327
328 u->pid = getpid();
329 if (ucred) {
330 u->uid = ucred->uid;
331 u->gid = ucred->gid;
332 } else {
333 u->uid = getuid();
334 u->gid = getgid();
335 }
336
337 pa_zero(mh);
338 mh.msg_iov = &iov;
339 mh.msg_iovlen = 1;
340 mh.msg_control = &cmsg;
341 mh.msg_controllen = sizeof(cmsg);
342
343 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
344 io->writable = io->hungup = false;
345 enable_events(io);
346 }
347
348 return r;
349 }
350
351 ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, bool *creds_valid) {
352 ssize_t r;
353 struct msghdr mh;
354 struct iovec iov;
355 union {
356 struct cmsghdr hdr;
357 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
358 } cmsg;
359
360 pa_assert(io);
361 pa_assert(data);
362 pa_assert(l);
363 pa_assert(io->ifd >= 0);
364 pa_assert(creds);
365 pa_assert(creds_valid);
366
367 pa_zero(iov);
368 iov.iov_base = data;
369 iov.iov_len = l;
370
371 pa_zero(cmsg);
372 pa_zero(mh);
373 mh.msg_iov = &iov;
374 mh.msg_iovlen = 1;
375 mh.msg_control = &cmsg;
376 mh.msg_controllen = sizeof(cmsg);
377
378 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
379 struct cmsghdr *cmh;
380
381 *creds_valid = false;
382
383 for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
384
385 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) {
386 struct ucred u;
387 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
388 memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
389
390 creds->gid = u.gid;
391 creds->uid = u.uid;
392 *creds_valid = true;
393 break;
394 }
395 }
396
397 io->readable = io->hungup = false;
398 enable_events(io);
399 }
400
401 return r;
402 }
403
404 #endif /* HAVE_CREDS */
405
406 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
407 pa_assert(io);
408
409 io->callback = _callback;
410 io->userdata = userdata;
411 }
412
413 void pa_iochannel_set_noclose(pa_iochannel*io, bool b) {
414 pa_assert(io);
415
416 io->no_close = !!b;
417 }
418
419 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
420 pa_assert(io);
421 pa_assert(s);
422 pa_assert(l);
423
424 pa_socket_peer_to_string(io->ifd, s, l);
425 }
426
427 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
428 pa_assert(io);
429
430 return pa_socket_set_rcvbuf(io->ifd, l);
431 }
432
433 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
434 pa_assert(io);
435
436 return pa_socket_set_sndbuf(io->ofd, l);
437 }
438
439 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
440 pa_assert(io);
441
442 return io->mainloop;
443 }
444
445 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
446 pa_assert(io);
447
448 return io->ifd;
449 }
450
451 int pa_iochannel_get_send_fd(pa_iochannel *io) {
452 pa_assert(io);
453
454 return io->ofd;
455 }
456
457 bool pa_iochannel_socket_is_local(pa_iochannel *io) {
458 pa_assert(io);
459
460 if (pa_socket_is_local(io->ifd))
461 return true;
462
463 if (io->ifd != io->ofd)
464 if (pa_socket_is_local(io->ofd))
465 return true;
466
467 return false;
468 }