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