File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libevent / buffer.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:02:54 2012 UTC (12 years, 3 months ago) by misho
Branches: libevent, MAIN
CVS tags: v1_4_14bp0, v1_4_14b, HEAD
libevent

    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>