4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as
11 published by the Free Software Foundation; either version 2.1 of the
12 License, or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
43 #include <pulse/xmalloc.h>
45 #include <pulsecore/core-error.h>
46 #include <pulsecore/core-util.h>
47 #include <pulsecore/socket-util.h>
48 #include <pulsecore/log.h>
49 #include <pulsecore/macro.h>
51 #include "iochannel.h"
55 int ifd_type
, ofd_type
;
56 pa_mainloop_api
* mainloop
;
58 pa_iochannel_cb_t callback
;
67 pa_io_event
* input_event
, *output_event
;
70 static void enable_mainloop_sources(pa_iochannel
*io
) {
73 if (io
->input_event
== io
->output_event
&& io
->input_event
) {
74 pa_io_event_flags_t f
= PA_IO_EVENT_NULL
;
75 pa_assert(io
->input_event
);
78 f
|= PA_IO_EVENT_INPUT
;
80 f
|= PA_IO_EVENT_OUTPUT
;
82 io
->mainloop
->io_enable(io
->input_event
, f
);
85 io
->mainloop
->io_enable(io
->input_event
, io
->readable
? PA_IO_EVENT_NULL
: PA_IO_EVENT_INPUT
);
87 io
->mainloop
->io_enable(io
->output_event
, io
->writable
? PA_IO_EVENT_NULL
: PA_IO_EVENT_OUTPUT
);
91 static void callback(pa_mainloop_api
* m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
92 pa_iochannel
*io
= userdata
;
93 pa_bool_t changed
= FALSE
;
100 if ((f
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
)) && !io
->hungup
) {
105 if ((f
& PA_IO_EVENT_INPUT
) && !io
->readable
) {
108 pa_assert(e
== io
->input_event
);
111 if ((f
& PA_IO_EVENT_OUTPUT
) && !io
->writable
) {
114 pa_assert(e
== io
->output_event
);
118 enable_mainloop_sources(io
);
121 io
->callback(io
, io
->userdata
);
125 pa_iochannel
* pa_iochannel_new(pa_mainloop_api
*m
, int ifd
, int ofd
) {
129 pa_assert(ifd
>= 0 || ofd
>= 0);
131 io
= pa_xnew(pa_iochannel
, 1);
134 io
->ifd_type
= io
->ofd_type
= 0;
139 io
->readable
= FALSE
;
140 io
->writable
= FALSE
;
142 io
->no_close
= FALSE
;
144 io
->input_event
= io
->output_event
= NULL
;
148 pa_make_fd_nonblock(io
->ifd
);
149 io
->input_event
= io
->output_event
= m
->io_new(m
, ifd
, PA_IO_EVENT_INPUT
|PA_IO_EVENT_OUTPUT
, callback
, io
);
153 pa_make_fd_nonblock(io
->ifd
);
154 io
->input_event
= m
->io_new(m
, ifd
, PA_IO_EVENT_INPUT
, callback
, io
);
158 pa_make_fd_nonblock(io
->ofd
);
159 io
->output_event
= m
->io_new(m
, ofd
, PA_IO_EVENT_OUTPUT
, callback
, io
);
166 void pa_iochannel_free(pa_iochannel
*io
) {
170 io
->mainloop
->io_free(io
->input_event
);
172 if (io
->output_event
&& (io
->output_event
!= io
->input_event
))
173 io
->mainloop
->io_free(io
->output_event
);
178 if (io
->ofd
>= 0 && io
->ofd
!= io
->ifd
)
185 pa_bool_t
pa_iochannel_is_readable(pa_iochannel
*io
) {
188 return io
->readable
|| io
->hungup
;
191 pa_bool_t
pa_iochannel_is_writable(pa_iochannel
*io
) {
194 return io
->writable
&& !io
->hungup
;
197 pa_bool_t
pa_iochannel_is_hungup(pa_iochannel
*io
) {
203 ssize_t
pa_iochannel_write(pa_iochannel
*io
, const void*data
, size_t l
) {
209 pa_assert(io
->ofd
>= 0);
211 if ((r
= pa_write(io
->ofd
, data
, l
, &io
->ofd_type
)) >= 0) {
212 io
->writable
= FALSE
;
213 enable_mainloop_sources(io
);
219 ssize_t
pa_iochannel_read(pa_iochannel
*io
, void*data
, size_t l
) {
224 pa_assert(io
->ifd
>= 0);
226 if ((r
= pa_read(io
->ifd
, data
, l
, &io
->ifd_type
)) >= 0) {
227 io
->readable
= FALSE
;
228 enable_mainloop_sources(io
);
236 pa_bool_t
pa_iochannel_creds_supported(pa_iochannel
*io
) {
237 struct sockaddr_un sa
;
241 pa_assert(io
->ifd
>= 0);
242 pa_assert(io
->ofd
== io
->ifd
);
246 if (getsockname(io
->ifd
, (struct sockaddr
*) &sa
, &l
) < 0)
249 return sa
.sun_family
== AF_UNIX
;
252 int pa_iochannel_creds_enable(pa_iochannel
*io
) {
256 pa_assert(io
->ifd
>= 0);
258 if (setsockopt(io
->ifd
, SOL_SOCKET
, SO_PASSCRED
, &t
, sizeof(t
)) < 0) {
259 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno
));
266 ssize_t
pa_iochannel_write_with_creds(pa_iochannel
*io
, const void*data
, size_t l
, const pa_creds
*ucred
) {
272 uint8_t data
[CMSG_SPACE(sizeof(struct ucred
))];
279 pa_assert(io
->ofd
>= 0);
281 memset(&iov
, 0, sizeof(iov
));
282 iov
.iov_base
= (void*) data
;
285 memset(&cmsg
, 0, sizeof(cmsg
));
286 cmsg
.hdr
.cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
287 cmsg
.hdr
.cmsg_level
= SOL_SOCKET
;
288 cmsg
.hdr
.cmsg_type
= SCM_CREDENTIALS
;
290 u
= (struct ucred
*) CMSG_DATA(&cmsg
.hdr
);
301 memset(&mh
, 0, sizeof(mh
));
306 mh
.msg_control
= &cmsg
;
307 mh
.msg_controllen
= sizeof(cmsg
);
310 if ((r
= sendmsg(io
->ofd
, &mh
, MSG_NOSIGNAL
)) >= 0) {
311 io
->writable
= FALSE
;
312 enable_mainloop_sources(io
);
318 ssize_t
pa_iochannel_read_with_creds(pa_iochannel
*io
, void*data
, size_t l
, pa_creds
*creds
, pa_bool_t
*creds_valid
) {
324 uint8_t data
[CMSG_SPACE(sizeof(struct ucred
))];
330 pa_assert(io
->ifd
>= 0);
332 pa_assert(creds_valid
);
334 memset(&iov
, 0, sizeof(iov
));
338 memset(&cmsg
, 0, sizeof(cmsg
));
340 memset(&mh
, 0, sizeof(mh
));
345 mh
.msg_control
= &cmsg
;
346 mh
.msg_controllen
= sizeof(cmsg
);
349 if ((r
= recvmsg(io
->ifd
, &mh
, 0)) >= 0) {
354 for (cmh
= CMSG_FIRSTHDR(&mh
); cmh
; cmh
= CMSG_NXTHDR(&mh
, cmh
)) {
356 if (cmh
->cmsg_level
== SOL_SOCKET
&& cmh
->cmsg_type
== SCM_CREDENTIALS
) {
358 pa_assert(cmh
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)));
359 memcpy(&u
, CMSG_DATA(cmh
), sizeof(struct ucred
));
368 io
->readable
= FALSE
;
369 enable_mainloop_sources(io
);
375 #endif /* HAVE_CREDS */
377 void pa_iochannel_set_callback(pa_iochannel
*io
, pa_iochannel_cb_t _callback
, void *userdata
) {
380 io
->callback
= _callback
;
381 io
->userdata
= userdata
;
384 void pa_iochannel_set_noclose(pa_iochannel
*io
, pa_bool_t b
) {
390 void pa_iochannel_socket_peer_to_string(pa_iochannel
*io
, char*s
, size_t l
) {
395 pa_socket_peer_to_string(io
->ifd
, s
, l
);
398 int pa_iochannel_socket_set_rcvbuf(pa_iochannel
*io
, size_t l
) {
401 return pa_socket_set_rcvbuf(io
->ifd
, l
);
404 int pa_iochannel_socket_set_sndbuf(pa_iochannel
*io
, size_t l
) {
407 return pa_socket_set_sndbuf(io
->ofd
, l
);
410 pa_mainloop_api
* pa_iochannel_get_mainloop_api(pa_iochannel
*io
) {
416 int pa_iochannel_get_recv_fd(pa_iochannel
*io
) {
422 int pa_iochannel_get_send_fd(pa_iochannel
*io
) {