]> code.delx.au - pulseaudio/blob - src/pulsecore/iochannel.c
fix two alignment issues found by the debian buildd gcc on sparc
[pulseaudio] / src / pulsecore / iochannel.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
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.
13
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.
18
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
22 USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <errno.h>
33
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 #ifdef HAVE_SYS_UN_H
38 #include <sys/un.h>
39 #endif
40
41 #include "winsock.h"
42
43 #include <pulse/xmalloc.h>
44
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>
50
51 #include "iochannel.h"
52
53 struct pa_iochannel {
54 int ifd, ofd;
55 int ifd_type, ofd_type;
56 pa_mainloop_api* mainloop;
57
58 pa_iochannel_cb_t callback;
59 void*userdata;
60
61 pa_bool_t readable;
62 pa_bool_t writable;
63 pa_bool_t hungup;
64
65 pa_bool_t no_close;
66
67 pa_io_event* input_event, *output_event;
68 };
69
70 static void enable_mainloop_sources(pa_iochannel *io) {
71 pa_assert(io);
72
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);
76
77 if (!io->readable)
78 f |= PA_IO_EVENT_INPUT;
79 if (!io->writable)
80 f |= PA_IO_EVENT_OUTPUT;
81
82 io->mainloop->io_enable(io->input_event, f);
83 } else {
84 if (io->input_event)
85 io->mainloop->io_enable(io->input_event, io->readable ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT);
86 if (io->output_event)
87 io->mainloop->io_enable(io->output_event, io->writable ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT);
88 }
89 }
90
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;
94
95 pa_assert(m);
96 pa_assert(e);
97 pa_assert(fd >= 0);
98 pa_assert(userdata);
99
100 if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
101 io->hungup = TRUE;
102 changed = TRUE;
103 }
104
105 if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
106 io->readable = TRUE;
107 changed = TRUE;
108 pa_assert(e == io->input_event);
109 }
110
111 if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
112 io->writable = TRUE;
113 changed = TRUE;
114 pa_assert(e == io->output_event);
115 }
116
117 if (changed) {
118 enable_mainloop_sources(io);
119
120 if (io->callback)
121 io->callback(io, io->userdata);
122 }
123 }
124
125 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
126 pa_iochannel *io;
127
128 pa_assert(m);
129 pa_assert(ifd >= 0 || ofd >= 0);
130
131 io = pa_xnew(pa_iochannel, 1);
132 io->ifd = ifd;
133 io->ofd = ofd;
134 io->ifd_type = io->ofd_type = 0;
135 io->mainloop = m;
136
137 io->userdata = NULL;
138 io->callback = NULL;
139 io->readable = FALSE;
140 io->writable = FALSE;
141 io->hungup = FALSE;
142 io->no_close = FALSE;
143
144 io->input_event = io->output_event = NULL;
145
146 if (ifd == ofd) {
147 pa_assert(ifd >= 0);
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);
150 } else {
151
152 if (ifd >= 0) {
153 pa_make_fd_nonblock(io->ifd);
154 io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io);
155 }
156
157 if (ofd >= 0) {
158 pa_make_fd_nonblock(io->ofd);
159 io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io);
160 }
161 }
162
163 return io;
164 }
165
166 void pa_iochannel_free(pa_iochannel*io) {
167 pa_assert(io);
168
169 if (io->input_event)
170 io->mainloop->io_free(io->input_event);
171
172 if (io->output_event && (io->output_event != io->input_event))
173 io->mainloop->io_free(io->output_event);
174
175 if (!io->no_close) {
176 if (io->ifd >= 0)
177 pa_close(io->ifd);
178 if (io->ofd >= 0 && io->ofd != io->ifd)
179 pa_close(io->ofd);
180 }
181
182 pa_xfree(io);
183 }
184
185 pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) {
186 pa_assert(io);
187
188 return io->readable || io->hungup;
189 }
190
191 pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) {
192 pa_assert(io);
193
194 return io->writable && !io->hungup;
195 }
196
197 pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) {
198 pa_assert(io);
199
200 return io->hungup;
201 }
202
203 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
204 ssize_t r;
205
206 pa_assert(io);
207 pa_assert(data);
208 pa_assert(l);
209 pa_assert(io->ofd >= 0);
210
211 if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) {
212 io->writable = FALSE;
213 enable_mainloop_sources(io);
214 }
215
216 return r;
217 }
218
219 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
220 ssize_t r;
221
222 pa_assert(io);
223 pa_assert(data);
224 pa_assert(io->ifd >= 0);
225
226 if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
227 io->readable = FALSE;
228 enable_mainloop_sources(io);
229 }
230
231 return r;
232 }
233
234 #ifdef HAVE_CREDS
235
236 pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) {
237 struct sockaddr_un sa;
238 socklen_t l;
239
240 pa_assert(io);
241 pa_assert(io->ifd >= 0);
242 pa_assert(io->ofd == io->ifd);
243
244 l = sizeof(sa);
245
246 if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0)
247 return 0;
248
249 return sa.sun_family == AF_UNIX;
250 }
251
252 int pa_iochannel_creds_enable(pa_iochannel *io) {
253 int t = 1;
254
255 pa_assert(io);
256 pa_assert(io->ifd >= 0);
257
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));
260 return -1;
261 }
262
263 return 0;
264 }
265
266 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
267 ssize_t r;
268 struct msghdr mh;
269 struct iovec iov;
270 union {
271 struct cmsghdr hdr;
272 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
273 } cmsg;
274 struct ucred *u;
275
276 pa_assert(io);
277 pa_assert(data);
278 pa_assert(l);
279 pa_assert(io->ofd >= 0);
280
281 memset(&iov, 0, sizeof(iov));
282 iov.iov_base = (void*) data;
283 iov.iov_len = l;
284
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;
289
290 u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
291
292 u->pid = getpid();
293 if (ucred) {
294 u->uid = ucred->uid;
295 u->gid = ucred->gid;
296 } else {
297 u->uid = getuid();
298 u->gid = getgid();
299 }
300
301 memset(&mh, 0, sizeof(mh));
302 mh.msg_name = NULL;
303 mh.msg_namelen = 0;
304 mh.msg_iov = &iov;
305 mh.msg_iovlen = 1;
306 mh.msg_control = &cmsg;
307 mh.msg_controllen = sizeof(cmsg);
308 mh.msg_flags = 0;
309
310 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
311 io->writable = FALSE;
312 enable_mainloop_sources(io);
313 }
314
315 return r;
316 }
317
318 ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, pa_bool_t *creds_valid) {
319 ssize_t r;
320 struct msghdr mh;
321 struct iovec iov;
322 union {
323 struct cmsghdr hdr;
324 uint8_t data[CMSG_SPACE(sizeof(struct ucred))];
325 } cmsg;
326
327 pa_assert(io);
328 pa_assert(data);
329 pa_assert(l);
330 pa_assert(io->ifd >= 0);
331 pa_assert(creds);
332 pa_assert(creds_valid);
333
334 memset(&iov, 0, sizeof(iov));
335 iov.iov_base = data;
336 iov.iov_len = l;
337
338 memset(&cmsg, 0, sizeof(cmsg));
339
340 memset(&mh, 0, sizeof(mh));
341 mh.msg_name = NULL;
342 mh.msg_namelen = 0;
343 mh.msg_iov = &iov;
344 mh.msg_iovlen = 1;
345 mh.msg_control = &cmsg;
346 mh.msg_controllen = sizeof(cmsg);
347 mh.msg_flags = 0;
348
349 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
350 struct cmsghdr *cmh;
351
352 *creds_valid = 0;
353
354 for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) {
355
356 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) {
357 struct ucred u;
358 pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
359 memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred));
360
361 creds->gid = u.gid;
362 creds->uid = u.uid;
363 *creds_valid = TRUE;
364 break;
365 }
366 }
367
368 io->readable = FALSE;
369 enable_mainloop_sources(io);
370 }
371
372 return r;
373 }
374
375 #endif /* HAVE_CREDS */
376
377 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
378 pa_assert(io);
379
380 io->callback = _callback;
381 io->userdata = userdata;
382 }
383
384 void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) {
385 pa_assert(io);
386
387 io->no_close = !!b;
388 }
389
390 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
391 pa_assert(io);
392 pa_assert(s);
393 pa_assert(l);
394
395 pa_socket_peer_to_string(io->ifd, s, l);
396 }
397
398 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
399 pa_assert(io);
400
401 return pa_socket_set_rcvbuf(io->ifd, l);
402 }
403
404 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
405 pa_assert(io);
406
407 return pa_socket_set_sndbuf(io->ofd, l);
408 }
409
410 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
411 pa_assert(io);
412
413 return io->mainloop;
414 }
415
416 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
417 pa_assert(io);
418
419 return io->ifd;
420 }
421
422 int pa_iochannel_get_send_fd(pa_iochannel *io) {
423 pa_assert(io);
424
425 return io->ofd;
426 }