/* $OpenBSD: buffer.c,v 1.3 2005/04/19 08:07:45 deraadt Exp $ */ /* * Copyright (c) 2002, 2003 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include #include #include #include #ifdef HAVE_STDARG_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include "event.h" struct evbuffer * evbuffer_new(void) { struct evbuffer *buffer; buffer = calloc(1, sizeof(struct evbuffer)); return (buffer); } void evbuffer_free(struct evbuffer *buffer) { if (buffer->buffer != NULL) free(buffer->buffer); free(buffer); } /* * This is a destructive add. The data from one buffer moves into * the other buffer. */ int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) { int res; res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off); if (res == 0) evbuffer_drain(inbuf, inbuf->off); return (res); } int evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...) { int res = -1; char *msg; va_list ap; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) goto end; res = strlen(msg); if (evbuffer_add(buf, msg, res) == -1) res = -1; free(msg); end: va_end(ap); return (res); } int evbuffer_add(struct evbuffer *buf, u_char *data, size_t datlen) { size_t need = buf->off + datlen; size_t oldoff = buf->off; if (buf->totallen < need) { void *newbuf; int length = buf->totallen; if (length < 256) length = 256; while (length < need) length <<= 1; if ((newbuf = realloc(buf->buffer, length)) == NULL) return (-1); buf->buffer = newbuf; buf->totallen = length; } memcpy(buf->buffer + buf->off, data, datlen); buf->off += datlen; if (datlen && buf->cb != NULL) (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); return (0); } void evbuffer_drain(struct evbuffer *buf, size_t len) { size_t oldoff = buf->off; if (len >= buf->off) { buf->off = 0; goto done; } memmove(buf->buffer, buf->buffer + len, buf->off - len); buf->off -= len; done: /* Tell someone about changes in this buffer */ if (buf->off != oldoff && buf->cb != NULL) (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); } int evbuffer_read(struct evbuffer *buffer, int fd, int howmuch) { u_char inbuf[4096]; int n; if (howmuch < 0 || howmuch > sizeof(inbuf)) howmuch = sizeof(inbuf); n = read(fd, inbuf, howmuch); if (n == -1) return (-1); if (n == 0) return (0); evbuffer_add(buffer, inbuf, n); return (n); } int evbuffer_write(struct evbuffer *buffer, int fd) { int n; n = write(fd, buffer->buffer, buffer->off); if (n == -1) return (-1); if (n == 0) return (0); evbuffer_drain(buffer, n); return (n); } u_char * evbuffer_find(struct evbuffer *buffer, u_char *what, size_t len) { size_t remain = buffer->off; u_char *search = buffer->buffer; u_char *p; while ((p = memchr(search, *what, remain)) != NULL && remain >= len) { if (memcmp(p, what, len) == 0) return (p); search = p + 1; remain = buffer->off - (size_t)(search - buffer->buffer); } return (NULL); } void evbuffer_setcb(struct evbuffer *buffer, void (*cb)(struct evbuffer *, size_t, size_t, void *), void *cbarg) { buffer->cb = cb; buffer->cbarg = cbarg; }