Home | History | Annotate | Line # | Download | only in dist
buffer.c revision 1.1
      1  1.1  plunky /*	$NetBSD: buffer.c,v 1.1 2009/11/02 10:00:52 plunky Exp $	*/
      2  1.1  plunky /*
      3  1.1  plunky  * Copyright (c) 2002, 2003 Niels Provos <provos (at) citi.umich.edu>
      4  1.1  plunky  * All rights reserved.
      5  1.1  plunky  *
      6  1.1  plunky  * Redistribution and use in source and binary forms, with or without
      7  1.1  plunky  * modification, are permitted provided that the following conditions
      8  1.1  plunky  * are met:
      9  1.1  plunky  * 1. Redistributions of source code must retain the above copyright
     10  1.1  plunky  *    notice, this list of conditions and the following disclaimer.
     11  1.1  plunky  * 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  plunky  *    notice, this list of conditions and the following disclaimer in the
     13  1.1  plunky  *    documentation and/or other materials provided with the distribution.
     14  1.1  plunky  * 3. The name of the author may not be used to endorse or promote products
     15  1.1  plunky  *    derived from this software without specific prior written permission.
     16  1.1  plunky  *
     17  1.1  plunky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  1.1  plunky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  1.1  plunky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  1.1  plunky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  1.1  plunky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  1.1  plunky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  1.1  plunky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  1.1  plunky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  1.1  plunky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  1.1  plunky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  1.1  plunky  */
     28  1.1  plunky 
     29  1.1  plunky #ifdef HAVE_CONFIG_H
     30  1.1  plunky #include "config.h"
     31  1.1  plunky #endif
     32  1.1  plunky 
     33  1.1  plunky #ifdef WIN32
     34  1.1  plunky #include <winsock2.h>
     35  1.1  plunky #include <windows.h>
     36  1.1  plunky #endif
     37  1.1  plunky 
     38  1.1  plunky #ifdef HAVE_VASPRINTF
     39  1.1  plunky /* If we have vasprintf, we need to define this before we include stdio.h. */
     40  1.1  plunky #define _GNU_SOURCE
     41  1.1  plunky #endif
     42  1.1  plunky 
     43  1.1  plunky #include <sys/types.h>
     44  1.1  plunky 
     45  1.1  plunky #ifdef HAVE_SYS_TIME_H
     46  1.1  plunky #include <sys/time.h>
     47  1.1  plunky #endif
     48  1.1  plunky 
     49  1.1  plunky #ifdef HAVE_SYS_IOCTL_H
     50  1.1  plunky #include <sys/ioctl.h>
     51  1.1  plunky #endif
     52  1.1  plunky 
     53  1.1  plunky #include <assert.h>
     54  1.1  plunky #include <errno.h>
     55  1.1  plunky #include <stdio.h>
     56  1.1  plunky #include <stdlib.h>
     57  1.1  plunky #include <string.h>
     58  1.1  plunky #ifdef HAVE_STDARG_H
     59  1.1  plunky #include <stdarg.h>
     60  1.1  plunky #endif
     61  1.1  plunky #ifdef HAVE_UNISTD_H
     62  1.1  plunky #include <unistd.h>
     63  1.1  plunky #endif
     64  1.1  plunky 
     65  1.1  plunky #include "event.h"
     66  1.1  plunky #include "config.h"
     67  1.1  plunky #include "evutil.h"
     68  1.1  plunky 
     69  1.1  plunky struct evbuffer *
     70  1.1  plunky evbuffer_new(void)
     71  1.1  plunky {
     72  1.1  plunky 	struct evbuffer *buffer;
     73  1.1  plunky 
     74  1.1  plunky 	buffer = calloc(1, sizeof(struct evbuffer));
     75  1.1  plunky 
     76  1.1  plunky 	return (buffer);
     77  1.1  plunky }
     78  1.1  plunky 
     79  1.1  plunky void
     80  1.1  plunky evbuffer_free(struct evbuffer *buffer)
     81  1.1  plunky {
     82  1.1  plunky 	if (buffer->orig_buffer != NULL)
     83  1.1  plunky 		free(buffer->orig_buffer);
     84  1.1  plunky 	free(buffer);
     85  1.1  plunky }
     86  1.1  plunky 
     87  1.1  plunky /*
     88  1.1  plunky  * This is a destructive add.  The data from one buffer moves into
     89  1.1  plunky  * the other buffer.
     90  1.1  plunky  */
     91  1.1  plunky 
     92  1.1  plunky #define SWAP(x,y) do { \
     93  1.1  plunky 	(x)->buffer = (y)->buffer; \
     94  1.1  plunky 	(x)->orig_buffer = (y)->orig_buffer; \
     95  1.1  plunky 	(x)->misalign = (y)->misalign; \
     96  1.1  plunky 	(x)->totallen = (y)->totallen; \
     97  1.1  plunky 	(x)->off = (y)->off; \
     98  1.1  plunky } while (0)
     99  1.1  plunky 
    100  1.1  plunky int
    101  1.1  plunky evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
    102  1.1  plunky {
    103  1.1  plunky 	int res;
    104  1.1  plunky 
    105  1.1  plunky 	/* Short cut for better performance */
    106  1.1  plunky 	if (outbuf->off == 0) {
    107  1.1  plunky 		struct evbuffer tmp;
    108  1.1  plunky 		size_t oldoff = inbuf->off;
    109  1.1  plunky 
    110  1.1  plunky 		/* Swap them directly */
    111  1.1  plunky 		SWAP(&tmp, outbuf);
    112  1.1  plunky 		SWAP(outbuf, inbuf);
    113  1.1  plunky 		SWAP(inbuf, &tmp);
    114  1.1  plunky 
    115  1.1  plunky 		/*
    116  1.1  plunky 		 * Optimization comes with a price; we need to notify the
    117  1.1  plunky 		 * buffer if necessary of the changes. oldoff is the amount
    118  1.1  plunky 		 * of data that we transfered from inbuf to outbuf
    119  1.1  plunky 		 */
    120  1.1  plunky 		if (inbuf->off != oldoff && inbuf->cb != NULL)
    121  1.1  plunky 			(*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
    122  1.1  plunky 		if (oldoff && outbuf->cb != NULL)
    123  1.1  plunky 			(*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
    124  1.1  plunky 
    125  1.1  plunky 		return (0);
    126  1.1  plunky 	}
    127  1.1  plunky 
    128  1.1  plunky 	res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
    129  1.1  plunky 	if (res == 0) {
    130  1.1  plunky 		/* We drain the input buffer on success */
    131  1.1  plunky 		evbuffer_drain(inbuf, inbuf->off);
    132  1.1  plunky 	}
    133  1.1  plunky 
    134  1.1  plunky 	return (res);
    135  1.1  plunky }
    136  1.1  plunky 
    137  1.1  plunky int
    138  1.1  plunky evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
    139  1.1  plunky {
    140  1.1  plunky 	char *buffer;
    141  1.1  plunky 	size_t space;
    142  1.1  plunky 	size_t oldoff = buf->off;
    143  1.1  plunky 	int sz;
    144  1.1  plunky 	va_list aq;
    145  1.1  plunky 
    146  1.1  plunky 	/* make sure that at least some space is available */
    147  1.1  plunky 	evbuffer_expand(buf, 64);
    148  1.1  plunky 	for (;;) {
    149  1.1  plunky 		size_t used = buf->misalign + buf->off;
    150  1.1  plunky 		buffer = (char *)buf->buffer + buf->off;
    151  1.1  plunky 		assert(buf->totallen >= used);
    152  1.1  plunky 		space = buf->totallen - used;
    153  1.1  plunky 
    154  1.1  plunky #ifndef va_copy
    155  1.1  plunky #define	va_copy(dst, src)	memcpy(&(dst), &(src), sizeof(va_list))
    156  1.1  plunky #endif
    157  1.1  plunky 		va_copy(aq, ap);
    158  1.1  plunky 
    159  1.1  plunky 		sz = evutil_vsnprintf(buffer, space, fmt, aq);
    160  1.1  plunky 
    161  1.1  plunky 		va_end(aq);
    162  1.1  plunky 
    163  1.1  plunky 		if (sz < 0)
    164  1.1  plunky 			return (-1);
    165  1.1  plunky 		if ((size_t)sz < space) {
    166  1.1  plunky 			buf->off += sz;
    167  1.1  plunky 			if (buf->cb != NULL)
    168  1.1  plunky 				(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
    169  1.1  plunky 			return (sz);
    170  1.1  plunky 		}
    171  1.1  plunky 		if (evbuffer_expand(buf, sz + 1) == -1)
    172  1.1  plunky 			return (-1);
    173  1.1  plunky 
    174  1.1  plunky 	}
    175  1.1  plunky 	/* NOTREACHED */
    176  1.1  plunky }
    177  1.1  plunky 
    178  1.1  plunky int
    179  1.1  plunky evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
    180  1.1  plunky {
    181  1.1  plunky 	int res = -1;
    182  1.1  plunky 	va_list ap;
    183  1.1  plunky 
    184  1.1  plunky 	va_start(ap, fmt);
    185  1.1  plunky 	res = evbuffer_add_vprintf(buf, fmt, ap);
    186  1.1  plunky 	va_end(ap);
    187  1.1  plunky 
    188  1.1  plunky 	return (res);
    189  1.1  plunky }
    190  1.1  plunky 
    191  1.1  plunky /* Reads data from an event buffer and drains the bytes read */
    192  1.1  plunky 
    193  1.1  plunky int
    194  1.1  plunky evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
    195  1.1  plunky {
    196  1.1  plunky 	size_t nread = datlen;
    197  1.1  plunky 	if (nread >= buf->off)
    198  1.1  plunky 		nread = buf->off;
    199  1.1  plunky 
    200  1.1  plunky 	memcpy(data, buf->buffer, nread);
    201  1.1  plunky 	evbuffer_drain(buf, nread);
    202  1.1  plunky 
    203  1.1  plunky 	return (nread);
    204  1.1  plunky }
    205  1.1  plunky 
    206  1.1  plunky /*
    207  1.1  plunky  * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
    208  1.1  plunky  * The returned buffer needs to be freed by the called.
    209  1.1  plunky  */
    210  1.1  plunky 
    211  1.1  plunky char *
    212  1.1  plunky evbuffer_readline(struct evbuffer *buffer)
    213  1.1  plunky {
    214  1.1  plunky 	u_char *data = EVBUFFER_DATA(buffer);
    215  1.1  plunky 	size_t len = EVBUFFER_LENGTH(buffer);
    216  1.1  plunky 	char *line;
    217  1.1  plunky 	unsigned int i;
    218  1.1  plunky 
    219  1.1  plunky 	for (i = 0; i < len; i++) {
    220  1.1  plunky 		if (data[i] == '\r' || data[i] == '\n')
    221  1.1  plunky 			break;
    222  1.1  plunky 	}
    223  1.1  plunky 
    224  1.1  plunky 	if (i == len)
    225  1.1  plunky 		return (NULL);
    226  1.1  plunky 
    227  1.1  plunky 	if ((line = malloc(i + 1)) == NULL) {
    228  1.1  plunky 		fprintf(stderr, "%s: out of memory\n", __func__);
    229  1.1  plunky 		evbuffer_drain(buffer, i);
    230  1.1  plunky 		return (NULL);
    231  1.1  plunky 	}
    232  1.1  plunky 
    233  1.1  plunky 	memcpy(line, data, i);
    234  1.1  plunky 	line[i] = '\0';
    235  1.1  plunky 
    236  1.1  plunky 	/*
    237  1.1  plunky 	 * Some protocols terminate a line with '\r\n', so check for
    238  1.1  plunky 	 * that, too.
    239  1.1  plunky 	 */
    240  1.1  plunky 	if ( i < len - 1 ) {
    241  1.1  plunky 		char fch = data[i], sch = data[i+1];
    242  1.1  plunky 
    243  1.1  plunky 		/* Drain one more character if needed */
    244  1.1  plunky 		if ( (sch == '\r' || sch == '\n') && sch != fch )
    245  1.1  plunky 			i += 1;
    246  1.1  plunky 	}
    247  1.1  plunky 
    248  1.1  plunky 	evbuffer_drain(buffer, i + 1);
    249  1.1  plunky 
    250  1.1  plunky 	return (line);
    251  1.1  plunky }
    252  1.1  plunky 
    253  1.1  plunky /* Adds data to an event buffer */
    254  1.1  plunky 
    255  1.1  plunky static void
    256  1.1  plunky evbuffer_align(struct evbuffer *buf)
    257  1.1  plunky {
    258  1.1  plunky 	memmove(buf->orig_buffer, buf->buffer, buf->off);
    259  1.1  plunky 	buf->buffer = buf->orig_buffer;
    260  1.1  plunky 	buf->misalign = 0;
    261  1.1  plunky }
    262  1.1  plunky 
    263  1.1  plunky /* Expands the available space in the event buffer to at least datlen */
    264  1.1  plunky 
    265  1.1  plunky int
    266  1.1  plunky evbuffer_expand(struct evbuffer *buf, size_t datlen)
    267  1.1  plunky {
    268  1.1  plunky 	size_t need = buf->misalign + buf->off + datlen;
    269  1.1  plunky 
    270  1.1  plunky 	/* If we can fit all the data, then we don't have to do anything */
    271  1.1  plunky 	if (buf->totallen >= need)
    272  1.1  plunky 		return (0);
    273  1.1  plunky 
    274  1.1  plunky 	/*
    275  1.1  plunky 	 * If the misalignment fulfills our data needs, we just force an
    276  1.1  plunky 	 * alignment to happen.  Afterwards, we have enough space.
    277  1.1  plunky 	 */
    278  1.1  plunky 	if (buf->misalign >= datlen) {
    279  1.1  plunky 		evbuffer_align(buf);
    280  1.1  plunky 	} else {
    281  1.1  plunky 		void *newbuf;
    282  1.1  plunky 		size_t length = buf->totallen;
    283  1.1  plunky 
    284  1.1  plunky 		if (length < 256)
    285  1.1  plunky 			length = 256;
    286  1.1  plunky 		while (length < need)
    287  1.1  plunky 			length <<= 1;
    288  1.1  plunky 
    289  1.1  plunky 		if (buf->orig_buffer != buf->buffer)
    290  1.1  plunky 			evbuffer_align(buf);
    291  1.1  plunky 		if ((newbuf = realloc(buf->buffer, length)) == NULL)
    292  1.1  plunky 			return (-1);
    293  1.1  plunky 
    294  1.1  plunky 		buf->orig_buffer = buf->buffer = newbuf;
    295  1.1  plunky 		buf->totallen = length;
    296  1.1  plunky 	}
    297  1.1  plunky 
    298  1.1  plunky 	return (0);
    299  1.1  plunky }
    300  1.1  plunky 
    301  1.1  plunky int
    302  1.1  plunky evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
    303  1.1  plunky {
    304  1.1  plunky 	size_t need = buf->misalign + buf->off + datlen;
    305  1.1  plunky 	size_t oldoff = buf->off;
    306  1.1  plunky 
    307  1.1  plunky 	if (buf->totallen < need) {
    308  1.1  plunky 		if (evbuffer_expand(buf, datlen) == -1)
    309  1.1  plunky 			return (-1);
    310  1.1  plunky 	}
    311  1.1  plunky 
    312  1.1  plunky 	memcpy(buf->buffer + buf->off, data, datlen);
    313  1.1  plunky 	buf->off += datlen;
    314  1.1  plunky 
    315  1.1  plunky 	if (datlen && buf->cb != NULL)
    316  1.1  plunky 		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
    317  1.1  plunky 
    318  1.1  plunky 	return (0);
    319  1.1  plunky }
    320  1.1  plunky 
    321  1.1  plunky void
    322  1.1  plunky evbuffer_drain(struct evbuffer *buf, size_t len)
    323  1.1  plunky {
    324  1.1  plunky 	size_t oldoff = buf->off;
    325  1.1  plunky 
    326  1.1  plunky 	if (len >= buf->off) {
    327  1.1  plunky 		buf->off = 0;
    328  1.1  plunky 		buf->buffer = buf->orig_buffer;
    329  1.1  plunky 		buf->misalign = 0;
    330  1.1  plunky 		goto done;
    331  1.1  plunky 	}
    332  1.1  plunky 
    333  1.1  plunky 	buf->buffer += len;
    334  1.1  plunky 	buf->misalign += len;
    335  1.1  plunky 
    336  1.1  plunky 	buf->off -= len;
    337  1.1  plunky 
    338  1.1  plunky  done:
    339  1.1  plunky 	/* Tell someone about changes in this buffer */
    340  1.1  plunky 	if (buf->off != oldoff && buf->cb != NULL)
    341  1.1  plunky 		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
    342  1.1  plunky 
    343  1.1  plunky }
    344  1.1  plunky 
    345  1.1  plunky /*
    346  1.1  plunky  * Reads data from a file descriptor into a buffer.
    347  1.1  plunky  */
    348  1.1  plunky 
    349  1.1  plunky #define EVBUFFER_MAX_READ	4096
    350  1.1  plunky 
    351  1.1  plunky int
    352  1.1  plunky evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
    353  1.1  plunky {
    354  1.1  plunky 	u_char *p;
    355  1.1  plunky 	size_t oldoff = buf->off;
    356  1.1  plunky 	int n = EVBUFFER_MAX_READ;
    357  1.1  plunky 
    358  1.1  plunky #if defined(FIONREAD)
    359  1.1  plunky #ifdef WIN32
    360  1.1  plunky 	long lng = n;
    361  1.1  plunky 	if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) == 0) {
    362  1.1  plunky #else
    363  1.1  plunky 	if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
    364  1.1  plunky #endif
    365  1.1  plunky 		n = EVBUFFER_MAX_READ;
    366  1.1  plunky 	} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
    367  1.1  plunky 		/*
    368  1.1  plunky 		 * It's possible that a lot of data is available for
    369  1.1  plunky 		 * reading.  We do not want to exhaust resources
    370  1.1  plunky 		 * before the reader has a chance to do something
    371  1.1  plunky 		 * about it.  If the reader does not tell us how much
    372  1.1  plunky 		 * data we should read, we artifically limit it.
    373  1.1  plunky 		 */
    374  1.1  plunky 		if ((size_t)n > buf->totallen << 2)
    375  1.1  plunky 			n = buf->totallen << 2;
    376  1.1  plunky 		if (n < EVBUFFER_MAX_READ)
    377  1.1  plunky 			n = EVBUFFER_MAX_READ;
    378  1.1  plunky 	}
    379  1.1  plunky #endif
    380  1.1  plunky 	if (howmuch < 0 || howmuch > n)
    381  1.1  plunky 		howmuch = n;
    382  1.1  plunky 
    383  1.1  plunky 	/* If we don't have FIONREAD, we might waste some space here */
    384  1.1  plunky 	if (evbuffer_expand(buf, howmuch) == -1)
    385  1.1  plunky 		return (-1);
    386  1.1  plunky 
    387  1.1  plunky 	/* We can append new data at this point */
    388  1.1  plunky 	p = buf->buffer + buf->off;
    389  1.1  plunky 
    390  1.1  plunky #ifndef WIN32
    391  1.1  plunky 	n = read(fd, p, howmuch);
    392  1.1  plunky #else
    393  1.1  plunky 	n = recv(fd, p, howmuch, 0);
    394  1.1  plunky #endif
    395  1.1  plunky 	if (n == -1)
    396  1.1  plunky 		return (-1);
    397  1.1  plunky 	if (n == 0)
    398  1.1  plunky 		return (0);
    399  1.1  plunky 
    400  1.1  plunky 	buf->off += n;
    401  1.1  plunky 
    402  1.1  plunky 	/* Tell someone about changes in this buffer */
    403  1.1  plunky 	if (buf->off != oldoff && buf->cb != NULL)
    404  1.1  plunky 		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
    405  1.1  plunky 
    406  1.1  plunky 	return (n);
    407  1.1  plunky }
    408  1.1  plunky 
    409  1.1  plunky int
    410  1.1  plunky evbuffer_write(struct evbuffer *buffer, int fd)
    411  1.1  plunky {
    412  1.1  plunky 	int n;
    413  1.1  plunky 
    414  1.1  plunky #ifndef WIN32
    415  1.1  plunky 	n = write(fd, buffer->buffer, buffer->off);
    416  1.1  plunky #else
    417  1.1  plunky 	n = send(fd, buffer->buffer, buffer->off, 0);
    418  1.1  plunky #endif
    419  1.1  plunky 	if (n == -1)
    420  1.1  plunky 		return (-1);
    421  1.1  plunky 	if (n == 0)
    422  1.1  plunky 		return (0);
    423  1.1  plunky 	evbuffer_drain(buffer, n);
    424  1.1  plunky 
    425  1.1  plunky 	return (n);
    426  1.1  plunky }
    427  1.1  plunky 
    428  1.1  plunky u_char *
    429  1.1  plunky evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
    430  1.1  plunky {
    431  1.1  plunky 	u_char *search = buffer->buffer, *end = search + buffer->off;
    432  1.1  plunky 	u_char *p;
    433  1.1  plunky 
    434  1.1  plunky 	while (search < end &&
    435  1.1  plunky 	    (p = memchr(search, *what, end - search)) != NULL) {
    436  1.1  plunky 		if (p + len > end)
    437  1.1  plunky 			break;
    438  1.1  plunky 		if (memcmp(p, what, len) == 0)
    439  1.1  plunky 			return (p);
    440  1.1  plunky 		search = p + 1;
    441  1.1  plunky 	}
    442  1.1  plunky 
    443  1.1  plunky 	return (NULL);
    444  1.1  plunky }
    445  1.1  plunky 
    446  1.1  plunky void evbuffer_setcb(struct evbuffer *buffer,
    447  1.1  plunky     void (*cb)(struct evbuffer *, size_t, size_t, void *),
    448  1.1  plunky     void *cbarg)
    449  1.1  plunky {
    450  1.1  plunky 	buffer->cb = cb;
    451  1.1  plunky 	buffer->cbarg = cbarg;
    452  1.1  plunky }
    453