Annotation of embedaddon/libevent/buffer.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 2002, 2003 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: #ifdef HAVE_CONFIG_H
        !            29: #include "config.h"
        !            30: #endif
        !            31: 
        !            32: #ifdef WIN32
        !            33: #include <winsock2.h>
        !            34: #include <windows.h>
        !            35: #endif
        !            36: 
        !            37: #ifdef HAVE_VASPRINTF
        !            38: /* If we have vasprintf, we need to define this before we include stdio.h. */
        !            39: #define _GNU_SOURCE
        !            40: #endif
        !            41: 
        !            42: #include <sys/types.h>
        !            43: 
        !            44: #ifdef HAVE_SYS_TIME_H
        !            45: #include <sys/time.h>
        !            46: #endif
        !            47: 
        !            48: #ifdef HAVE_SYS_IOCTL_H
        !            49: #include <sys/ioctl.h>
        !            50: #endif
        !            51: 
        !            52: #include <assert.h>
        !            53: #include <errno.h>
        !            54: #include <stdio.h>
        !            55: #include <stdlib.h>
        !            56: #include <string.h>
        !            57: #ifdef HAVE_STDARG_H
        !            58: #include <stdarg.h>
        !            59: #endif
        !            60: #ifdef HAVE_UNISTD_H
        !            61: #include <unistd.h>
        !            62: #endif
        !            63: 
        !            64: #include "event.h"
        !            65: #include "config.h"
        !            66: #include "evutil.h"
        !            67: #include "./log.h"
        !            68: 
        !            69: struct evbuffer *
        !            70: evbuffer_new(void)
        !            71: {
        !            72:        struct evbuffer *buffer;
        !            73:        
        !            74:        buffer = calloc(1, sizeof(struct evbuffer));
        !            75: 
        !            76:        return (buffer);
        !            77: }
        !            78: 
        !            79: void
        !            80: evbuffer_free(struct evbuffer *buffer)
        !            81: {
        !            82:        if (buffer->orig_buffer != NULL)
        !            83:                free(buffer->orig_buffer);
        !            84:        free(buffer);
        !            85: }
        !            86: 
        !            87: /* 
        !            88:  * This is a destructive add.  The data from one buffer moves into
        !            89:  * the other buffer.
        !            90:  */
        !            91: 
        !            92: #define SWAP(x,y) do { \
        !            93:        (x)->buffer = (y)->buffer; \
        !            94:        (x)->orig_buffer = (y)->orig_buffer; \
        !            95:        (x)->misalign = (y)->misalign; \
        !            96:        (x)->totallen = (y)->totallen; \
        !            97:        (x)->off = (y)->off; \
        !            98: } while (0)
        !            99: 
        !           100: int
        !           101: evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
        !           102: {
        !           103:        int res;
        !           104: 
        !           105:        /* Short cut for better performance */
        !           106:        if (outbuf->off == 0) {
        !           107:                struct evbuffer tmp;
        !           108:                size_t oldoff = inbuf->off;
        !           109: 
        !           110:                /* Swap them directly */
        !           111:                SWAP(&tmp, outbuf);
        !           112:                SWAP(outbuf, inbuf);
        !           113:                SWAP(inbuf, &tmp);
        !           114: 
        !           115:                /* 
        !           116:                 * Optimization comes with a price; we need to notify the
        !           117:                 * buffer if necessary of the changes. oldoff is the amount
        !           118:                 * of data that we transfered from inbuf to outbuf
        !           119:                 */
        !           120:                if (inbuf->off != oldoff && inbuf->cb != NULL)
        !           121:                        (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
        !           122:                if (oldoff && outbuf->cb != NULL)
        !           123:                        (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
        !           124:                
        !           125:                return (0);
        !           126:        }
        !           127: 
        !           128:        res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
        !           129:        if (res == 0) {
        !           130:                /* We drain the input buffer on success */
        !           131:                evbuffer_drain(inbuf, inbuf->off);
        !           132:        }
        !           133: 
        !           134:        return (res);
        !           135: }
        !           136: 
        !           137: int
        !           138: evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
        !           139: {
        !           140:        char *buffer;
        !           141:        size_t space;
        !           142:        size_t oldoff = buf->off;
        !           143:        int sz;
        !           144:        va_list aq;
        !           145: 
        !           146:        /* make sure that at least some space is available */
        !           147:        evbuffer_expand(buf, 64);
        !           148:        for (;;) {
        !           149:                size_t used = buf->misalign + buf->off;
        !           150:                buffer = (char *)buf->buffer + buf->off;
        !           151:                assert(buf->totallen >= used);
        !           152:                space = buf->totallen - used;
        !           153: 
        !           154: #ifndef va_copy
        !           155: #define        va_copy(dst, src)       memcpy(&(dst), &(src), sizeof(va_list))
        !           156: #endif
        !           157:                va_copy(aq, ap);
        !           158: 
        !           159:                sz = evutil_vsnprintf(buffer, space, fmt, aq);
        !           160: 
        !           161:                va_end(aq);
        !           162: 
        !           163:                if (sz < 0)
        !           164:                        return (-1);
        !           165:                if ((size_t)sz < space) {
        !           166:                        buf->off += sz;
        !           167:                        if (buf->cb != NULL)
        !           168:                                (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
        !           169:                        return (sz);
        !           170:                }
        !           171:                if (evbuffer_expand(buf, sz + 1) == -1)
        !           172:                        return (-1);
        !           173: 
        !           174:        }
        !           175:        /* NOTREACHED */
        !           176: }
        !           177: 
        !           178: int
        !           179: evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
        !           180: {
        !           181:        int res = -1;
        !           182:        va_list ap;
        !           183: 
        !           184:        va_start(ap, fmt);
        !           185:        res = evbuffer_add_vprintf(buf, fmt, ap);
        !           186:        va_end(ap);
        !           187: 
        !           188:        return (res);
        !           189: }
        !           190: 
        !           191: /* Reads data from an event buffer and drains the bytes read */
        !           192: 
        !           193: int
        !           194: evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
        !           195: {
        !           196:        size_t nread = datlen;
        !           197:        if (nread >= buf->off)
        !           198:                nread = buf->off;
        !           199: 
        !           200:        memcpy(data, buf->buffer, nread);
        !           201:        evbuffer_drain(buf, nread);
        !           202:        
        !           203:        return (nread);
        !           204: }
        !           205: 
        !           206: /*
        !           207:  * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
        !           208:  * The returned buffer needs to be freed by the called.
        !           209:  */
        !           210: 
        !           211: char *
        !           212: evbuffer_readline(struct evbuffer *buffer)
        !           213: {
        !           214:        u_char *data = EVBUFFER_DATA(buffer);
        !           215:        size_t len = EVBUFFER_LENGTH(buffer);
        !           216:        char *line;
        !           217:        unsigned int i;
        !           218: 
        !           219:        for (i = 0; i < len; i++) {
        !           220:                if (data[i] == '\r' || data[i] == '\n')
        !           221:                        break;
        !           222:        }
        !           223: 
        !           224:        if (i == len)
        !           225:                return (NULL);
        !           226: 
        !           227:        if ((line = malloc(i + 1)) == NULL) {
        !           228:                fprintf(stderr, "%s: out of memory\n", __func__);
        !           229:                return (NULL);
        !           230:        }
        !           231: 
        !           232:        memcpy(line, data, i);
        !           233:        line[i] = '\0';
        !           234: 
        !           235:        /*
        !           236:         * Some protocols terminate a line with '\r\n', so check for
        !           237:         * that, too.
        !           238:         */
        !           239:        if ( i < len - 1 ) {
        !           240:                char fch = data[i], sch = data[i+1];
        !           241: 
        !           242:                /* Drain one more character if needed */
        !           243:                if ( (sch == '\r' || sch == '\n') && sch != fch )
        !           244:                        i += 1;
        !           245:        }
        !           246: 
        !           247:        evbuffer_drain(buffer, i + 1);
        !           248: 
        !           249:        return (line);
        !           250: }
        !           251: 
        !           252: 
        !           253: char *
        !           254: evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
        !           255:                enum evbuffer_eol_style eol_style)
        !           256: {
        !           257:        u_char *data = EVBUFFER_DATA(buffer);
        !           258:        u_char *start_of_eol, *end_of_eol;
        !           259:        size_t len = EVBUFFER_LENGTH(buffer);
        !           260:        char *line;
        !           261:        unsigned int i, n_to_copy, n_to_drain;
        !           262: 
        !           263:        if (n_read_out)
        !           264:                *n_read_out = 0;
        !           265: 
        !           266:        /* depending on eol_style, set start_of_eol to the first character
        !           267:         * in the newline, and end_of_eol to one after the last character. */
        !           268:        switch (eol_style) {
        !           269:        case EVBUFFER_EOL_ANY:
        !           270:                for (i = 0; i < len; i++) {
        !           271:                        if (data[i] == '\r' || data[i] == '\n')
        !           272:                                break;
        !           273:                }
        !           274:                if (i == len)
        !           275:                        return (NULL);
        !           276:                start_of_eol = data+i;
        !           277:                ++i;
        !           278:                for ( ; i < len; i++) {
        !           279:                        if (data[i] != '\r' && data[i] != '\n')
        !           280:                                break;
        !           281:                }
        !           282:                end_of_eol = data+i;
        !           283:                break;
        !           284:        case EVBUFFER_EOL_CRLF:
        !           285:                end_of_eol = memchr(data, '\n', len);
        !           286:                if (!end_of_eol)
        !           287:                        return (NULL);
        !           288:                if (end_of_eol > data && *(end_of_eol-1) == '\r')
        !           289:                        start_of_eol = end_of_eol - 1;
        !           290:                else
        !           291:                        start_of_eol = end_of_eol;
        !           292:                end_of_eol++; /*point to one after the LF. */
        !           293:                break;
        !           294:        case EVBUFFER_EOL_CRLF_STRICT: {
        !           295:                u_char *cp = data;
        !           296:                while ((cp = memchr(cp, '\r', len-(cp-data)))) {
        !           297:                        if (cp < data+len-1 && *(cp+1) == '\n')
        !           298:                                break;
        !           299:                        if (++cp >= data+len) {
        !           300:                                cp = NULL;
        !           301:                                break;
        !           302:                        }
        !           303:                }
        !           304:                if (!cp)
        !           305:                        return (NULL);
        !           306:                start_of_eol = cp;
        !           307:                end_of_eol = cp+2;
        !           308:                break;
        !           309:        }
        !           310:        case EVBUFFER_EOL_LF:
        !           311:                start_of_eol = memchr(data, '\n', len);
        !           312:                if (!start_of_eol)
        !           313:                        return (NULL);
        !           314:                end_of_eol = start_of_eol + 1;
        !           315:                break;
        !           316:        default:
        !           317:                return (NULL);
        !           318:        }
        !           319: 
        !           320:        n_to_copy = start_of_eol - data;
        !           321:        n_to_drain = end_of_eol - data;
        !           322: 
        !           323:        if ((line = malloc(n_to_copy+1)) == NULL) {
        !           324:                event_warn("%s: out of memory\n", __func__);
        !           325:                return (NULL);
        !           326:        }
        !           327: 
        !           328:        memcpy(line, data, n_to_copy);
        !           329:        line[n_to_copy] = '\0';
        !           330: 
        !           331:        evbuffer_drain(buffer, n_to_drain);
        !           332:        if (n_read_out)
        !           333:                *n_read_out = (size_t)n_to_copy;
        !           334: 
        !           335:        return (line);
        !           336: }
        !           337: 
        !           338: /* Adds data to an event buffer */
        !           339: 
        !           340: static void
        !           341: evbuffer_align(struct evbuffer *buf)
        !           342: {
        !           343:        memmove(buf->orig_buffer, buf->buffer, buf->off);
        !           344:        buf->buffer = buf->orig_buffer;
        !           345:        buf->misalign = 0;
        !           346: }
        !           347: 
        !           348: /* Expands the available space in the event buffer to at least datlen */
        !           349: 
        !           350: int
        !           351: evbuffer_expand(struct evbuffer *buf, size_t datlen)
        !           352: {
        !           353:        size_t need = buf->misalign + buf->off + datlen;
        !           354: 
        !           355:        /* If we can fit all the data, then we don't have to do anything */
        !           356:        if (buf->totallen >= need)
        !           357:                return (0);
        !           358: 
        !           359:        /*
        !           360:         * If the misalignment fulfills our data needs, we just force an
        !           361:         * alignment to happen.  Afterwards, we have enough space.
        !           362:         */
        !           363:        if (buf->misalign >= datlen) {
        !           364:                evbuffer_align(buf);
        !           365:        } else {
        !           366:                void *newbuf;
        !           367:                size_t length = buf->totallen;
        !           368: 
        !           369:                if (length < 256)
        !           370:                        length = 256;
        !           371:                while (length < need)
        !           372:                        length <<= 1;
        !           373: 
        !           374:                if (buf->orig_buffer != buf->buffer)
        !           375:                        evbuffer_align(buf);
        !           376:                if ((newbuf = realloc(buf->buffer, length)) == NULL)
        !           377:                        return (-1);
        !           378: 
        !           379:                buf->orig_buffer = buf->buffer = newbuf;
        !           380:                buf->totallen = length;
        !           381:        }
        !           382: 
        !           383:        return (0);
        !           384: }
        !           385: 
        !           386: int
        !           387: evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
        !           388: {
        !           389:        size_t need = buf->misalign + buf->off + datlen;
        !           390:        size_t oldoff = buf->off;
        !           391: 
        !           392:        if (buf->totallen < need) {
        !           393:                if (evbuffer_expand(buf, datlen) == -1)
        !           394:                        return (-1);
        !           395:        }
        !           396: 
        !           397:        memcpy(buf->buffer + buf->off, data, datlen);
        !           398:        buf->off += datlen;
        !           399: 
        !           400:        if (datlen && buf->cb != NULL)
        !           401:                (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
        !           402: 
        !           403:        return (0);
        !           404: }
        !           405: 
        !           406: void
        !           407: evbuffer_drain(struct evbuffer *buf, size_t len)
        !           408: {
        !           409:        size_t oldoff = buf->off;
        !           410: 
        !           411:        if (len >= buf->off) {
        !           412:                buf->off = 0;
        !           413:                buf->buffer = buf->orig_buffer;
        !           414:                buf->misalign = 0;
        !           415:                goto done;
        !           416:        }
        !           417: 
        !           418:        buf->buffer += len;
        !           419:        buf->misalign += len;
        !           420: 
        !           421:        buf->off -= len;
        !           422: 
        !           423:  done:
        !           424:        /* Tell someone about changes in this buffer */
        !           425:        if (buf->off != oldoff && buf->cb != NULL)
        !           426:                (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
        !           427: 
        !           428: }
        !           429: 
        !           430: /*
        !           431:  * Reads data from a file descriptor into a buffer.
        !           432:  */
        !           433: 
        !           434: #define EVBUFFER_MAX_READ      4096
        !           435: 
        !           436: int
        !           437: evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
        !           438: {
        !           439:        u_char *p;
        !           440:        size_t oldoff = buf->off;
        !           441:        int n = EVBUFFER_MAX_READ;
        !           442: 
        !           443: #if defined(FIONREAD)
        !           444: #ifdef WIN32
        !           445:        long lng = n;
        !           446:        if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) <= 0) {
        !           447: #else
        !           448:        if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) {
        !           449: #endif
        !           450:                n = EVBUFFER_MAX_READ;
        !           451:        } else if (n > EVBUFFER_MAX_READ && n > howmuch) {
        !           452:                /*
        !           453:                 * It's possible that a lot of data is available for
        !           454:                 * reading.  We do not want to exhaust resources
        !           455:                 * before the reader has a chance to do something
        !           456:                 * about it.  If the reader does not tell us how much
        !           457:                 * data we should read, we artifically limit it.
        !           458:                 */
        !           459:                if ((size_t)n > buf->totallen << 2)
        !           460:                        n = buf->totallen << 2;
        !           461:                if (n < EVBUFFER_MAX_READ)
        !           462:                        n = EVBUFFER_MAX_READ;
        !           463:        }
        !           464: #endif 
        !           465:        if (howmuch < 0 || howmuch > n)
        !           466:                howmuch = n;
        !           467: 
        !           468:        /* If we don't have FIONREAD, we might waste some space here */
        !           469:        if (evbuffer_expand(buf, howmuch) == -1)
        !           470:                return (-1);
        !           471: 
        !           472:        /* We can append new data at this point */
        !           473:        p = buf->buffer + buf->off;
        !           474: 
        !           475: #ifndef WIN32
        !           476:        n = read(fd, p, howmuch);
        !           477: #else
        !           478:        n = recv(fd, p, howmuch, 0);
        !           479: #endif
        !           480:        if (n == -1)
        !           481:                return (-1);
        !           482:        if (n == 0)
        !           483:                return (0);
        !           484: 
        !           485:        buf->off += n;
        !           486: 
        !           487:        /* Tell someone about changes in this buffer */
        !           488:        if (buf->off != oldoff && buf->cb != NULL)
        !           489:                (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
        !           490: 
        !           491:        return (n);
        !           492: }
        !           493: 
        !           494: int
        !           495: evbuffer_write(struct evbuffer *buffer, int fd)
        !           496: {
        !           497:        int n;
        !           498: 
        !           499: #ifndef WIN32
        !           500:        n = write(fd, buffer->buffer, buffer->off);
        !           501: #else
        !           502:        n = send(fd, buffer->buffer, buffer->off, 0);
        !           503: #endif
        !           504:        if (n == -1)
        !           505:                return (-1);
        !           506:        if (n == 0)
        !           507:                return (0);
        !           508:        evbuffer_drain(buffer, n);
        !           509: 
        !           510:        return (n);
        !           511: }
        !           512: 
        !           513: u_char *
        !           514: evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
        !           515: {
        !           516:        u_char *search = buffer->buffer, *end = search + buffer->off;
        !           517:        u_char *p;
        !           518: 
        !           519:        while (search < end &&
        !           520:            (p = memchr(search, *what, end - search)) != NULL) {
        !           521:                if (p + len > end)
        !           522:                        break;
        !           523:                if (memcmp(p, what, len) == 0)
        !           524:                        return (p);
        !           525:                search = p + 1;
        !           526:        }
        !           527: 
        !           528:        return (NULL);
        !           529: }
        !           530: 
        !           531: void evbuffer_setcb(struct evbuffer *buffer,
        !           532:     void (*cb)(struct evbuffer *, size_t, size_t, void *),
        !           533:     void *cbarg)
        !           534: {
        !           535:        buffer->cb = cb;
        !           536:        buffer->cbarg = cbarg;
        !           537: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>