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
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
41 #include <pulse/xmalloc.h>
43 #include <pulsecore/core-error.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/socket-util.h>
46 #include <pulsecore/log.h>
47 #include <pulsecore/macro.h>
49 #include "iochannel.h"
53 int ifd_type
, ofd_type
;
54 pa_mainloop_api
* mainloop
;
56 pa_iochannel_cb_t callback
;
65 pa_io_event
* input_event
, *output_event
;
68 static void enable_mainloop_sources(pa_iochannel
*io
) {
71 if (io
->input_event
== io
->output_event
&& io
->input_event
) {
72 pa_io_event_flags_t f
= PA_IO_EVENT_NULL
;
73 pa_assert(io
->input_event
);
76 f
|= PA_IO_EVENT_INPUT
;
78 f
|= PA_IO_EVENT_OUTPUT
;
80 io
->mainloop
->io_enable(io
->input_event
, f
);
83 io
->mainloop
->io_enable(io
->input_event
, io
->readable
? PA_IO_EVENT_NULL
: PA_IO_EVENT_INPUT
);
85 io
->mainloop
->io_enable(io
->output_event
, io
->writable
? PA_IO_EVENT_NULL
: PA_IO_EVENT_OUTPUT
);
89 static void callback(pa_mainloop_api
* m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
90 pa_iochannel
*io
= userdata
;
91 pa_bool_t changed
= FALSE
;
98 if ((f
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
)) && !io
->hungup
) {
103 if ((f
& PA_IO_EVENT_INPUT
) && !io
->readable
) {
106 pa_assert(e
== io
->input_event
);
109 if ((f
& PA_IO_EVENT_OUTPUT
) && !io
->writable
) {
112 pa_assert(e
== io
->output_event
);
116 enable_mainloop_sources(io
);
119 io
->callback(io
, io
->userdata
);
123 pa_iochannel
* pa_iochannel_new(pa_mainloop_api
*m
, int ifd
, int ofd
) {
127 pa_assert(ifd
>= 0 || ofd
>= 0);
129 io
= pa_xnew(pa_iochannel
, 1);
132 io
->ifd_type
= io
->ofd_type
= 0;
137 io
->readable
= FALSE
;
138 io
->writable
= FALSE
;
140 io
->no_close
= FALSE
;
142 io
->input_event
= io
->output_event
= NULL
;
146 pa_make_fd_nonblock(io
->ifd
);
147 io
->input_event
= io
->output_event
= m
->io_new(m
, ifd
, PA_IO_EVENT_INPUT
|PA_IO_EVENT_OUTPUT
, callback
, io
);
151 pa_make_fd_nonblock(io
->ifd
);
152 io
->input_event
= m
->io_new(m
, ifd
, PA_IO_EVENT_INPUT
, callback
, io
);
156 pa_make_fd_nonblock(io
->ofd
);
157 io
->output_event
= m
->io_new(m
, ofd
, PA_IO_EVENT_OUTPUT
, callback
, io
);
164 void pa_iochannel_free(pa_iochannel
*io
) {
168 io
->mainloop
->io_free(io
->input_event
);
170 if (io
->output_event
&& (io
->output_event
!= io
->input_event
))
171 io
->mainloop
->io_free(io
->output_event
);
176 if (io
->ofd
>= 0 && io
->ofd
!= io
->ifd
)
183 pa_bool_t
pa_iochannel_is_readable(pa_iochannel
*io
) {
186 return io
->readable
|| io
->hungup
;
189 pa_bool_t
pa_iochannel_is_writable(pa_iochannel
*io
) {
192 return io
->writable
&& !io
->hungup
;
195 pa_bool_t
pa_iochannel_is_hungup(pa_iochannel
*io
) {
201 ssize_t
pa_iochannel_write(pa_iochannel
*io
, const void*data
, size_t l
) {
207 pa_assert(io
->ofd
>= 0);
209 if ((r
= pa_write(io
->ofd
, data
, l
, &io
->ofd_type
)) >= 0) {
210 io
->writable
= FALSE
;
211 enable_mainloop_sources(io
);
217 ssize_t
pa_iochannel_read(pa_iochannel
*io
, void*data
, size_t l
) {
222 pa_assert(io
->ifd
>= 0);
224 if ((r
= pa_read(io
->ifd
, data
, l
, &io
->ifd_type
)) >= 0) {
225 io
->readable
= FALSE
;
226 enable_mainloop_sources(io
);
234 pa_bool_t
pa_iochannel_creds_supported(pa_iochannel
*io
) {
235 struct sockaddr_un sa
;
239 pa_assert(io
->ifd
>= 0);
240 pa_assert(io
->ofd
== io
->ifd
);
244 if (getsockname(io
->ifd
, (struct sockaddr
*) &sa
, &l
) < 0)
247 return sa
.sun_family
== AF_UNIX
;
250 int pa_iochannel_creds_enable(pa_iochannel
*io
) {
254 pa_assert(io
->ifd
>= 0);
256 if (setsockopt(io
->ifd
, SOL_SOCKET
, SO_PASSCRED
, &t
, sizeof(t
)) < 0) {
257 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno
));
264 ssize_t
pa_iochannel_write_with_creds(pa_iochannel
*io
, const void*data
, size_t l
, const pa_creds
*ucred
) {
270 uint8_t data
[CMSG_SPACE(sizeof(struct ucred
))];
277 pa_assert(io
->ofd
>= 0);
279 memset(&iov
, 0, sizeof(iov
));
280 iov
.iov_base
= (void*) data
;
283 memset(&cmsg
, 0, sizeof(cmsg
));
284 cmsg
.hdr
.cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
285 cmsg
.hdr
.cmsg_level
= SOL_SOCKET
;
286 cmsg
.hdr
.cmsg_type
= SCM_CREDENTIALS
;
288 u
= (struct ucred
*) CMSG_DATA(&cmsg
.hdr
);
299 memset(&mh
, 0, sizeof(mh
));
304 mh
.msg_control
= &cmsg
;
305 mh
.msg_controllen
= sizeof(cmsg
);
308 if ((r
= sendmsg(io
->ofd
, &mh
, MSG_NOSIGNAL
)) >= 0) {
309 io
->writable
= FALSE
;
310 enable_mainloop_sources(io
);
316 ssize_t
pa_iochannel_read_with_creds(pa_iochannel
*io
, void*data
, size_t l
, pa_creds
*creds
, pa_bool_t
*creds_valid
) {
322 uint8_t data
[CMSG_SPACE(sizeof(struct ucred
))];
328 pa_assert(io
->ifd
>= 0);
330 pa_assert(creds_valid
);
332 memset(&iov
, 0, sizeof(iov
));
336 memset(&cmsg
, 0, sizeof(cmsg
));
338 memset(&mh
, 0, sizeof(mh
));
343 mh
.msg_control
= &cmsg
;
344 mh
.msg_controllen
= sizeof(cmsg
);
347 if ((r
= recvmsg(io
->ifd
, &mh
, 0)) >= 0) {
352 for (cmh
= CMSG_FIRSTHDR(&mh
); cmh
; cmh
= CMSG_NXTHDR(&mh
, cmh
)) {
354 if (cmh
->cmsg_level
== SOL_SOCKET
&& cmh
->cmsg_type
== SCM_CREDENTIALS
) {
356 pa_assert(cmh
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)));
357 memcpy(&u
, CMSG_DATA(cmh
), sizeof(struct ucred
));
366 io
->readable
= FALSE
;
367 enable_mainloop_sources(io
);
373 #endif /* HAVE_CREDS */
375 void pa_iochannel_set_callback(pa_iochannel
*io
, pa_iochannel_cb_t _callback
, void *userdata
) {
378 io
->callback
= _callback
;
379 io
->userdata
= userdata
;
382 void pa_iochannel_set_noclose(pa_iochannel
*io
, pa_bool_t b
) {
388 void pa_iochannel_socket_peer_to_string(pa_iochannel
*io
, char*s
, size_t l
) {
393 pa_socket_peer_to_string(io
->ifd
, s
, l
);
396 int pa_iochannel_socket_set_rcvbuf(pa_iochannel
*io
, size_t l
) {
399 return pa_socket_set_rcvbuf(io
->ifd
, l
);
402 int pa_iochannel_socket_set_sndbuf(pa_iochannel
*io
, size_t l
) {
405 return pa_socket_set_sndbuf(io
->ofd
, l
);
408 pa_mainloop_api
* pa_iochannel_get_mainloop_api(pa_iochannel
*io
) {
414 int pa_iochannel_get_recv_fd(pa_iochannel
*io
) {
420 int pa_iochannel_get_send_fd(pa_iochannel
*io
) {
426 pa_bool_t
pa_iochannel_socket_is_local(pa_iochannel
*io
) {
429 if (pa_socket_is_local(io
->ifd
))
432 if (io
->ifd
!= io
->ofd
)
433 if (pa_socket_is_local(io
->ofd
))