Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : :
6 : : PulseAudio is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU Lesser General Public License as published
8 : : by the Free Software Foundation; either version 2.1 of the License,
9 : : or (at your option) any later version.
10 : :
11 : : PulseAudio is distributed in the hope that it will be useful, but
12 : : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU Lesser General Public License
17 : : along with PulseAudio; if not, write to the Free Software
18 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 : : USA.
20 : : ***/
21 : :
22 : : #ifdef HAVE_CONFIG_H
23 : : #include <config.h>
24 : : #endif
25 : :
26 : : #include <errno.h>
27 : : #include <stdio.h>
28 : : #include <stdlib.h>
29 : : #include <string.h>
30 : :
31 : : #include <pulse/xmalloc.h>
32 : :
33 : : #include <pulsecore/socket.h>
34 : : #include <pulsecore/core-error.h>
35 : : #include <pulsecore/core-util.h>
36 : : #include <pulsecore/log.h>
37 : : #include <pulsecore/macro.h>
38 : : #include <pulsecore/refcnt.h>
39 : :
40 : : #include "ioline.h"
41 : :
42 : : #define BUFFER_LIMIT (64*1024)
43 : : #define READ_SIZE (1024)
44 : :
45 : : struct pa_ioline {
46 : : PA_REFCNT_DECLARE;
47 : :
48 : : pa_iochannel *io;
49 : : pa_defer_event *defer_event;
50 : : pa_mainloop_api *mainloop;
51 : :
52 : : char *wbuf;
53 : : size_t wbuf_length, wbuf_index, wbuf_valid_length;
54 : :
55 : : char *rbuf;
56 : : size_t rbuf_length, rbuf_index, rbuf_valid_length;
57 : :
58 : : pa_ioline_cb_t callback;
59 : : void *userdata;
60 : :
61 : : pa_ioline_drain_cb_t drain_callback;
62 : : void *drain_userdata;
63 : :
64 : : pa_bool_t dead:1;
65 : : pa_bool_t defer_close:1;
66 : : };
67 : :
68 : : static void io_callback(pa_iochannel*io, void *userdata);
69 : : static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata);
70 : :
71 : 0 : pa_ioline* pa_ioline_new(pa_iochannel *io) {
72 : : pa_ioline *l;
73 [ # # ]: 0 : pa_assert(io);
74 : :
75 : 0 : l = pa_xnew(pa_ioline, 1);
76 : 0 : PA_REFCNT_INIT(l);
77 : 0 : l->io = io;
78 : :
79 : 0 : l->wbuf = NULL;
80 : 0 : l->wbuf_length = l->wbuf_index = l->wbuf_valid_length = 0;
81 : :
82 : 0 : l->rbuf = NULL;
83 : 0 : l->rbuf_length = l->rbuf_index = l->rbuf_valid_length = 0;
84 : :
85 : 0 : l->callback = NULL;
86 : 0 : l->userdata = NULL;
87 : :
88 : 0 : l->drain_callback = NULL;
89 : 0 : l->drain_userdata = NULL;
90 : :
91 : 0 : l->mainloop = pa_iochannel_get_mainloop_api(io);
92 : :
93 : 0 : l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l);
94 : 0 : l->mainloop->defer_enable(l->defer_event, 0);
95 : :
96 : 0 : l->dead = FALSE;
97 : 0 : l->defer_close = FALSE;
98 : :
99 : 0 : pa_iochannel_set_callback(io, io_callback, l);
100 : :
101 : 0 : return l;
102 : : }
103 : :
104 : : static void ioline_free(pa_ioline *l) {
105 [ # # ]: 0 : pa_assert(l);
106 : :
107 [ # # ]: 0 : if (l->io)
108 : 0 : pa_iochannel_free(l->io);
109 : :
110 [ # # ]: 0 : if (l->defer_event)
111 : 0 : l->mainloop->defer_free(l->defer_event);
112 : :
113 : 0 : pa_xfree(l->wbuf);
114 : 0 : pa_xfree(l->rbuf);
115 : 0 : pa_xfree(l);
116 : : }
117 : :
118 : 0 : void pa_ioline_unref(pa_ioline *l) {
119 [ # # ]: 0 : pa_assert(l);
120 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
121 : :
122 [ # # ]: 0 : if (PA_REFCNT_DEC(l) <= 0)
123 : : ioline_free(l);
124 : 0 : }
125 : :
126 : 0 : pa_ioline* pa_ioline_ref(pa_ioline *l) {
127 [ # # ]: 0 : pa_assert(l);
128 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
129 : :
130 : 0 : PA_REFCNT_INC(l);
131 : 0 : return l;
132 : : }
133 : :
134 : 0 : void pa_ioline_close(pa_ioline *l) {
135 [ # # ]: 0 : pa_assert(l);
136 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
137 : :
138 : 0 : l->dead = TRUE;
139 : :
140 [ # # ]: 0 : if (l->io) {
141 : 0 : pa_iochannel_free(l->io);
142 : 0 : l->io = NULL;
143 : : }
144 : :
145 [ # # ]: 0 : if (l->defer_event) {
146 : 0 : l->mainloop->defer_free(l->defer_event);
147 : 0 : l->defer_event = NULL;
148 : : }
149 : :
150 [ # # ]: 0 : if (l->callback)
151 : 0 : l->callback = NULL;
152 : 0 : }
153 : :
154 : 0 : void pa_ioline_puts(pa_ioline *l, const char *c) {
155 : : size_t len;
156 : :
157 [ # # ]: 0 : pa_assert(l);
158 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
159 [ # # ]: 0 : pa_assert(c);
160 : :
161 [ # # ]: 0 : if (l->dead)
162 : 0 : return;
163 : :
164 : 0 : len = strlen(c);
165 [ # # ]: 0 : if (len > BUFFER_LIMIT - l->wbuf_valid_length)
166 : 0 : len = BUFFER_LIMIT - l->wbuf_valid_length;
167 : :
168 [ # # ]: 0 : if (len) {
169 [ # # ]: 0 : pa_assert(l->wbuf_length >= l->wbuf_valid_length);
170 : :
171 : : /* In case the allocated buffer is too small, enlarge it. */
172 [ # # ]: 0 : if (l->wbuf_valid_length + len > l->wbuf_length) {
173 : 0 : size_t n = l->wbuf_valid_length+len;
174 : 0 : char *new = pa_xnew(char, (unsigned) n);
175 : :
176 [ # # ]: 0 : if (l->wbuf) {
177 : 0 : memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length);
178 : 0 : pa_xfree(l->wbuf);
179 : : }
180 : :
181 : 0 : l->wbuf = new;
182 : 0 : l->wbuf_length = n;
183 : 0 : l->wbuf_index = 0;
184 [ # # ]: 0 : } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) {
185 : :
186 : : /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */
187 : 0 : memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length);
188 : 0 : l->wbuf_index = 0;
189 : : }
190 : :
191 [ # # ]: 0 : pa_assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length);
192 : :
193 : : /* Append the new string */
194 : 0 : memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len);
195 : 0 : l->wbuf_valid_length += len;
196 : :
197 : 0 : l->mainloop->defer_enable(l->defer_event, 1);
198 : : }
199 : : }
200 : :
201 : 0 : void pa_ioline_set_callback(pa_ioline*l, pa_ioline_cb_t callback, void *userdata) {
202 [ # # ]: 0 : pa_assert(l);
203 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
204 : :
205 [ # # ]: 0 : if (l->dead)
206 : 0 : return;
207 : :
208 : 0 : l->callback = callback;
209 : 0 : l->userdata = userdata;
210 : : }
211 : :
212 : 0 : void pa_ioline_set_drain_callback(pa_ioline*l, pa_ioline_drain_cb_t callback, void *userdata) {
213 [ # # ]: 0 : pa_assert(l);
214 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
215 : :
216 [ # # ]: 0 : if (l->dead)
217 : 0 : return;
218 : :
219 : 0 : l->drain_callback = callback;
220 : 0 : l->drain_userdata = userdata;
221 : : }
222 : :
223 : 0 : static void failure(pa_ioline *l, pa_bool_t process_leftover) {
224 [ # # ]: 0 : pa_assert(l);
225 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
226 [ # # ]: 0 : pa_assert(!l->dead);
227 : :
228 [ # # ][ # # ]: 0 : if (process_leftover && l->rbuf_valid_length > 0) {
229 : : /* Pass the last missing bit to the client */
230 : :
231 [ # # ]: 0 : if (l->callback) {
232 : 0 : char *p = pa_xstrndup(l->rbuf+l->rbuf_index, l->rbuf_valid_length);
233 : 0 : l->callback(l, p, l->userdata);
234 : 0 : pa_xfree(p);
235 : : }
236 : : }
237 : :
238 [ # # ]: 0 : if (l->callback) {
239 : 0 : l->callback(l, NULL, l->userdata);
240 : 0 : l->callback = NULL;
241 : : }
242 : :
243 : 0 : pa_ioline_close(l);
244 : 0 : }
245 : :
246 : 0 : static void scan_for_lines(pa_ioline *l, size_t skip) {
247 [ # # ]: 0 : pa_assert(l);
248 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
249 [ # # ]: 0 : pa_assert(skip < l->rbuf_valid_length);
250 : :
251 [ # # ][ # # ]: 0 : while (!l->dead && l->rbuf_valid_length > skip) {
252 : : char *e, *p;
253 : : size_t m;
254 : :
255 [ # # ]: 0 : if (!(e = memchr(l->rbuf + l->rbuf_index + skip, '\n', l->rbuf_valid_length - skip)))
256 : : break;
257 : :
258 : 0 : *e = 0;
259 : :
260 : 0 : p = l->rbuf + l->rbuf_index;
261 : 0 : m = strlen(p);
262 : :
263 : 0 : l->rbuf_index += m+1;
264 : 0 : l->rbuf_valid_length -= m+1;
265 : :
266 : : /* A shortcut for the next time */
267 [ # # ]: 0 : if (l->rbuf_valid_length == 0)
268 : 0 : l->rbuf_index = 0;
269 : :
270 [ # # ]: 0 : if (l->callback)
271 : 0 : l->callback(l, pa_strip_nl(p), l->userdata);
272 : :
273 : : skip = 0;
274 : : }
275 : :
276 : : /* If the buffer became too large and still no newline was found, drop it. */
277 [ # # ]: 0 : if (l->rbuf_valid_length >= BUFFER_LIMIT)
278 : 0 : l->rbuf_index = l->rbuf_valid_length = 0;
279 : 0 : }
280 : :
281 : : static int do_write(pa_ioline *l);
282 : :
283 : 0 : static int do_read(pa_ioline *l) {
284 [ # # ]: 0 : pa_assert(l);
285 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
286 : :
287 [ # # ][ # # ]: 0 : while (l->io && !l->dead && pa_iochannel_is_readable(l->io)) {
[ # # ]
288 : : ssize_t r;
289 : : size_t len;
290 : :
291 : 0 : len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
292 : :
293 : : /* Check if we have to enlarge the read buffer */
294 [ # # ]: 0 : if (len < READ_SIZE) {
295 : 0 : size_t n = l->rbuf_valid_length+READ_SIZE;
296 : :
297 [ # # ]: 0 : if (n >= BUFFER_LIMIT)
298 : 0 : n = BUFFER_LIMIT;
299 : :
300 [ # # ]: 0 : if (l->rbuf_length >= n) {
301 : : /* The current buffer is large enough, let's just move the data to the front */
302 [ # # ]: 0 : if (l->rbuf_valid_length)
303 : 0 : memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length);
304 : : } else {
305 : : /* Enlarge the buffer */
306 : 0 : char *new = pa_xnew(char, (unsigned) n);
307 [ # # ]: 0 : if (l->rbuf_valid_length)
308 : 0 : memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length);
309 : 0 : pa_xfree(l->rbuf);
310 : 0 : l->rbuf = new;
311 : 0 : l->rbuf_length = n;
312 : : }
313 : :
314 : 0 : l->rbuf_index = 0;
315 : : }
316 : :
317 : 0 : len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
318 : :
319 [ # # ]: 0 : pa_assert(len >= READ_SIZE);
320 : :
321 : : /* Read some data */
322 [ # # ]: 0 : if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) {
323 : :
324 [ # # ][ # # ]: 0 : if (r < 0 && errno == EAGAIN)
325 : : return 0;
326 : :
327 [ # # ][ # # ]: 0 : if (r < 0 && errno != ECONNRESET) {
328 : 0 : pa_log("read(): %s", pa_cstrerror(errno));
329 : 0 : failure(l, FALSE);
330 : : } else
331 : 0 : failure(l, TRUE);
332 : :
333 : : return -1;
334 : : }
335 : :
336 : 0 : l->rbuf_valid_length += (size_t) r;
337 : :
338 : : /* Look if a line has been terminated in the newly read data */
339 : 0 : scan_for_lines(l, l->rbuf_valid_length - (size_t) r);
340 : : }
341 : :
342 : : return 0;
343 : : }
344 : :
345 : : /* Try to flush the buffer */
346 : 0 : static int do_write(pa_ioline *l) {
347 : : ssize_t r;
348 : :
349 [ # # ]: 0 : pa_assert(l);
350 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
351 : :
352 [ # # ][ # # ]: 0 : while (l->io && !l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length > 0) {
[ # # ][ # # ]
353 : :
354 [ # # ]: 0 : if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) <= 0) {
355 : :
356 [ # # ][ # # ]: 0 : if (r < 0 && errno == EAGAIN)
357 : : break;
358 : :
359 [ # # ][ # # ]: 0 : if (r < 0 && errno != EPIPE)
360 : 0 : pa_log("write(): %s", pa_cstrerror(errno));
361 : :
362 : 0 : failure(l, FALSE);
363 : :
364 : 0 : return -1;
365 : : }
366 : :
367 : 0 : l->wbuf_index += (size_t) r;
368 : 0 : l->wbuf_valid_length -= (size_t) r;
369 : :
370 : : /* A shortcut for the next time */
371 [ # # ]: 0 : if (l->wbuf_valid_length == 0)
372 : 0 : l->wbuf_index = 0;
373 : : }
374 : :
375 [ # # ][ # # ]: 0 : if (l->wbuf_valid_length <= 0 && l->drain_callback)
376 : 0 : l->drain_callback(l, l->drain_userdata);
377 : :
378 : : return 0;
379 : : }
380 : :
381 : : /* Try to flush read/write data */
382 : 0 : static void do_work(pa_ioline *l) {
383 [ # # ]: 0 : pa_assert(l);
384 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
385 : :
386 : 0 : pa_ioline_ref(l);
387 : :
388 : 0 : l->mainloop->defer_enable(l->defer_event, 0);
389 : :
390 [ # # ]: 0 : if (!l->dead)
391 : 0 : do_read(l);
392 : :
393 [ # # ]: 0 : if (!l->dead)
394 : 0 : do_write(l);
395 : :
396 [ # # ][ # # ]: 0 : if (l->defer_close && !l->wbuf_valid_length)
397 : 0 : failure(l, TRUE);
398 : :
399 : 0 : pa_ioline_unref(l);
400 : 0 : }
401 : :
402 : 0 : static void io_callback(pa_iochannel*io, void *userdata) {
403 : 0 : pa_ioline *l = userdata;
404 : :
405 [ # # ]: 0 : pa_assert(io);
406 [ # # ]: 0 : pa_assert(l);
407 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
408 : :
409 : 0 : do_work(l);
410 : 0 : }
411 : :
412 : 0 : static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) {
413 : 0 : pa_ioline *l = userdata;
414 : :
415 [ # # ]: 0 : pa_assert(l);
416 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
417 [ # # ]: 0 : pa_assert(l->mainloop == m);
418 [ # # ]: 0 : pa_assert(l->defer_event == e);
419 : :
420 : 0 : do_work(l);
421 : 0 : }
422 : :
423 : 0 : void pa_ioline_defer_close(pa_ioline *l) {
424 [ # # ]: 0 : pa_assert(l);
425 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
426 : :
427 : 0 : l->defer_close = TRUE;
428 : :
429 [ # # ]: 0 : if (!l->wbuf_valid_length)
430 : 0 : l->mainloop->defer_enable(l->defer_event, 1);
431 : 0 : }
432 : :
433 : 0 : void pa_ioline_printf(pa_ioline *l, const char *format, ...) {
434 : : char *t;
435 : : va_list ap;
436 : :
437 [ # # ]: 0 : pa_assert(l);
438 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(l) >= 1);
439 : :
440 : 0 : va_start(ap, format);
441 : 0 : t = pa_vsprintf_malloc(format, ap);
442 : 0 : va_end(ap);
443 : :
444 : 0 : pa_ioline_puts(l, t);
445 : 0 : pa_xfree(t);
446 : 0 : }
447 : :
448 : 0 : pa_iochannel* pa_ioline_detach_iochannel(pa_ioline *l) {
449 : : pa_iochannel *r;
450 : :
451 [ # # ]: 0 : pa_assert(l);
452 : :
453 [ # # ]: 0 : if (!l->io)
454 : : return NULL;
455 : :
456 : 0 : r = l->io;
457 : 0 : l->io = NULL;
458 : :
459 : 0 : pa_iochannel_set_callback(r, NULL, NULL);
460 : :
461 : 0 : return r;
462 : : }
463 : :
464 : 0 : pa_bool_t pa_ioline_is_drained(pa_ioline *l) {
465 [ # # ]: 0 : pa_assert(l);
466 : :
467 : 0 : return l->wbuf_valid_length <= 0;
468 : : }
|