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, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <errno.h>
28
29 #ifdef HAVE_SYS_UN_H
30 #include <sys/un.h>
31 #endif
32
33 #include <pulse/xmalloc.h>
34
35 #include <pulsecore/core-error.h>
36 #include <pulsecore/core-util.h>
37 #include <pulsecore/socket.h>
38 #include <pulsecore/socket-util.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/macro.h>
41
42 #include "iochannel.h"
43
44 struct pa_iochannel {
45 int ifd, ofd;
46 int ifd_type, ofd_type;
47 pa_mainloop_api* mainloop;
48
49 pa_iochannel_cb_t callback;
50 void*userdata;
51
52 bool readable:1;
53 bool writable:1;
54 bool hungup:1;
55 bool no_close:1;
56
57 pa_io_event* input_event, *output_event;
58 };
59
60 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata);
61
delete_events(pa_iochannel * io)62 static void delete_events(pa_iochannel *io) {
63 pa_assert(io);
64
65 if (io->input_event)
66 io->mainloop->io_free(io->input_event);
67
68 if (io->output_event && io->output_event != io->input_event)
69 io->mainloop->io_free(io->output_event);
70
71 io->input_event = io->output_event = NULL;
72 }
73
enable_events(pa_iochannel * io)74 static void enable_events(pa_iochannel *io) {
75 pa_assert(io);
76
77 if (io->hungup) {
78 delete_events(io);
79 return;
80 }
81
82 if (io->ifd == io->ofd && io->ifd >= 0) {
83 pa_io_event_flags_t f = PA_IO_EVENT_NULL;
84
85 if (!io->readable)
86 f |= PA_IO_EVENT_INPUT;
87 if (!io->writable)
88 f |= PA_IO_EVENT_OUTPUT;
89
90 pa_assert(io->input_event == io->output_event);
91
92 if (f != PA_IO_EVENT_NULL) {
93 if (io->input_event)
94 io->mainloop->io_enable(io->input_event, f);
95 else
96 io->input_event = io->output_event = io->mainloop->io_new(io->mainloop, io->ifd, f, callback, io);
97 } else
98 delete_events(io);
99
100 } else {
101
102 if (io->ifd >= 0) {
103 if (!io->readable) {
104 if (io->input_event)
105 io->mainloop->io_enable(io->input_event, PA_IO_EVENT_INPUT);
106 else
107 io->input_event = io->mainloop->io_new(io->mainloop, io->ifd, PA_IO_EVENT_INPUT, callback, io);
108 } else if (io->input_event) {
109 io->mainloop->io_free(io->input_event);
110 io->input_event = NULL;
111 }
112 }
113
114 if (io->ofd >= 0) {
115 if (!io->writable) {
116 if (io->output_event)
117 io->mainloop->io_enable(io->output_event, PA_IO_EVENT_OUTPUT);
118 else
119 io->output_event = io->mainloop->io_new(io->mainloop, io->ofd, PA_IO_EVENT_OUTPUT, callback, io);
120 } else if (io->output_event) {
121 io->mainloop->io_free(io->output_event);
122 io->output_event = NULL;
123 }
124 }
125 }
126 }
127
callback(pa_mainloop_api * m,pa_io_event * e,int fd,pa_io_event_flags_t f,void * userdata)128 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
129 pa_iochannel *io = userdata;
130 bool changed = false;
131
132 pa_assert(m);
133 pa_assert(e);
134 pa_assert(fd >= 0);
135 pa_assert(userdata);
136
137 if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
138 io->hungup = true;
139 changed = true;
140 }
141
142 if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
143 io->readable = true;
144 changed = true;
145 pa_assert(e == io->input_event);
146 }
147
148 if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
149 io->writable = true;
150 changed = true;
151 pa_assert(e == io->output_event);
152 }
153
154 if (changed) {
155 enable_events(io);
156
157 if (io->callback)
158 io->callback(io, io->userdata);
159 }
160 }
161
pa_iochannel_new(pa_mainloop_api * m,int ifd,int ofd)162 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
163 pa_iochannel *io;
164
165 pa_assert(m);
166 pa_assert(ifd >= 0 || ofd >= 0);
167
168 io = pa_xnew0(pa_iochannel, 1);
169 io->ifd = ifd;
170 io->ofd = ofd;
171 io->mainloop = m;
172
173 if (io->ifd >= 0)
174 pa_make_fd_nonblock(io->ifd);
175
176 if (io->ofd >= 0 && io->ofd != io->ifd)
177 pa_make_fd_nonblock(io->ofd);
178
179 enable_events(io);
180 return io;
181 }
182
pa_iochannel_free(pa_iochannel * io)183 void pa_iochannel_free(pa_iochannel*io) {
184 pa_assert(io);
185
186 delete_events(io);
187
188 if (!io->no_close) {
189 if (io->ifd >= 0)
190 pa_close(io->ifd);
191 if (io->ofd >= 0 && io->ofd != io->ifd)
192 pa_close(io->ofd);
193 }
194
195 pa_xfree(io);
196 }
197
pa_iochannel_is_readable(pa_iochannel * io)198 bool pa_iochannel_is_readable(pa_iochannel*io) {
199 pa_assert(io);
200
201 return io->readable || io->hungup;
202 }
203
pa_iochannel_is_writable(pa_iochannel * io)204 bool pa_iochannel_is_writable(pa_iochannel*io) {
205 pa_assert(io);
206
207 return io->writable && !io->hungup;
208 }
209
pa_iochannel_is_hungup(pa_iochannel * io)210 bool pa_iochannel_is_hungup(pa_iochannel*io) {
211 pa_assert(io);
212
213 return io->hungup;
214 }
215
pa_iochannel_write(pa_iochannel * io,const void * data,size_t l)216 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
217 ssize_t r;
218
219 pa_assert(io);
220 pa_assert(data);
221 pa_assert(l);
222 pa_assert(io->ofd >= 0);
223
224 r = pa_write(io->ofd, data, l, &io->ofd_type);
225
226 if ((size_t) r == l)
227 return r; /* Fast path - we almost always successfully write everything */
228
229 if (r < 0) {
230 if (errno == EAGAIN)
231 r = 0;
232 else
233 return r;
234 }
235
236 /* Partial write - let's get a notification when we can write more */
237 io->writable = io->hungup = false;
238 enable_events(io);
239
240 return r;
241 }
242
pa_iochannel_read(pa_iochannel * io,void * data,size_t l)243 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
244 ssize_t r;
245
246 pa_assert(io);
247 pa_assert(data);
248 pa_assert(io->ifd >= 0);
249
250 if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
251
252 /* We also reset the hangup flag here to ensure that another
253 * IO callback is triggered so that we will again call into
254 * user code */
255 io->readable = io->hungup = false;
256 enable_events(io);
257 }
258
259 return r;
260 }
261
262 #ifdef HAVE_CREDS
263
264 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
265 typedef struct cmsgcred pa_ucred_t;
266 #define SCM_CREDENTIALS SCM_CREDS
267 #else
268 typedef struct ucred pa_ucred_t;
269 #endif
270
pa_iochannel_creds_supported(pa_iochannel * io)271 bool pa_iochannel_creds_supported(pa_iochannel *io) {
272 struct {
273 struct sockaddr sa;
274 #ifdef HAVE_SYS_UN_H
275 struct sockaddr_un un;
276 #endif
277 struct sockaddr_storage storage;
278 } sa;
279
280 socklen_t l;
281
282 pa_assert(io);
283 pa_assert(io->ifd >= 0);
284 pa_assert(io->ofd == io->ifd);
285
286 l = sizeof(sa);
287 if (getsockname(io->ifd, &sa.sa, &l) < 0)
288 return false;
289
290 return sa.sa.sa_family == AF_UNIX;
291 }
292
pa_iochannel_creds_enable(pa_iochannel * io)293 int pa_iochannel_creds_enable(pa_iochannel *io) {
294 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__)
295 int t = 1;
296 #endif
297
298 pa_assert(io);
299 pa_assert(io->ifd >= 0);
300
301 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__)
302 if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
303 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
304 return -1;
305 }
306 #endif
307
308 return 0;
309 }
310
pa_iochannel_write_with_creds(pa_iochannel * io,const void * data,size_t l,const pa_creds * ucred)311 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
312 ssize_t r;
313 struct msghdr mh;
314 struct iovec iov;
315 union {
316 struct cmsghdr hdr;
317 uint8_t data[CMSG_SPACE(sizeof(pa_ucred_t))];
318 } cmsg;
319 pa_ucred_t *u;
320
321 pa_assert(io);
322 pa_assert(data);
323 pa_assert(l);
324 pa_assert(io->ofd >= 0);
325
326 pa_zero(iov);
327 iov.iov_base = (void*) data;
328 iov.iov_len = l;
329
330 pa_zero(cmsg);
331 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(pa_ucred_t));
332 cmsg.hdr.cmsg_level = SOL_SOCKET;
333 cmsg.hdr.cmsg_type = SCM_CREDENTIALS;
334
335 u = (pa_ucred_t*) CMSG_DATA(&cmsg.hdr);
336
337 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
338 // the kernel fills everything
339 #else
340 u->pid = getpid();
341 if (ucred) {
342 u->uid = ucred->uid;
343 u->gid = ucred->gid;
344 } else {
345 u->uid = getuid();
346 u->gid = getgid();
347 }
348 #endif
349
350 pa_zero(mh);
351 mh.msg_iov = &iov;
352 mh.msg_iovlen = 1;
353 mh.msg_control = &cmsg;
354 mh.msg_controllen = sizeof(cmsg);
355
356 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
357 io->writable = io->hungup = false;
358 enable_events(io);
359 }
360
361 return r;
362 }
363
364 /* For more details on FD passing, check the cmsg(3) manpage
365 * and IETF RFC #2292: "Advanced Sockets API for IPv6" */
pa_iochannel_write_with_fds(pa_iochannel * io,const void * data,size_t l,int nfd,const int * fds)366 ssize_t pa_iochannel_write_with_fds(pa_iochannel*io, const void*data, size_t l, int nfd, const int *fds) {
367 ssize_t r;
368 int *msgdata;
369 struct msghdr mh;
370 struct iovec iov;
371 union {
372 struct cmsghdr hdr;
373 uint8_t data[CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)];
374 } cmsg;
375
376 pa_assert(io);
377 pa_assert(data);
378 pa_assert(l);
379 pa_assert(io->ofd >= 0);
380 pa_assert(fds);
381 pa_assert(nfd > 0);
382 pa_assert(nfd <= MAX_ANCIL_DATA_FDS);
383
384 pa_zero(iov);
385 iov.iov_base = (void*) data;
386 iov.iov_len = l;
387
388 pa_zero(cmsg);
389 cmsg.hdr.cmsg_level = SOL_SOCKET;
390 cmsg.hdr.cmsg_type = SCM_RIGHTS;
391
392 msgdata = (int*) CMSG_DATA(&cmsg.hdr);
393 memcpy(msgdata, fds, nfd * sizeof(int));
394 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int) * nfd);
395
396 pa_zero(mh);
397 mh.msg_iov = &iov;
398 mh.msg_iovlen = 1;
399 mh.msg_control = &cmsg;
400
401 /* If we followed the example on the cmsg man page, we'd use
402 * sizeof(cmsg.data) here, but if nfd < MAX_ANCIL_DATA_FDS, then the data
403 * buffer is larger than needed, and the kernel doesn't like it if we set
404 * msg_controllen to a larger than necessary value. The commit message for
405 * commit 451d1d6762 contains a longer explanation. */
406 mh.msg_controllen = CMSG_SPACE(sizeof(int) * nfd);
407
408 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
409 io->writable = io->hungup = false;
410 enable_events(io);
411 }
412 return r;
413 }
414
pa_iochannel_read_with_ancil_data(pa_iochannel * io,void * data,size_t l,pa_cmsg_ancil_data * ancil_data)415 ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l, pa_cmsg_ancil_data *ancil_data) {
416 ssize_t r;
417 struct msghdr mh;
418 struct iovec iov;
419 union {
420 struct cmsghdr hdr;
421 uint8_t data[CMSG_SPACE(sizeof(pa_ucred_t)) + CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)];
422 } cmsg;
423
424 pa_assert(io);
425 pa_assert(data);
426 pa_assert(l);
427 pa_assert(io->ifd >= 0);
428 pa_assert(ancil_data);
429
430 if (io->ifd_type > 0) {
431 ancil_data->creds_valid = false;
432 ancil_data->nfd = 0;
433 return pa_iochannel_read(io, data, l);
434 }
435
436 iov.iov_base = data;
437 iov.iov_len = l;
438
439 pa_zero(mh);
440 mh.msg_iov = &iov;
441 mh.msg_iovlen = 1;
442 mh.msg_control = &cmsg;
443 mh.msg_controllen = sizeof(cmsg);
444
445 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
446 struct cmsghdr *cmh;
447
448 ancil_data->creds_valid = false;
449 ancil_data->nfd = 0;
450
451 for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
452
453 if (cmh->cmsg_level != SOL_SOCKET)
454 continue;
455
456 if (cmh->cmsg_type == SCM_CREDENTIALS) {
457 pa_ucred_t u;
458 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(pa_ucred_t)));
459 memcpy(&u, CMSG_DATA(cmh), sizeof(pa_ucred_t));
460 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
461 ancil_data->creds.gid = u.cmcred_gid;
462 ancil_data->creds.uid = u.cmcred_uid;
463 #else
464 ancil_data->creds.gid = u.gid;
465 ancil_data->creds.uid = u.uid;
466 #endif
467 ancil_data->creds_valid = true;
468 }
469 else if (cmh->cmsg_type == SCM_RIGHTS) {
470 int nfd = (cmh->cmsg_len - CMSG_LEN(0)) / sizeof(int);
471 if (nfd > MAX_ANCIL_DATA_FDS) {
472 int i;
473 pa_log("Trying to receive too many file descriptors!");
474 for (i = 0; i < nfd; i++)
475 pa_close(((int*) CMSG_DATA(cmh))[i]);
476 continue;
477 }
478 memcpy(ancil_data->fds, CMSG_DATA(cmh), nfd * sizeof(int));
479 ancil_data->nfd = nfd;
480 ancil_data->close_fds_on_cleanup = true;
481 }
482 }
483
484 io->readable = io->hungup = false;
485 enable_events(io);
486 }
487
488 if (r == -1 && errno == ENOTSOCK) {
489 io->ifd_type = 1;
490 return pa_iochannel_read_with_ancil_data(io, data, l, ancil_data);
491 }
492
493 return r;
494 }
495
496 #endif /* HAVE_CREDS */
497
pa_iochannel_set_callback(pa_iochannel * io,pa_iochannel_cb_t _callback,void * userdata)498 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
499 pa_assert(io);
500
501 io->callback = _callback;
502 io->userdata = userdata;
503 }
504
pa_iochannel_set_noclose(pa_iochannel * io,bool b)505 void pa_iochannel_set_noclose(pa_iochannel*io, bool b) {
506 pa_assert(io);
507
508 io->no_close = b;
509 }
510
pa_iochannel_socket_peer_to_string(pa_iochannel * io,char * s,size_t l)511 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
512 pa_assert(io);
513 pa_assert(s);
514 pa_assert(l);
515
516 pa_socket_peer_to_string(io->ifd, s, l);
517 }
518
pa_iochannel_socket_set_rcvbuf(pa_iochannel * io,size_t l)519 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
520 pa_assert(io);
521
522 return pa_socket_set_rcvbuf(io->ifd, l);
523 }
524
pa_iochannel_socket_set_sndbuf(pa_iochannel * io,size_t l)525 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
526 pa_assert(io);
527
528 return pa_socket_set_sndbuf(io->ofd, l);
529 }
530
pa_iochannel_get_mainloop_api(pa_iochannel * io)531 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
532 pa_assert(io);
533
534 return io->mainloop;
535 }
536
pa_iochannel_get_recv_fd(pa_iochannel * io)537 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
538 pa_assert(io);
539
540 return io->ifd;
541 }
542
pa_iochannel_get_send_fd(pa_iochannel * io)543 int pa_iochannel_get_send_fd(pa_iochannel *io) {
544 pa_assert(io);
545
546 return io->ofd;
547 }
548
pa_iochannel_socket_is_local(pa_iochannel * io)549 bool pa_iochannel_socket_is_local(pa_iochannel *io) {
550 pa_assert(io);
551
552 if (pa_socket_is_local(io->ifd))
553 return true;
554
555 if (io->ifd != io->ofd)
556 if (pa_socket_is_local(io->ofd))
557 return true;
558
559 return false;
560 }
561