4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 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
);
179 if (io
->ofd
>= 0 && io
->ofd
!= io
->ifd
)
186 int pa_iochannel_is_readable(pa_iochannel
*io
) {
189 return io
->readable
|| io
->hungup
;
192 int pa_iochannel_is_writable(pa_iochannel
*io
) {
195 return io
->writable
&& !io
->hungup
;
198 int pa_iochannel_is_hungup(pa_iochannel
*io
) {
204 ssize_t
pa_iochannel_write(pa_iochannel
*io
, const void*data
, size_t l
) {
210 assert(io
->ofd
>= 0);
212 r
= pa_write(io
->ofd
, data
, l
, &io
->ofd_type
);
215 enable_mainloop_sources(io
);
221 ssize_t
pa_iochannel_read(pa_iochannel
*io
, void*data
, size_t l
) {
226 assert(io
->ifd
>= 0);
228 r
= pa_read(io
->ifd
, data
, l
, &io
->ifd_type
);
231 enable_mainloop_sources(io
);
239 int pa_iochannel_creds_supported(pa_iochannel
*io
) {
240 struct sockaddr_un sa
;
244 assert(io
->ifd
>= 0);
245 assert(io
->ofd
== io
->ifd
);
249 if (getsockname(io
->ifd
, (struct sockaddr
*) &sa
, &l
) < 0)
252 return sa
.sun_family
== AF_UNIX
;
255 int pa_iochannel_creds_enable(pa_iochannel
*io
) {
259 assert(io
->ifd
>= 0);
261 if (setsockopt(io
->ifd
, SOL_SOCKET
, SO_PASSCRED
, &t
, sizeof(t
)) < 0) {
262 pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno
));
269 ssize_t
pa_iochannel_write_with_creds(pa_iochannel
*io
, const void*data
, size_t l
, const pa_creds
*ucred
) {
273 uint8_t cmsg_data
[CMSG_SPACE(sizeof(struct ucred
))];
275 struct cmsghdr
*cmsg
;
280 assert(io
->ofd
>= 0);
282 memset(&iov
, 0, sizeof(iov
));
283 iov
.iov_base
= (void*) data
;
286 memset(cmsg_data
, 0, sizeof(cmsg_data
));
287 cmsg
= (struct cmsghdr
*) cmsg_data
;
288 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
289 cmsg
->cmsg_level
= SOL_SOCKET
;
290 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
292 u
= (struct ucred
*) CMSG_DATA(cmsg
);
303 memset(&mh
, 0, sizeof(mh
));
308 mh
.msg_control
= cmsg_data
;
309 mh
.msg_controllen
= sizeof(cmsg_data
);
312 if ((r
= sendmsg(io
->ofd
, &mh
, MSG_NOSIGNAL
)) >= 0) {
314 enable_mainloop_sources(io
);
320 ssize_t
pa_iochannel_read_with_creds(pa_iochannel
*io
, void*data
, size_t l
, pa_creds
*creds
, int *creds_valid
) {
324 uint8_t cmsg_data
[CMSG_SPACE(sizeof(struct ucred
))];
329 assert(io
->ifd
>= 0);
333 memset(&iov
, 0, sizeof(iov
));
337 memset(cmsg_data
, 0, sizeof(cmsg_data
));
339 memset(&mh
, 0, sizeof(mh
));
344 mh
.msg_control
= cmsg_data
;
345 mh
.msg_controllen
= sizeof(cmsg_data
);
348 if ((r
= recvmsg(io
->ifd
, &mh
, 0)) >= 0) {
349 struct cmsghdr
*cmsg
;
353 for (cmsg
= CMSG_FIRSTHDR(&mh
); cmsg
; cmsg
= CMSG_NXTHDR(&mh
, cmsg
)) {
355 if (cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_CREDENTIALS
) {
357 assert(cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)));
358 memcpy(&u
, CMSG_DATA(cmsg
), sizeof(struct ucred
));
368 enable_mainloop_sources(io
);
374 #endif /* HAVE_CREDS */
376 void pa_iochannel_set_callback(pa_iochannel
*io
, pa_iochannel_cb_t _callback
, void *userdata
) {
379 io
->callback
= _callback
;
380 io
->userdata
= userdata
;
383 void pa_iochannel_set_noclose(pa_iochannel
*io
, int b
) {
389 void pa_iochannel_socket_peer_to_string(pa_iochannel
*io
, char*s
, size_t l
) {
394 pa_socket_peer_to_string(io
->ifd
, s
, l
);
397 int pa_iochannel_socket_set_rcvbuf(pa_iochannel
*io
, size_t l
) {
400 return pa_socket_set_rcvbuf(io
->ifd
, l
);
403 int pa_iochannel_socket_set_sndbuf(pa_iochannel
*io
, size_t l
) {
406 return pa_socket_set_sndbuf(io
->ofd
, l
);
409 pa_mainloop_api
* pa_iochannel_get_mainloop_api(pa_iochannel
*io
) {
415 int pa_iochannel_get_recv_fd(pa_iochannel
*io
) {