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
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
44 #include <pulse/xmalloc.h>
46 #include <pulsecore/core-error.h>
47 #include <pulsecore/core-util.h>
48 #include <pulsecore/socket-util.h>
49 #include <pulsecore/log.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 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
;
100 if ((f
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
)) && !io
->hungup
) {
105 if ((f
& PA_IO_EVENT_INPUT
) && !io
->readable
) {
108 assert(e
== io
->input_event
);
111 if ((f
& PA_IO_EVENT_OUTPUT
) && !io
->writable
) {
114 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 assert(ifd
>= 0 || ofd
>= 0);
131 io
= pa_xnew(pa_iochannel
, 1);
134 io
->ifd_type
= io
->ofd_type
= 0;
144 io
->input_event
= io
->output_event
= NULL
;
148 pa_make_nonblock_fd(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_nonblock_fd(io
->ifd
);
154 io
->input_event
= m
->io_new(m
, ifd
, PA_IO_EVENT_INPUT
, callback
, io
);
158 pa_make_nonblock_fd(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 int pa_iochannel_is_readable(pa_iochannel
*io
) {
188 return io
->readable
|| io
->hungup
;
191 int pa_iochannel_is_writable(pa_iochannel
*io
) {
194 return io
->writable
&& !io
->hungup
;
197 int pa_iochannel_is_hungup(pa_iochannel
*io
) {
203 ssize_t
pa_iochannel_write(pa_iochannel
*io
, const void*data
, size_t l
) {
209 assert(io
->ofd
>= 0);
211 r
= pa_write(io
->ofd
, data
, l
, &io
->ofd_type
);
214 enable_mainloop_sources(io
);
220 ssize_t
pa_iochannel_read(pa_iochannel
*io
, void*data
, size_t l
) {
225 assert(io
->ifd
>= 0);
227 r
= pa_read(io
->ifd
, data
, l
, &io
->ifd_type
);
230 enable_mainloop_sources(io
);
238 int pa_iochannel_creds_supported(pa_iochannel
*io
) {
239 struct sockaddr_un sa
;
243 assert(io
->ifd
>= 0);
244 assert(io
->ofd
== io
->ifd
);
248 if (getsockname(io
->ifd
, (struct sockaddr
*) &sa
, &l
) < 0)
251 return sa
.sun_family
== AF_UNIX
;
254 int pa_iochannel_creds_enable(pa_iochannel
*io
) {
258 assert(io
->ifd
>= 0);
260 if (setsockopt(io
->ifd
, SOL_SOCKET
, SO_PASSCRED
, &t
, sizeof(t
)) < 0) {
261 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno
));
268 ssize_t
pa_iochannel_write_with_creds(pa_iochannel
*io
, const void*data
, size_t l
, const pa_creds
*ucred
) {
272 uint8_t cmsg_data
[CMSG_SPACE(sizeof(struct ucred
))];
274 struct cmsghdr
*cmsg
;
279 assert(io
->ofd
>= 0);
281 memset(&iov
, 0, sizeof(iov
));
282 iov
.iov_base
= (void*) data
;
285 memset(cmsg_data
, 0, sizeof(cmsg_data
));
286 cmsg
= (struct cmsghdr
*) cmsg_data
;
287 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
288 cmsg
->cmsg_level
= SOL_SOCKET
;
289 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
291 u
= (struct ucred
*) CMSG_DATA(cmsg
);
302 memset(&mh
, 0, sizeof(mh
));
307 mh
.msg_control
= cmsg_data
;
308 mh
.msg_controllen
= sizeof(cmsg_data
);
311 if ((r
= sendmsg(io
->ofd
, &mh
, MSG_NOSIGNAL
)) >= 0) {
313 enable_mainloop_sources(io
);
319 ssize_t
pa_iochannel_read_with_creds(pa_iochannel
*io
, void*data
, size_t l
, pa_creds
*creds
, int *creds_valid
) {
323 uint8_t cmsg_data
[CMSG_SPACE(sizeof(struct ucred
))];
328 assert(io
->ifd
>= 0);
332 memset(&iov
, 0, sizeof(iov
));
336 memset(cmsg_data
, 0, sizeof(cmsg_data
));
338 memset(&mh
, 0, sizeof(mh
));
343 mh
.msg_control
= cmsg_data
;
344 mh
.msg_controllen
= sizeof(cmsg_data
);
347 if ((r
= recvmsg(io
->ifd
, &mh
, 0)) >= 0) {
348 struct cmsghdr
*cmsg
;
352 for (cmsg
= CMSG_FIRSTHDR(&mh
); cmsg
; cmsg
= CMSG_NXTHDR(&mh
, cmsg
)) {
354 if (cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_CREDENTIALS
) {
356 assert(cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)));
357 memcpy(&u
, CMSG_DATA(cmsg
), sizeof(struct ucred
));
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
, int 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
) {