• 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 == 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