2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
35 #include <pulse/xmalloc.h>
37 #include <pulsecore/core-error.h>
38 #include <pulsecore/core-util.h>
39 #include <pulsecore/socket.h>
40 #include <pulsecore/socket-util.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/macro.h>
44 #include "iochannel.h"
48 int ifd_type
, ofd_type
;
49 pa_mainloop_api
* mainloop
;
51 pa_iochannel_cb_t callback
;
59 pa_io_event
* input_event
, *output_event
;
62 static void callback(pa_mainloop_api
* m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
);
64 static void delete_events(pa_iochannel
*io
) {
68 io
->mainloop
->io_free(io
->input_event
);
70 if (io
->output_event
&& io
->output_event
!= io
->input_event
)
71 io
->mainloop
->io_free(io
->output_event
);
73 io
->input_event
= io
->output_event
= NULL
;
76 static void enable_events(pa_iochannel
*io
) {
84 if (io
->ifd
== io
->ofd
&& io
->ifd
>= 0) {
85 pa_io_event_flags_t f
= PA_IO_EVENT_NULL
;
88 f
|= PA_IO_EVENT_INPUT
;
90 f
|= PA_IO_EVENT_OUTPUT
;
92 pa_assert(io
->input_event
== io
->output_event
);
94 if (f
!= PA_IO_EVENT_NULL
) {
96 io
->mainloop
->io_enable(io
->input_event
, f
);
98 io
->input_event
= io
->output_event
= io
->mainloop
->io_new(io
->mainloop
, io
->ifd
, f
, callback
, io
);
107 io
->mainloop
->io_enable(io
->input_event
, PA_IO_EVENT_INPUT
);
109 io
->input_event
= io
->mainloop
->io_new(io
->mainloop
, io
->ifd
, PA_IO_EVENT_INPUT
, callback
, io
);
110 } else if (io
->input_event
) {
111 io
->mainloop
->io_free(io
->input_event
);
112 io
->input_event
= NULL
;
118 if (io
->output_event
)
119 io
->mainloop
->io_enable(io
->output_event
, PA_IO_EVENT_OUTPUT
);
121 io
->output_event
= io
->mainloop
->io_new(io
->mainloop
, io
->ofd
, PA_IO_EVENT_OUTPUT
, callback
, io
);
122 } else if (io
->output_event
) {
123 io
->mainloop
->io_free(io
->output_event
);
124 io
->output_event
= NULL
;
130 static void callback(pa_mainloop_api
* m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
131 pa_iochannel
*io
= userdata
;
132 bool changed
= false;
139 if ((f
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
)) && !io
->hungup
) {
144 if ((f
& PA_IO_EVENT_INPUT
) && !io
->readable
) {
147 pa_assert(e
== io
->input_event
);
150 if ((f
& PA_IO_EVENT_OUTPUT
) && !io
->writable
) {
153 pa_assert(e
== io
->output_event
);
160 io
->callback(io
, io
->userdata
);
164 pa_iochannel
* pa_iochannel_new(pa_mainloop_api
*m
, int ifd
, int ofd
) {
168 pa_assert(ifd
>= 0 || ofd
>= 0);
170 io
= pa_xnew0(pa_iochannel
, 1);
176 pa_make_fd_nonblock(io
->ifd
);
178 if (io
->ofd
>= 0 && io
->ofd
!= io
->ifd
)
179 pa_make_fd_nonblock(io
->ofd
);
185 void pa_iochannel_free(pa_iochannel
*io
) {
193 if (io
->ofd
>= 0 && io
->ofd
!= io
->ifd
)
200 bool pa_iochannel_is_readable(pa_iochannel
*io
) {
203 return io
->readable
|| io
->hungup
;
206 bool pa_iochannel_is_writable(pa_iochannel
*io
) {
209 return io
->writable
&& !io
->hungup
;
212 bool pa_iochannel_is_hungup(pa_iochannel
*io
) {
218 ssize_t
pa_iochannel_write(pa_iochannel
*io
, const void*data
, size_t l
) {
224 pa_assert(io
->ofd
>= 0);
226 r
= pa_write(io
->ofd
, data
, l
, &io
->ofd_type
);
229 return r
; /* Fast path - we almost always successfully write everything */
232 if (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
238 /* Partial write - let's get a notification when we can write more */
239 io
->writable
= io
->hungup
= false;
245 ssize_t
pa_iochannel_read(pa_iochannel
*io
, void*data
, size_t l
) {
250 pa_assert(io
->ifd
>= 0);
252 if ((r
= pa_read(io
->ifd
, data
, l
, &io
->ifd_type
)) >= 0) {
254 /* We also reset the hangup flag here to ensure that another
255 * IO callback is triggered so that we will again call into
257 io
->readable
= io
->hungup
= false;
266 bool pa_iochannel_creds_supported(pa_iochannel
*io
) {
270 struct sockaddr_un un
;
272 struct sockaddr_storage storage
;
278 pa_assert(io
->ifd
>= 0);
279 pa_assert(io
->ofd
== io
->ifd
);
282 if (getsockname(io
->ifd
, &sa
.sa
, &l
) < 0)
285 return sa
.sa
.sa_family
== AF_UNIX
;
288 int pa_iochannel_creds_enable(pa_iochannel
*io
) {
292 pa_assert(io
->ifd
>= 0);
294 if (setsockopt(io
->ifd
, SOL_SOCKET
, SO_PASSCRED
, &t
, sizeof(t
)) < 0) {
295 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno
));
302 ssize_t
pa_iochannel_write_with_creds(pa_iochannel
*io
, const void*data
, size_t l
, const pa_creds
*ucred
) {
308 uint8_t data
[CMSG_SPACE(sizeof(struct ucred
))];
315 pa_assert(io
->ofd
>= 0);
318 iov
.iov_base
= (void*) data
;
322 cmsg
.hdr
.cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
323 cmsg
.hdr
.cmsg_level
= SOL_SOCKET
;
324 cmsg
.hdr
.cmsg_type
= SCM_CREDENTIALS
;
326 u
= (struct ucred
*) CMSG_DATA(&cmsg
.hdr
);
340 mh
.msg_control
= &cmsg
;
341 mh
.msg_controllen
= sizeof(cmsg
);
343 if ((r
= sendmsg(io
->ofd
, &mh
, MSG_NOSIGNAL
)) >= 0) {
344 io
->writable
= io
->hungup
= false;
351 ssize_t
pa_iochannel_read_with_creds(pa_iochannel
*io
, void*data
, size_t l
, pa_creds
*creds
, bool *creds_valid
) {
357 uint8_t data
[CMSG_SPACE(sizeof(struct ucred
))];
363 pa_assert(io
->ifd
>= 0);
365 pa_assert(creds_valid
);
375 mh
.msg_control
= &cmsg
;
376 mh
.msg_controllen
= sizeof(cmsg
);
378 if ((r
= recvmsg(io
->ifd
, &mh
, 0)) >= 0) {
381 *creds_valid
= false;
383 for (cmh
= CMSG_FIRSTHDR(&mh
); cmh
; cmh
= CMSG_NXTHDR(&mh
, cmh
)) {
385 if (cmh
->cmsg_level
== SOL_SOCKET
&& cmh
->cmsg_type
== SCM_CREDENTIALS
) {
387 pa_assert(cmh
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)));
388 memcpy(&u
, CMSG_DATA(cmh
), sizeof(struct ucred
));
397 io
->readable
= io
->hungup
= false;
404 #endif /* HAVE_CREDS */
406 void pa_iochannel_set_callback(pa_iochannel
*io
, pa_iochannel_cb_t _callback
, void *userdata
) {
409 io
->callback
= _callback
;
410 io
->userdata
= userdata
;
413 void pa_iochannel_set_noclose(pa_iochannel
*io
, bool b
) {
419 void pa_iochannel_socket_peer_to_string(pa_iochannel
*io
, char*s
, size_t l
) {
424 pa_socket_peer_to_string(io
->ifd
, s
, l
);
427 int pa_iochannel_socket_set_rcvbuf(pa_iochannel
*io
, size_t l
) {
430 return pa_socket_set_rcvbuf(io
->ifd
, l
);
433 int pa_iochannel_socket_set_sndbuf(pa_iochannel
*io
, size_t l
) {
436 return pa_socket_set_sndbuf(io
->ofd
, l
);
439 pa_mainloop_api
* pa_iochannel_get_mainloop_api(pa_iochannel
*io
) {
445 int pa_iochannel_get_recv_fd(pa_iochannel
*io
) {
451 int pa_iochannel_get_send_fd(pa_iochannel
*io
) {
457 bool pa_iochannel_socket_is_local(pa_iochannel
*io
) {
460 if (pa_socket_is_local(io
->ifd
))
463 if (io
->ifd
!= io
->ofd
)
464 if (pa_socket_is_local(io
->ofd
))