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 == EINTR || 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
pa_iochannel_creds_supported(pa_iochannel * io)264 bool pa_iochannel_creds_supported(pa_iochannel *io) {
265 struct {
266 struct sockaddr sa;
267 #ifdef HAVE_SYS_UN_H
268 struct sockaddr_un un;
269 #endif
270 struct sockaddr_storage storage;
271 } sa;
272
273 socklen_t l;
274
275 pa_assert(io);
276 pa_assert(io->ifd >= 0);
277 pa_assert(io->ofd == io->ifd);
278
279 l = sizeof(sa);
280 if (getsockname(io->ifd, &sa.sa, &l) < 0)
281 return false;
282
283 return sa.sa.sa_family == AF_UNIX;
284 }
285
pa_iochannel_creds_enable(pa_iochannel * io)286 int pa_iochannel_creds_enable(pa_iochannel *io) {
287 int t = 1;
288
289 pa_assert(io);
290 pa_assert(io->ifd >= 0);
291
292 if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
293 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
294 return -1;
295 }
296
297 return 0;
298 }
299
pa_iochannel_write_with_creds(pa_iochannel * io,const void * data,size_t l,const pa_creds * ucred)300 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
301 ssize_t r;
302 struct msghdr mh;
303 struct iovec iov;
304 union {
305 struct cmsghdr hdr;
306 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
307 } cmsg;
308 struct ucred *u;
309
310 pa_assert(io);
311 pa_assert(data);
312 pa_assert(l);
313 pa_assert(io->ofd >= 0);
314
315 pa_zero(iov);
316 iov.iov_base = (void*) data;
317 iov.iov_len = l;
318
319 pa_zero(cmsg);
320 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct ucred));
321 cmsg.hdr.cmsg_level = SOL_SOCKET;
322 cmsg.hdr.cmsg_type = SCM_CREDENTIALS;
323
324 u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
325
326 u->pid = getpid();
327 if (ucred) {
328 u->uid = ucred->uid;
329 u->gid = ucred->gid;
330 } else {
331 u->uid = getuid();
332 u->gid = getgid();
333 }
334
335 pa_zero(mh);
336 mh.msg_iov = &iov;
337 mh.msg_iovlen = 1;
338 mh.msg_control = &cmsg;
339 mh.msg_controllen = sizeof(cmsg);
340
341 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
342 io->writable = io->hungup = false;
343 enable_events(io);
344 }
345
346 return r;
347 }
348
349 /* For more details on FD passing, check the cmsg(3) manpage
350 * 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)351 ssize_t pa_iochannel_write_with_fds(pa_iochannel*io, const void*data, size_t l, int nfd, const int *fds) {
352 ssize_t r;
353 int *msgdata;
354 struct msghdr mh;
355 struct iovec iov;
356 union {
357 struct cmsghdr hdr;
358 uint8_t data[CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)];
359 } cmsg;
360
361 pa_assert(io);
362 pa_assert(data);
363 pa_assert(l);
364 pa_assert(io->ofd >= 0);
365 pa_assert(fds);
366 pa_assert(nfd > 0);
367 pa_assert(nfd <= MAX_ANCIL_DATA_FDS);
368
369 pa_zero(iov);
370 iov.iov_base = (void*) data;
371 iov.iov_len = l;
372
373 pa_zero(cmsg);
374 cmsg.hdr.cmsg_level = SOL_SOCKET;
375 cmsg.hdr.cmsg_type = SCM_RIGHTS;
376
377 msgdata = (int*) CMSG_DATA(&cmsg.hdr);
378 memcpy(msgdata, fds, nfd * sizeof(int));
379 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int) * nfd);
380
381 pa_zero(mh);
382 mh.msg_iov = &iov;
383 mh.msg_iovlen = 1;
384 mh.msg_control = &cmsg;
385
386 /* If we followed the example on the cmsg man page, we'd use
387 * sizeof(cmsg.data) here, but if nfd < MAX_ANCIL_DATA_FDS, then the data
388 * buffer is larger than needed, and the kernel doesn't like it if we set
389 * msg_controllen to a larger than necessary value. The commit message for
390 * commit 451d1d6762 contains a longer explanation. */
391 mh.msg_controllen = CMSG_SPACE(sizeof(int) * nfd);
392
393 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
394 io->writable = io->hungup = false;
395 enable_events(io);
396 }
397 return r;
398 }
399
pa_iochannel_read_with_ancil_data(pa_iochannel * io,void * data,size_t l,pa_cmsg_ancil_data * ancil_data)400 ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l, pa_cmsg_ancil_data *ancil_data) {
401 ssize_t r;
402 struct msghdr mh;
403 struct iovec iov;
404 union {
405 struct cmsghdr hdr;
406 uint8_t data[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)];
407 } cmsg;
408
409 pa_assert(io);
410 pa_assert(data);
411 pa_assert(l);
412 pa_assert(io->ifd >= 0);
413 pa_assert(ancil_data);
414
415 if (io->ifd_type > 0) {
416 ancil_data->creds_valid = false;
417 ancil_data->nfd = 0;
418 return pa_iochannel_read(io, data, l);
419 }
420
421 iov.iov_base = data;
422 iov.iov_len = l;
423
424 pa_zero(mh);
425 mh.msg_iov = &iov;
426 mh.msg_iovlen = 1;
427 mh.msg_control = &cmsg;
428 mh.msg_controllen = sizeof(cmsg);
429
430 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
431 struct cmsghdr *cmh;
432
433 ancil_data->creds_valid = false;
434 ancil_data->nfd = 0;
435
436 for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
437
438 if (cmh->cmsg_level != SOL_SOCKET)
439 continue;
440
441 if (cmh->cmsg_type == SCM_CREDENTIALS) {
442 struct ucred u;
443 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
444 memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
445
446 ancil_data->creds.gid = u.gid;
447 ancil_data->creds.uid = u.uid;
448 ancil_data->creds_valid = true;
449 }
450 else if (cmh->cmsg_type == SCM_RIGHTS) {
451 int nfd = (cmh->cmsg_len - CMSG_LEN(0)) / sizeof(int);
452 if (nfd > MAX_ANCIL_DATA_FDS) {
453 int i;
454 pa_log("Trying to receive too many file descriptors!");
455 for (i = 0; i < nfd; i++)
456 pa_close(((int*) CMSG_DATA(cmh))[i]);
457 continue;
458 }
459 memcpy(ancil_data->fds, CMSG_DATA(cmh), nfd * sizeof(int));
460 ancil_data->nfd = nfd;
461 ancil_data->close_fds_on_cleanup = true;
462 }
463 }
464
465 io->readable = io->hungup = false;
466 enable_events(io);
467 }
468
469 if (r == -1 && errno == ENOTSOCK) {
470 io->ifd_type = 1;
471 return pa_iochannel_read_with_ancil_data(io, data, l, ancil_data);
472 }
473
474 return r;
475 }
476
477 #endif /* HAVE_CREDS */
478
pa_iochannel_set_callback(pa_iochannel * io,pa_iochannel_cb_t _callback,void * userdata)479 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
480 pa_assert(io);
481
482 io->callback = _callback;
483 io->userdata = userdata;
484 }
485
pa_iochannel_set_noclose(pa_iochannel * io,bool b)486 void pa_iochannel_set_noclose(pa_iochannel*io, bool b) {
487 pa_assert(io);
488
489 io->no_close = b;
490 }
491
pa_iochannel_socket_peer_to_string(pa_iochannel * io,char * s,size_t l)492 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
493 pa_assert(io);
494 pa_assert(s);
495 pa_assert(l);
496
497 pa_socket_peer_to_string(io->ifd, s, l);
498 }
499
pa_iochannel_socket_set_rcvbuf(pa_iochannel * io,size_t l)500 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
501 pa_assert(io);
502
503 return pa_socket_set_rcvbuf(io->ifd, l);
504 }
505
pa_iochannel_socket_set_sndbuf(pa_iochannel * io,size_t l)506 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
507 pa_assert(io);
508
509 return pa_socket_set_sndbuf(io->ofd, l);
510 }
511
pa_iochannel_get_mainloop_api(pa_iochannel * io)512 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
513 pa_assert(io);
514
515 return io->mainloop;
516 }
517
pa_iochannel_get_recv_fd(pa_iochannel * io)518 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
519 pa_assert(io);
520
521 return io->ifd;
522 }
523
pa_iochannel_get_send_fd(pa_iochannel * io)524 int pa_iochannel_get_send_fd(pa_iochannel *io) {
525 pa_assert(io);
526
527 return io->ofd;
528 }
529
pa_iochannel_socket_is_local(pa_iochannel * io)530 bool pa_iochannel_socket_is_local(pa_iochannel *io) {
531 pa_assert(io);
532
533 if (pa_socket_is_local(io->ifd))
534 return true;
535
536 if (io->ifd != io->ofd)
537 if (pa_socket_is_local(io->ofd))
538 return true;
539
540 return false;
541 }
542