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