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
36 #include <pulse/xmalloc.h>
38 #include <pulsecore/core-error.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/socket.h>
41 #include <pulsecore/socket-util.h>
42 #include <pulsecore/log.h>
43 #include <pulsecore/macro.h>
45 #include "iochannel.h"
49 int ifd_type
, ofd_type
;
50 pa_mainloop_api
* mainloop
;
52 pa_iochannel_cb_t callback
;
60 pa_io_event
* input_event
, *output_event
;
63 static void callback(pa_mainloop_api
* m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
);
65 static void delete_events(pa_iochannel
*io
) {
69 io
->mainloop
->io_free(io
->input_event
);
71 if (io
->output_event
&& io
->output_event
!= io
->input_event
)
72 io
->mainloop
->io_free(io
->output_event
);
74 io
->input_event
= io
->output_event
= NULL
;
77 static void enable_events(pa_iochannel
*io
) {
85 if (io
->ifd
== io
->ofd
&& io
->ifd
>= 0) {
86 pa_io_event_flags_t f
= PA_IO_EVENT_NULL
;
89 f
|= PA_IO_EVENT_INPUT
;
91 f
|= PA_IO_EVENT_OUTPUT
;
93 pa_assert(io
->input_event
== io
->output_event
);
95 if (f
!= PA_IO_EVENT_NULL
) {
97 io
->mainloop
->io_enable(io
->input_event
, f
);
99 io
->input_event
= io
->output_event
= io
->mainloop
->io_new(io
->mainloop
, io
->ifd
, f
, callback
, io
);
108 io
->mainloop
->io_enable(io
->input_event
, PA_IO_EVENT_INPUT
);
110 io
->input_event
= io
->mainloop
->io_new(io
->mainloop
, io
->ifd
, PA_IO_EVENT_INPUT
, callback
, io
);
111 } else if (io
->input_event
) {
112 io
->mainloop
->io_free(io
->input_event
);
113 io
->input_event
= NULL
;
119 if (io
->output_event
)
120 io
->mainloop
->io_enable(io
->output_event
, PA_IO_EVENT_OUTPUT
);
122 io
->output_event
= io
->mainloop
->io_new(io
->mainloop
, io
->ofd
, PA_IO_EVENT_OUTPUT
, callback
, io
);
123 } else if (io
->input_event
) {
124 io
->mainloop
->io_free(io
->output_event
);
125 io
->output_event
= NULL
;
131 static void callback(pa_mainloop_api
* m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
132 pa_iochannel
*io
= userdata
;
133 pa_bool_t changed
= FALSE
;
140 if ((f
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
)) && !io
->hungup
) {
145 if ((f
& PA_IO_EVENT_INPUT
) && !io
->readable
) {
148 pa_assert(e
== io
->input_event
);
151 if ((f
& PA_IO_EVENT_OUTPUT
) && !io
->writable
) {
154 pa_assert(e
== io
->output_event
);
161 io
->callback(io
, io
->userdata
);
165 pa_iochannel
* pa_iochannel_new(pa_mainloop_api
*m
, int ifd
, int ofd
) {
169 pa_assert(ifd
>= 0 || ofd
>= 0);
171 io
= pa_xnew0(pa_iochannel
, 1);
177 pa_make_fd_nonblock(io
->ifd
);
179 if (io
->ofd
>= 0 && io
->ofd
!= io
->ifd
)
180 pa_make_fd_nonblock(io
->ofd
);
186 void pa_iochannel_free(pa_iochannel
*io
) {
194 if (io
->ofd
>= 0 && io
->ofd
!= io
->ifd
)
201 pa_bool_t
pa_iochannel_is_readable(pa_iochannel
*io
) {
204 return io
->readable
|| io
->hungup
;
207 pa_bool_t
pa_iochannel_is_writable(pa_iochannel
*io
) {
210 return io
->writable
&& !io
->hungup
;
213 pa_bool_t
pa_iochannel_is_hungup(pa_iochannel
*io
) {
219 ssize_t
pa_iochannel_write(pa_iochannel
*io
, const void*data
, size_t l
) {
225 pa_assert(io
->ofd
>= 0);
227 if ((r
= pa_write(io
->ofd
, data
, l
, &io
->ofd_type
)) >= 0) {
228 io
->writable
= io
->hungup
= FALSE
;
235 ssize_t
pa_iochannel_read(pa_iochannel
*io
, void*data
, size_t l
) {
240 pa_assert(io
->ifd
>= 0);
242 if ((r
= pa_read(io
->ifd
, data
, l
, &io
->ifd_type
)) >= 0) {
244 /* We also reset the hangup flag here to ensure that another
245 * IO callback is triggered so that we will again call into
247 io
->readable
= io
->hungup
= FALSE
;
256 pa_bool_t
pa_iochannel_creds_supported(pa_iochannel
*io
) {
259 struct sockaddr_un un
;
260 struct sockaddr_storage storage
;
266 pa_assert(io
->ifd
>= 0);
267 pa_assert(io
->ofd
== io
->ifd
);
270 if (getsockname(io
->ifd
, &sa
.sa
, &l
) < 0)
273 return sa
.sa
.sa_family
== AF_UNIX
;
276 int pa_iochannel_creds_enable(pa_iochannel
*io
) {
280 pa_assert(io
->ifd
>= 0);
282 if (setsockopt(io
->ifd
, SOL_SOCKET
, SO_PASSCRED
, &t
, sizeof(t
)) < 0) {
283 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno
));
290 ssize_t
pa_iochannel_write_with_creds(pa_iochannel
*io
, const void*data
, size_t l
, const pa_creds
*ucred
) {
296 uint8_t data
[CMSG_SPACE(sizeof(struct ucred
))];
303 pa_assert(io
->ofd
>= 0);
306 iov
.iov_base
= (void*) data
;
310 cmsg
.hdr
.cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
311 cmsg
.hdr
.cmsg_level
= SOL_SOCKET
;
312 cmsg
.hdr
.cmsg_type
= SCM_CREDENTIALS
;
314 u
= (struct ucred
*) CMSG_DATA(&cmsg
.hdr
);
328 mh
.msg_control
= &cmsg
;
329 mh
.msg_controllen
= sizeof(cmsg
);
331 if ((r
= sendmsg(io
->ofd
, &mh
, MSG_NOSIGNAL
)) >= 0) {
332 io
->writable
= io
->hungup
= FALSE
;
339 ssize_t
pa_iochannel_read_with_creds(pa_iochannel
*io
, void*data
, size_t l
, pa_creds
*creds
, pa_bool_t
*creds_valid
) {
345 uint8_t data
[CMSG_SPACE(sizeof(struct ucred
))];
351 pa_assert(io
->ifd
>= 0);
353 pa_assert(creds_valid
);
363 mh
.msg_control
= &cmsg
;
364 mh
.msg_controllen
= sizeof(cmsg
);
366 if ((r
= recvmsg(io
->ifd
, &mh
, 0)) >= 0) {
369 *creds_valid
= FALSE
;
371 for (cmh
= CMSG_FIRSTHDR(&mh
); cmh
; cmh
= CMSG_NXTHDR(&mh
, cmh
)) {
373 if (cmh
->cmsg_level
== SOL_SOCKET
&& cmh
->cmsg_type
== SCM_CREDENTIALS
) {
375 pa_assert(cmh
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)));
376 memcpy(&u
, CMSG_DATA(cmh
), sizeof(struct ucred
));
385 io
->readable
= io
->hungup
= FALSE
;
392 #endif /* HAVE_CREDS */
394 void pa_iochannel_set_callback(pa_iochannel
*io
, pa_iochannel_cb_t _callback
, void *userdata
) {
397 io
->callback
= _callback
;
398 io
->userdata
= userdata
;
401 void pa_iochannel_set_noclose(pa_iochannel
*io
, pa_bool_t b
) {
407 void pa_iochannel_socket_peer_to_string(pa_iochannel
*io
, char*s
, size_t l
) {
412 pa_socket_peer_to_string(io
->ifd
, s
, l
);
415 int pa_iochannel_socket_set_rcvbuf(pa_iochannel
*io
, size_t l
) {
418 return pa_socket_set_rcvbuf(io
->ifd
, l
);
421 int pa_iochannel_socket_set_sndbuf(pa_iochannel
*io
, size_t l
) {
424 return pa_socket_set_sndbuf(io
->ofd
, l
);
427 pa_mainloop_api
* pa_iochannel_get_mainloop_api(pa_iochannel
*io
) {
433 int pa_iochannel_get_recv_fd(pa_iochannel
*io
) {
439 int pa_iochannel_get_send_fd(pa_iochannel
*io
) {
445 pa_bool_t
pa_iochannel_socket_is_local(pa_iochannel
*io
) {
448 if (pa_socket_is_local(io
->ifd
))
451 if (io
->ifd
!= io
->ofd
)
452 if (pa_socket_is_local(io
->ofd
))