• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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