LCOV - code coverage report
Current view: top level - pulsecore - ioline.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 0 223 0.0 %
Date: 2012-07-17 Functions: 0 18 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 196 0.0 %

           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                 :            : }

Generated by: LCOV version 1.9