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
44struct 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
60static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata);
61
62static 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
74static 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
128static 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
162pa_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
183void 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
198bool pa_iochannel_is_readable(pa_iochannel*io) {
199    pa_assert(io);
200
201    return io->readable || io->hungup;
202}
203
204bool pa_iochannel_is_writable(pa_iochannel*io) {
205    pa_assert(io);
206
207    return io->writable && !io->hungup;
208}
209
210bool pa_iochannel_is_hungup(pa_iochannel*io) {
211    pa_assert(io);
212
213    return io->hungup;
214}
215
216ssize_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
243ssize_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__)
265typedef struct cmsgcred pa_ucred_t;
266#define SCM_CREDENTIALS SCM_CREDS
267#else
268typedef struct ucred pa_ucred_t;
269#endif
270
271bool 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
293int 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
311ssize_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" */
366ssize_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
415ssize_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
498void 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
505void pa_iochannel_set_noclose(pa_iochannel*io, bool b) {
506    pa_assert(io);
507
508    io->no_close = b;
509}
510
511void 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
519int 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
525int 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
531pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
532    pa_assert(io);
533
534    return io->mainloop;
535}
536
537int pa_iochannel_get_recv_fd(pa_iochannel *io) {
538    pa_assert(io);
539
540    return io->ifd;
541}
542
543int pa_iochannel_get_send_fd(pa_iochannel *io) {
544    pa_assert(io);
545
546    return io->ofd;
547}
548
549bool 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