LCOV - code coverage report
Current view: directory - ipc/chromium/src/third_party/libevent - evbuffer.c (source / functions) Found Hit Coverage
Test: app.info Lines: 185 0 0.0 %
Date: 2012-06-02 Functions: 17 0 0.0 %

       1                 : /*
       2                 :  * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
       3                 :  * All rights reserved.
       4                 :  *
       5                 :  * Redistribution and use in source and binary forms, with or without
       6                 :  * modification, are permitted provided that the following conditions
       7                 :  * are met:
       8                 :  * 1. Redistributions of source code must retain the above copyright
       9                 :  *    notice, this list of conditions and the following disclaimer.
      10                 :  * 2. Redistributions in binary form must reproduce the above copyright
      11                 :  *    notice, this list of conditions and the following disclaimer in the
      12                 :  *    documentation and/or other materials provided with the distribution.
      13                 :  * 3. The name of the author may not be used to endorse or promote products
      14                 :  *    derived from this software without specific prior written permission.
      15                 :  *
      16                 :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      17                 :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      18                 :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      19                 :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      20                 :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      21                 :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      22                 :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      23                 :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      24                 :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      25                 :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26                 :  */
      27                 : 
      28                 : #include <sys/types.h>
      29                 : 
      30                 : #ifdef HAVE_CONFIG_H
      31                 : #include "config.h"
      32                 : #endif
      33                 : 
      34                 : #ifdef HAVE_SYS_TIME_H
      35                 : #include <sys/time.h>
      36                 : #endif
      37                 : 
      38                 : #include <errno.h>
      39                 : #include <stdio.h>
      40                 : #include <stdlib.h>
      41                 : #include <string.h>
      42                 : #ifdef HAVE_STDARG_H
      43                 : #include <stdarg.h>
      44                 : #endif
      45                 : 
      46                 : #ifdef WIN32
      47                 : #include <winsock2.h>
      48                 : #endif
      49                 : 
      50                 : #include "evutil.h"
      51                 : #include "event.h"
      52                 : 
      53                 : /* prototypes */
      54                 : 
      55                 : void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
      56                 : 
      57                 : static int
      58               0 : bufferevent_add(struct event *ev, int timeout)
      59                 : {
      60               0 :         struct timeval tv, *ptv = NULL;
      61                 : 
      62               0 :         if (timeout) {
      63               0 :                 evutil_timerclear(&tv);
      64               0 :                 tv.tv_sec = timeout;
      65               0 :                 ptv = &tv;
      66                 :         }
      67                 : 
      68               0 :         return (event_add(ev, ptv));
      69                 : }
      70                 : 
      71                 : /* 
      72                 :  * This callback is executed when the size of the input buffer changes.
      73                 :  * We use it to apply back pressure on the reading side.
      74                 :  */
      75                 : 
      76                 : void
      77               0 : bufferevent_read_pressure_cb(struct evbuffer *buf, size_t old, size_t now,
      78                 :     void *arg) {
      79               0 :         struct bufferevent *bufev = arg;
      80                 :         /* 
      81                 :          * If we are below the watermark then reschedule reading if it's
      82                 :          * still enabled.
      83                 :          */
      84               0 :         if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) {
      85               0 :                 evbuffer_setcb(buf, NULL, NULL);
      86                 : 
      87               0 :                 if (bufev->enabled & EV_READ)
      88               0 :                         bufferevent_add(&bufev->ev_read, bufev->timeout_read);
      89                 :         }
      90               0 : }
      91                 : 
      92                 : static void
      93               0 : bufferevent_readcb(int fd, short event, void *arg)
      94                 : {
      95               0 :         struct bufferevent *bufev = arg;
      96               0 :         int res = 0;
      97               0 :         short what = EVBUFFER_READ;
      98                 :         size_t len;
      99               0 :         int howmuch = -1;
     100                 : 
     101               0 :         if (event == EV_TIMEOUT) {
     102               0 :                 what |= EVBUFFER_TIMEOUT;
     103               0 :                 goto error;
     104                 :         }
     105                 : 
     106                 :         /*
     107                 :          * If we have a high watermark configured then we don't want to
     108                 :          * read more data than would make us reach the watermark.
     109                 :          */
     110               0 :         if (bufev->wm_read.high != 0) {
     111               0 :                 howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
     112                 :                 /* we might have lowered the watermark, stop reading */
     113               0 :                 if (howmuch <= 0) {
     114               0 :                         struct evbuffer *buf = bufev->input;
     115               0 :                         event_del(&bufev->ev_read);
     116               0 :                         evbuffer_setcb(buf,
     117                 :                             bufferevent_read_pressure_cb, bufev);
     118               0 :                         return;
     119                 :                 }
     120                 :         }
     121                 : 
     122               0 :         res = evbuffer_read(bufev->input, fd, howmuch);
     123               0 :         if (res == -1) {
     124               0 :                 if (errno == EAGAIN || errno == EINTR)
     125                 :                         goto reschedule;
     126                 :                 /* error case */
     127               0 :                 what |= EVBUFFER_ERROR;
     128               0 :         } else if (res == 0) {
     129                 :                 /* eof case */
     130               0 :                 what |= EVBUFFER_EOF;
     131                 :         }
     132                 : 
     133               0 :         if (res <= 0)
     134               0 :                 goto error;
     135                 : 
     136               0 :         bufferevent_add(&bufev->ev_read, bufev->timeout_read);
     137                 : 
     138                 :         /* See if this callbacks meets the water marks */
     139               0 :         len = EVBUFFER_LENGTH(bufev->input);
     140               0 :         if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
     141               0 :                 return;
     142               0 :         if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
     143               0 :                 struct evbuffer *buf = bufev->input;
     144               0 :                 event_del(&bufev->ev_read);
     145                 : 
     146                 :                 /* Now schedule a callback for us when the buffer changes */
     147               0 :                 evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
     148                 :         }
     149                 : 
     150                 :         /* Invoke the user callback - must always be called last */
     151               0 :         if (bufev->readcb != NULL)
     152               0 :                 (*bufev->readcb)(bufev, bufev->cbarg);
     153               0 :         return;
     154                 : 
     155                 :  reschedule:
     156               0 :         bufferevent_add(&bufev->ev_read, bufev->timeout_read);
     157               0 :         return;
     158                 : 
     159                 :  error:
     160               0 :         (*bufev->errorcb)(bufev, what, bufev->cbarg);
     161                 : }
     162                 : 
     163                 : static void
     164               0 : bufferevent_writecb(int fd, short event, void *arg)
     165                 : {
     166               0 :         struct bufferevent *bufev = arg;
     167               0 :         int res = 0;
     168               0 :         short what = EVBUFFER_WRITE;
     169                 : 
     170               0 :         if (event == EV_TIMEOUT) {
     171               0 :                 what |= EVBUFFER_TIMEOUT;
     172               0 :                 goto error;
     173                 :         }
     174                 : 
     175               0 :         if (EVBUFFER_LENGTH(bufev->output)) {
     176               0 :             res = evbuffer_write(bufev->output, fd);
     177               0 :             if (res == -1) {
     178                 : #ifndef WIN32
     179                 : /*todo. evbuffer uses WriteFile when WIN32 is set. WIN32 system calls do not
     180                 :  *set errno. thus this error checking is not portable*/
     181               0 :                     if (errno == EAGAIN ||
     182               0 :                         errno == EINTR ||
     183               0 :                         errno == EINPROGRESS)
     184                 :                             goto reschedule;
     185                 :                     /* error case */
     186               0 :                     what |= EVBUFFER_ERROR;
     187                 : 
     188                 : #else
     189                 :                                 goto reschedule;
     190                 : #endif
     191                 : 
     192               0 :             } else if (res == 0) {
     193                 :                     /* eof case */
     194               0 :                     what |= EVBUFFER_EOF;
     195                 :             }
     196               0 :             if (res <= 0)
     197               0 :                     goto error;
     198                 :         }
     199                 : 
     200               0 :         if (EVBUFFER_LENGTH(bufev->output) != 0)
     201               0 :                 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
     202                 : 
     203                 :         /*
     204                 :          * Invoke the user callback if our buffer is drained or below the
     205                 :          * low watermark.
     206                 :          */
     207               0 :         if (bufev->writecb != NULL &&
     208               0 :             EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
     209               0 :                 (*bufev->writecb)(bufev, bufev->cbarg);
     210                 : 
     211               0 :         return;
     212                 : 
     213                 :  reschedule:
     214               0 :         if (EVBUFFER_LENGTH(bufev->output) != 0)
     215               0 :                 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
     216               0 :         return;
     217                 : 
     218                 :  error:
     219               0 :         (*bufev->errorcb)(bufev, what, bufev->cbarg);
     220                 : }
     221                 : 
     222                 : /*
     223                 :  * Create a new buffered event object.
     224                 :  *
     225                 :  * The read callback is invoked whenever we read new data.
     226                 :  * The write callback is invoked whenever the output buffer is drained.
     227                 :  * The error callback is invoked on a write/read error or on EOF.
     228                 :  *
     229                 :  * Both read and write callbacks maybe NULL.  The error callback is not
     230                 :  * allowed to be NULL and have to be provided always.
     231                 :  */
     232                 : 
     233                 : struct bufferevent *
     234               0 : bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb,
     235                 :     everrorcb errorcb, void *cbarg)
     236                 : {
     237                 :         struct bufferevent *bufev;
     238                 : 
     239               0 :         if ((bufev = calloc(1, sizeof(struct bufferevent))) == NULL)
     240               0 :                 return (NULL);
     241                 : 
     242               0 :         if ((bufev->input = evbuffer_new()) == NULL) {
     243               0 :                 free(bufev);
     244               0 :                 return (NULL);
     245                 :         }
     246                 : 
     247               0 :         if ((bufev->output = evbuffer_new()) == NULL) {
     248               0 :                 evbuffer_free(bufev->input);
     249               0 :                 free(bufev);
     250               0 :                 return (NULL);
     251                 :         }
     252                 : 
     253               0 :         event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
     254               0 :         event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
     255                 : 
     256               0 :         bufferevent_setcb(bufev, readcb, writecb, errorcb, cbarg);
     257                 : 
     258                 :         /*
     259                 :          * Set to EV_WRITE so that using bufferevent_write is going to
     260                 :          * trigger a callback.  Reading needs to be explicitly enabled
     261                 :          * because otherwise no data will be available.
     262                 :          */
     263               0 :         bufev->enabled = EV_WRITE;
     264                 : 
     265               0 :         return (bufev);
     266                 : }
     267                 : 
     268                 : void
     269               0 : bufferevent_setcb(struct bufferevent *bufev,
     270                 :     evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg)
     271                 : {
     272               0 :         bufev->readcb = readcb;
     273               0 :         bufev->writecb = writecb;
     274               0 :         bufev->errorcb = errorcb;
     275                 : 
     276               0 :         bufev->cbarg = cbarg;
     277               0 : }
     278                 : 
     279                 : void
     280               0 : bufferevent_setfd(struct bufferevent *bufev, int fd)
     281                 : {
     282               0 :         event_del(&bufev->ev_read);
     283               0 :         event_del(&bufev->ev_write);
     284                 : 
     285               0 :         event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
     286               0 :         event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
     287               0 :         if (bufev->ev_base != NULL) {
     288               0 :                 event_base_set(bufev->ev_base, &bufev->ev_read);
     289               0 :                 event_base_set(bufev->ev_base, &bufev->ev_write);
     290                 :         }
     291                 : 
     292                 :         /* might have to manually trigger event registration */
     293               0 : }
     294                 : 
     295                 : int
     296               0 : bufferevent_priority_set(struct bufferevent *bufev, int priority)
     297                 : {
     298               0 :         if (event_priority_set(&bufev->ev_read, priority) == -1)
     299               0 :                 return (-1);
     300               0 :         if (event_priority_set(&bufev->ev_write, priority) == -1)
     301               0 :                 return (-1);
     302                 : 
     303               0 :         return (0);
     304                 : }
     305                 : 
     306                 : /* Closing the file descriptor is the responsibility of the caller */
     307                 : 
     308                 : void
     309               0 : bufferevent_free(struct bufferevent *bufev)
     310                 : {
     311               0 :         event_del(&bufev->ev_read);
     312               0 :         event_del(&bufev->ev_write);
     313                 : 
     314               0 :         evbuffer_free(bufev->input);
     315               0 :         evbuffer_free(bufev->output);
     316                 : 
     317               0 :         free(bufev);
     318               0 : }
     319                 : 
     320                 : /*
     321                 :  * Returns 0 on success;
     322                 :  *        -1 on failure.
     323                 :  */
     324                 : 
     325                 : int
     326               0 : bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
     327                 : {
     328                 :         int res;
     329                 : 
     330               0 :         res = evbuffer_add(bufev->output, data, size);
     331                 : 
     332               0 :         if (res == -1)
     333               0 :                 return (res);
     334                 : 
     335                 :         /* If everything is okay, we need to schedule a write */
     336               0 :         if (size > 0 && (bufev->enabled & EV_WRITE))
     337               0 :                 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
     338                 : 
     339               0 :         return (res);
     340                 : }
     341                 : 
     342                 : int
     343               0 : bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
     344                 : {
     345                 :         int res;
     346                 : 
     347               0 :         res = bufferevent_write(bufev, buf->buffer, buf->off);
     348               0 :         if (res != -1)
     349               0 :                 evbuffer_drain(buf, buf->off);
     350                 : 
     351               0 :         return (res);
     352                 : }
     353                 : 
     354                 : size_t
     355               0 : bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
     356                 : {
     357               0 :         struct evbuffer *buf = bufev->input;
     358                 : 
     359               0 :         if (buf->off < size)
     360               0 :                 size = buf->off;
     361                 : 
     362                 :         /* Copy the available data to the user buffer */
     363               0 :         memcpy(data, buf->buffer, size);
     364                 : 
     365               0 :         if (size)
     366               0 :                 evbuffer_drain(buf, size);
     367                 : 
     368               0 :         return (size);
     369                 : }
     370                 : 
     371                 : int
     372               0 : bufferevent_enable(struct bufferevent *bufev, short event)
     373                 : {
     374               0 :         if (event & EV_READ) {
     375               0 :                 if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1)
     376               0 :                         return (-1);
     377                 :         }
     378               0 :         if (event & EV_WRITE) {
     379               0 :                 if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1)
     380               0 :                         return (-1);
     381                 :         }
     382                 : 
     383               0 :         bufev->enabled |= event;
     384               0 :         return (0);
     385                 : }
     386                 : 
     387                 : int
     388               0 : bufferevent_disable(struct bufferevent *bufev, short event)
     389                 : {
     390               0 :         if (event & EV_READ) {
     391               0 :                 if (event_del(&bufev->ev_read) == -1)
     392               0 :                         return (-1);
     393                 :         }
     394               0 :         if (event & EV_WRITE) {
     395               0 :                 if (event_del(&bufev->ev_write) == -1)
     396               0 :                         return (-1);
     397                 :         }
     398                 : 
     399               0 :         bufev->enabled &= ~event;
     400               0 :         return (0);
     401                 : }
     402                 : 
     403                 : /*
     404                 :  * Sets the read and write timeout for a buffered event.
     405                 :  */
     406                 : 
     407                 : void
     408               0 : bufferevent_settimeout(struct bufferevent *bufev,
     409                 :     int timeout_read, int timeout_write) {
     410               0 :         bufev->timeout_read = timeout_read;
     411               0 :         bufev->timeout_write = timeout_write;
     412                 : 
     413               0 :         if (event_pending(&bufev->ev_read, EV_READ, NULL))
     414               0 :                 bufferevent_add(&bufev->ev_read, timeout_read);
     415               0 :         if (event_pending(&bufev->ev_write, EV_WRITE, NULL))
     416               0 :                 bufferevent_add(&bufev->ev_write, timeout_write);
     417               0 : }
     418                 : 
     419                 : /*
     420                 :  * Sets the water marks
     421                 :  */
     422                 : 
     423                 : void
     424               0 : bufferevent_setwatermark(struct bufferevent *bufev, short events,
     425                 :     size_t lowmark, size_t highmark)
     426                 : {
     427               0 :         if (events & EV_READ) {
     428               0 :                 bufev->wm_read.low = lowmark;
     429               0 :                 bufev->wm_read.high = highmark;
     430                 :         }
     431                 : 
     432               0 :         if (events & EV_WRITE) {
     433               0 :                 bufev->wm_write.low = lowmark;
     434               0 :                 bufev->wm_write.high = highmark;
     435                 :         }
     436                 : 
     437                 :         /* If the watermarks changed then see if we should call read again */
     438               0 :         bufferevent_read_pressure_cb(bufev->input,
     439               0 :             0, EVBUFFER_LENGTH(bufev->input), bufev);
     440               0 : }
     441                 : 
     442                 : int
     443               0 : bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
     444                 : {
     445                 :         int res;
     446                 : 
     447               0 :         bufev->ev_base = base;
     448                 : 
     449               0 :         res = event_base_set(base, &bufev->ev_read);
     450               0 :         if (res == -1)
     451               0 :                 return (res);
     452                 : 
     453               0 :         res = event_base_set(base, &bufev->ev_write);
     454               0 :         return (res);
     455                 : }

Generated by: LCOV version 1.7