]> code.delx.au - pulseaudio/blob - src/pulsecore/iochannel.c
Add copyright notices to all relevant files. (based on svn log)
[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 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 <assert.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <errno.h>
34
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38 #ifdef HAVE_SYS_UN_H
39 #include <sys/un.h>
40 #endif
41
42 #include "winsock.h"
43
44 #include <pulse/xmalloc.h>
45
46 #include <pulsecore/core-error.h>
47 #include <pulsecore/core-util.h>
48 #include <pulsecore/socket-util.h>
49 #include <pulsecore/log.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 int readable;
62 int writable;
63 int hungup;
64
65 int no_close;
66
67 pa_io_event* input_event, *output_event;
68 };
69
70 static void enable_mainloop_sources(pa_iochannel *io) {
71 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 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 int changed = 0;
94
95 assert(m);
96 assert(e);
97 assert(fd >= 0);
98 assert(userdata);
99
100 if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
101 io->hungup = 1;
102 changed = 1;
103 }
104
105 if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
106 io->readable = 1;
107 changed = 1;
108 assert(e == io->input_event);
109 }
110
111 if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
112 io->writable = 1;
113 changed = 1;
114 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 assert(m);
129 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 = 0;
140 io->writable = 0;
141 io->hungup = 0;
142 io->no_close = 0;
143
144 io->input_event = io->output_event = NULL;
145
146 if (ifd == ofd) {
147 assert(ifd >= 0);
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);
150 } else {
151
152 if (ifd >= 0) {
153 pa_make_nonblock_fd(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_nonblock_fd(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 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
178 close(io->ifd);
179 if (io->ofd >= 0 && io->ofd != io->ifd)
180 close(io->ofd);
181 }
182
183 pa_xfree(io);
184 }
185
186 int pa_iochannel_is_readable(pa_iochannel*io) {
187 assert(io);
188
189 return io->readable || io->hungup;
190 }
191
192 int pa_iochannel_is_writable(pa_iochannel*io) {
193 assert(io);
194
195 return io->writable && !io->hungup;
196 }
197
198 int pa_iochannel_is_hungup(pa_iochannel*io) {
199 assert(io);
200
201 return io->hungup;
202 }
203
204 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
205 ssize_t r;
206
207 assert(io);
208 assert(data);
209 assert(l);
210 assert(io->ofd >= 0);
211
212 r = pa_write(io->ofd, data, l, &io->ofd_type);
213 if (r >= 0) {
214 io->writable = 0;
215 enable_mainloop_sources(io);
216 }
217
218 return r;
219 }
220
221 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
222 ssize_t r;
223
224 assert(io);
225 assert(data);
226 assert(io->ifd >= 0);
227
228 r = pa_read(io->ifd, data, l, &io->ifd_type);
229 if (r >= 0) {
230 io->readable = 0;
231 enable_mainloop_sources(io);
232 }
233
234 return r;
235 }
236
237 #ifdef HAVE_CREDS
238
239 int pa_iochannel_creds_supported(pa_iochannel *io) {
240 struct sockaddr_un sa;
241 socklen_t l;
242
243 assert(io);
244 assert(io->ifd >= 0);
245 assert(io->ofd == io->ifd);
246
247 l = sizeof(sa);
248
249 if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0)
250 return 0;
251
252 return sa.sun_family == AF_UNIX;
253 }
254
255 int pa_iochannel_creds_enable(pa_iochannel *io) {
256 int t = 1;
257
258 assert(io);
259 assert(io->ifd >= 0);
260
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));
263 return -1;
264 }
265
266 return 0;
267 }
268
269 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) {
270 ssize_t r;
271 struct msghdr mh;
272 struct iovec iov;
273 uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))];
274 struct ucred *u;
275 struct cmsghdr *cmsg;
276
277 assert(io);
278 assert(data);
279 assert(l);
280 assert(io->ofd >= 0);
281
282 memset(&iov, 0, sizeof(iov));
283 iov.iov_base = (void*) data;
284 iov.iov_len = l;
285
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;
291
292 u = (struct ucred*) CMSG_DATA(cmsg);
293
294 u->pid = getpid();
295 if (ucred) {
296 u->uid = ucred->uid;
297 u->gid = ucred->gid;
298 } else {
299 u->uid = getuid();
300 u->gid = getgid();
301 }
302
303 memset(&mh, 0, sizeof(mh));
304 mh.msg_name = NULL;
305 mh.msg_namelen = 0;
306 mh.msg_iov = &iov;
307 mh.msg_iovlen = 1;
308 mh.msg_control = cmsg_data;
309 mh.msg_controllen = sizeof(cmsg_data);
310 mh.msg_flags = 0;
311
312 if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
313 io->writable = 0;
314 enable_mainloop_sources(io);
315 }
316
317 return r;
318 }
319
320 ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, int *creds_valid) {
321 ssize_t r;
322 struct msghdr mh;
323 struct iovec iov;
324 uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))];
325
326 assert(io);
327 assert(data);
328 assert(l);
329 assert(io->ifd >= 0);
330 assert(creds);
331 assert(creds_valid);
332
333 memset(&iov, 0, sizeof(iov));
334 iov.iov_base = data;
335 iov.iov_len = l;
336
337 memset(cmsg_data, 0, sizeof(cmsg_data));
338
339 memset(&mh, 0, sizeof(mh));
340 mh.msg_name = NULL;
341 mh.msg_namelen = 0;
342 mh.msg_iov = &iov;
343 mh.msg_iovlen = 1;
344 mh.msg_control = cmsg_data;
345 mh.msg_controllen = sizeof(cmsg_data);
346 mh.msg_flags = 0;
347
348 if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) {
349 struct cmsghdr *cmsg;
350
351 *creds_valid = 0;
352
353 for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
354
355 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
356 struct ucred u;
357 assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
358 memcpy(&u, CMSG_DATA(cmsg), sizeof(struct ucred));
359
360 creds->gid = u.gid;
361 creds->uid = u.uid;
362 *creds_valid = 1;
363 break;
364 }
365 }
366
367 io->readable = 0;
368 enable_mainloop_sources(io);
369 }
370
371 return r;
372 }
373
374 #endif /* HAVE_CREDS */
375
376 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
377 assert(io);
378
379 io->callback = _callback;
380 io->userdata = userdata;
381 }
382
383 void pa_iochannel_set_noclose(pa_iochannel*io, int b) {
384 assert(io);
385
386 io->no_close = b;
387 }
388
389 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
390 assert(io);
391 assert(s);
392 assert(l);
393
394 pa_socket_peer_to_string(io->ifd, s, l);
395 }
396
397 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
398 assert(io);
399
400 return pa_socket_set_rcvbuf(io->ifd, l);
401 }
402
403 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
404 assert(io);
405
406 return pa_socket_set_sndbuf(io->ofd, l);
407 }
408
409 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
410 assert(io);
411
412 return io->mainloop;
413 }
414
415 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
416 assert(io);
417
418 return io->ifd;
419 }