buffer.c revision 171169
1171169Smlaier/* 2171169Smlaier * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu> 3171169Smlaier * All rights reserved. 4171169Smlaier * 5171169Smlaier * Redistribution and use in source and binary forms, with or without 6171169Smlaier * modification, are permitted provided that the following conditions 7171169Smlaier * are met: 8171169Smlaier * 1. Redistributions of source code must retain the above copyright 9171169Smlaier * notice, this list of conditions and the following disclaimer. 10171169Smlaier * 2. Redistributions in binary form must reproduce the above copyright 11171169Smlaier * notice, this list of conditions and the following disclaimer in the 12171169Smlaier * documentation and/or other materials provided with the distribution. 13171169Smlaier * 3. The name of the author may not be used to endorse or promote products 14171169Smlaier * derived from this software without specific prior written permission. 15171169Smlaier * 16171169Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17171169Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18171169Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19171169Smlaier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20171169Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21171169Smlaier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22171169Smlaier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23171169Smlaier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24171169Smlaier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25171169Smlaier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26171169Smlaier */ 27171169Smlaier 28171169Smlaier#ifdef HAVE_CONFIG_H 29171169Smlaier#include "config.h" 30171169Smlaier#endif 31171169Smlaier 32171169Smlaier#ifdef HAVE_VASPRINTF 33171169Smlaier/* If we have vasprintf, we need to define this before we include stdio.h. */ 34171169Smlaier#define _GNU_SOURCE 35171169Smlaier#endif 36171169Smlaier 37171169Smlaier#include <sys/types.h> 38171169Smlaier 39171169Smlaier#ifdef HAVE_SYS_TIME_H 40171169Smlaier#include <sys/time.h> 41171169Smlaier#endif 42171169Smlaier 43171169Smlaier#ifdef HAVE_SYS_IOCTL_H 44171169Smlaier#include <sys/ioctl.h> 45171169Smlaier#endif 46171169Smlaier 47171169Smlaier#include <errno.h> 48171169Smlaier#include <stdio.h> 49171169Smlaier#include <stdlib.h> 50171169Smlaier#include <string.h> 51171169Smlaier#ifdef HAVE_STDARG_H 52171169Smlaier#include <stdarg.h> 53171169Smlaier#endif 54171169Smlaier#ifdef HAVE_UNISTD_H 55171169Smlaier#include <unistd.h> 56171169Smlaier#endif 57171169Smlaier 58171169Smlaier#include "event.h" 59171169Smlaier 60171169Smlaierstruct evbuffer * 61171169Smlaierevbuffer_new(void) 62171169Smlaier{ 63171169Smlaier struct evbuffer *buffer; 64171169Smlaier 65171169Smlaier buffer = calloc(1, sizeof(struct evbuffer)); 66171169Smlaier 67171169Smlaier return (buffer); 68171169Smlaier} 69171169Smlaier 70171169Smlaiervoid 71171169Smlaierevbuffer_free(struct evbuffer *buffer) 72171169Smlaier{ 73171169Smlaier if (buffer->orig_buffer != NULL) 74171169Smlaier free(buffer->orig_buffer); 75171169Smlaier free(buffer); 76171169Smlaier} 77171169Smlaier 78171169Smlaier/* 79171169Smlaier * This is a destructive add. The data from one buffer moves into 80171169Smlaier * the other buffer. 81171169Smlaier */ 82171169Smlaier 83171169Smlaier#define SWAP(x,y) do { \ 84171169Smlaier (x)->buffer = (y)->buffer; \ 85171169Smlaier (x)->orig_buffer = (y)->orig_buffer; \ 86171169Smlaier (x)->misalign = (y)->misalign; \ 87171169Smlaier (x)->totallen = (y)->totallen; \ 88171169Smlaier (x)->off = (y)->off; \ 89171169Smlaier} while (0) 90171169Smlaier 91171169Smlaierint 92171169Smlaierevbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) 93171169Smlaier{ 94171169Smlaier int res; 95171169Smlaier 96171169Smlaier /* Short cut for better performance */ 97171169Smlaier if (outbuf->off == 0) { 98171169Smlaier struct evbuffer tmp; 99171169Smlaier size_t oldoff = inbuf->off; 100171169Smlaier 101171169Smlaier /* Swap them directly */ 102171169Smlaier SWAP(&tmp, outbuf); 103171169Smlaier SWAP(outbuf, inbuf); 104171169Smlaier SWAP(inbuf, &tmp); 105171169Smlaier 106171169Smlaier /* 107171169Smlaier * Optimization comes with a price; we need to notify the 108171169Smlaier * buffer if necessary of the changes. oldoff is the amount 109171169Smlaier * of data that we tranfered from inbuf to outbuf 110171169Smlaier */ 111171169Smlaier if (inbuf->off != oldoff && inbuf->cb != NULL) 112171169Smlaier (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg); 113171169Smlaier if (oldoff && outbuf->cb != NULL) 114171169Smlaier (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg); 115171169Smlaier 116171169Smlaier return (0); 117171169Smlaier } 118171169Smlaier 119171169Smlaier res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off); 120171169Smlaier if (res == 0) { 121171169Smlaier /* We drain the input buffer on success */ 122171169Smlaier evbuffer_drain(inbuf, inbuf->off); 123171169Smlaier } 124171169Smlaier 125171169Smlaier return (res); 126171169Smlaier} 127171169Smlaier 128171169Smlaierint 129171169Smlaierevbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) 130171169Smlaier{ 131171169Smlaier char *buffer; 132171169Smlaier size_t space; 133171169Smlaier size_t oldoff = buf->off; 134171169Smlaier int sz; 135171169Smlaier va_list aq; 136171169Smlaier 137171169Smlaier for (;;) { 138171169Smlaier buffer = (char *)buf->buffer + buf->off; 139171169Smlaier space = buf->totallen - buf->misalign - buf->off; 140171169Smlaier 141171169Smlaier#ifndef va_copy 142171169Smlaier#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list)) 143171169Smlaier#endif 144171169Smlaier va_copy(aq, ap); 145171169Smlaier 146171169Smlaier#ifdef WIN32 147171169Smlaier sz = vsnprintf(buffer, space - 1, fmt, aq); 148171169Smlaier buffer[space - 1] = '\0'; 149171169Smlaier#else 150171169Smlaier sz = vsnprintf(buffer, space, fmt, aq); 151171169Smlaier#endif 152171169Smlaier 153171169Smlaier va_end(aq); 154171169Smlaier 155171169Smlaier if (sz == -1) 156171169Smlaier return (-1); 157171169Smlaier if (sz < space) { 158171169Smlaier buf->off += sz; 159171169Smlaier if (buf->cb != NULL) 160171169Smlaier (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 161171169Smlaier return (sz); 162171169Smlaier } 163171169Smlaier if (evbuffer_expand(buf, sz + 1) == -1) 164171169Smlaier return (-1); 165171169Smlaier 166171169Smlaier } 167171169Smlaier /* NOTREACHED */ 168171169Smlaier} 169171169Smlaier 170171169Smlaierint 171171169Smlaierevbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...) 172171169Smlaier{ 173171169Smlaier int res = -1; 174171169Smlaier va_list ap; 175171169Smlaier 176171169Smlaier va_start(ap, fmt); 177171169Smlaier res = evbuffer_add_vprintf(buf, fmt, ap); 178171169Smlaier va_end(ap); 179171169Smlaier 180171169Smlaier return (res); 181171169Smlaier} 182171169Smlaier 183171169Smlaier/* Reads data from an event buffer and drains the bytes read */ 184171169Smlaier 185171169Smlaierint 186171169Smlaierevbuffer_remove(struct evbuffer *buf, void *data, size_t datlen) 187171169Smlaier{ 188171169Smlaier size_t nread = datlen; 189171169Smlaier if (nread >= buf->off) 190171169Smlaier nread = buf->off; 191171169Smlaier 192171169Smlaier memcpy(data, buf->buffer, nread); 193171169Smlaier evbuffer_drain(buf, nread); 194171169Smlaier 195171169Smlaier return (nread); 196171169Smlaier} 197171169Smlaier 198171169Smlaier/* 199171169Smlaier * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'. 200171169Smlaier * The returned buffer needs to be freed by the called. 201171169Smlaier */ 202171169Smlaier 203171169Smlaierchar * 204171169Smlaierevbuffer_readline(struct evbuffer *buffer) 205171169Smlaier{ 206171169Smlaier u_char *data = EVBUFFER_DATA(buffer); 207171169Smlaier size_t len = EVBUFFER_LENGTH(buffer); 208171169Smlaier char *line; 209171169Smlaier unsigned int i; 210171169Smlaier 211171169Smlaier for (i = 0; i < len; i++) { 212171169Smlaier if (data[i] == '\r' || data[i] == '\n') 213171169Smlaier break; 214171169Smlaier } 215171169Smlaier 216171169Smlaier if (i == len) 217171169Smlaier return (NULL); 218171169Smlaier 219171169Smlaier if ((line = malloc(i + 1)) == NULL) { 220171169Smlaier fprintf(stderr, "%s: out of memory\n", __func__); 221171169Smlaier evbuffer_drain(buffer, i); 222171169Smlaier return (NULL); 223171169Smlaier } 224171169Smlaier 225171169Smlaier memcpy(line, data, i); 226171169Smlaier line[i] = '\0'; 227171169Smlaier 228171169Smlaier /* 229171169Smlaier * Some protocols terminate a line with '\r\n', so check for 230171169Smlaier * that, too. 231171169Smlaier */ 232171169Smlaier if ( i < len - 1 ) { 233171169Smlaier char fch = data[i], sch = data[i+1]; 234171169Smlaier 235171169Smlaier /* Drain one more character if needed */ 236171169Smlaier if ( (sch == '\r' || sch == '\n') && sch != fch ) 237171169Smlaier i += 1; 238171169Smlaier } 239171169Smlaier 240171169Smlaier evbuffer_drain(buffer, i + 1); 241171169Smlaier 242171169Smlaier return (line); 243171169Smlaier} 244171169Smlaier 245171169Smlaier/* Adds data to an event buffer */ 246171169Smlaier 247171169Smlaierstatic inline void 248171169Smlaierevbuffer_align(struct evbuffer *buf) 249171169Smlaier{ 250171169Smlaier memmove(buf->orig_buffer, buf->buffer, buf->off); 251171169Smlaier buf->buffer = buf->orig_buffer; 252171169Smlaier buf->misalign = 0; 253171169Smlaier} 254171169Smlaier 255171169Smlaier/* Expands the available space in the event buffer to at least datlen */ 256171169Smlaier 257171169Smlaierint 258171169Smlaierevbuffer_expand(struct evbuffer *buf, size_t datlen) 259171169Smlaier{ 260171169Smlaier size_t need = buf->misalign + buf->off + datlen; 261171169Smlaier 262171169Smlaier /* If we can fit all the data, then we don't have to do anything */ 263171169Smlaier if (buf->totallen >= need) 264171169Smlaier return (0); 265171169Smlaier 266171169Smlaier /* 267171169Smlaier * If the misalignment fulfills our data needs, we just force an 268171169Smlaier * alignment to happen. Afterwards, we have enough space. 269171169Smlaier */ 270171169Smlaier if (buf->misalign >= datlen) { 271171169Smlaier evbuffer_align(buf); 272171169Smlaier } else { 273171169Smlaier void *newbuf; 274171169Smlaier size_t length = buf->totallen; 275171169Smlaier 276171169Smlaier if (length < 256) 277171169Smlaier length = 256; 278171169Smlaier while (length < need) 279171169Smlaier length <<= 1; 280171169Smlaier 281171169Smlaier if (buf->orig_buffer != buf->buffer) 282171169Smlaier evbuffer_align(buf); 283171169Smlaier if ((newbuf = realloc(buf->buffer, length)) == NULL) 284171169Smlaier return (-1); 285171169Smlaier 286171169Smlaier buf->orig_buffer = buf->buffer = newbuf; 287171169Smlaier buf->totallen = length; 288171169Smlaier } 289171169Smlaier 290171169Smlaier return (0); 291171169Smlaier} 292171169Smlaier 293171169Smlaierint 294171169Smlaierevbuffer_add(struct evbuffer *buf, const void *data, size_t datlen) 295171169Smlaier{ 296171169Smlaier size_t need = buf->misalign + buf->off + datlen; 297171169Smlaier size_t oldoff = buf->off; 298171169Smlaier 299171169Smlaier if (buf->totallen < need) { 300171169Smlaier if (evbuffer_expand(buf, datlen) == -1) 301171169Smlaier return (-1); 302171169Smlaier } 303171169Smlaier 304171169Smlaier memcpy(buf->buffer + buf->off, data, datlen); 305171169Smlaier buf->off += datlen; 306171169Smlaier 307171169Smlaier if (datlen && buf->cb != NULL) 308171169Smlaier (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 309171169Smlaier 310171169Smlaier return (0); 311171169Smlaier} 312171169Smlaier 313171169Smlaiervoid 314171169Smlaierevbuffer_drain(struct evbuffer *buf, size_t len) 315171169Smlaier{ 316171169Smlaier size_t oldoff = buf->off; 317171169Smlaier 318171169Smlaier if (len >= buf->off) { 319171169Smlaier buf->off = 0; 320171169Smlaier buf->buffer = buf->orig_buffer; 321171169Smlaier buf->misalign = 0; 322171169Smlaier goto done; 323171169Smlaier } 324171169Smlaier 325171169Smlaier buf->buffer += len; 326171169Smlaier buf->misalign += len; 327171169Smlaier 328171169Smlaier buf->off -= len; 329171169Smlaier 330171169Smlaier done: 331171169Smlaier /* Tell someone about changes in this buffer */ 332171169Smlaier if (buf->off != oldoff && buf->cb != NULL) 333171169Smlaier (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 334171169Smlaier 335171169Smlaier} 336171169Smlaier 337171169Smlaier/* 338171169Smlaier * Reads data from a file descriptor into a buffer. 339171169Smlaier */ 340171169Smlaier 341171169Smlaier#define EVBUFFER_MAX_READ 4096 342171169Smlaier 343171169Smlaierint 344171169Smlaierevbuffer_read(struct evbuffer *buf, int fd, int howmuch) 345171169Smlaier{ 346171169Smlaier u_char *p; 347171169Smlaier size_t oldoff = buf->off; 348171169Smlaier int n = EVBUFFER_MAX_READ; 349171169Smlaier#ifdef WIN32 350171169Smlaier DWORD dwBytesRead; 351171169Smlaier#endif 352171169Smlaier 353171169Smlaier#ifdef FIONREAD 354171169Smlaier if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) { 355171169Smlaier n = EVBUFFER_MAX_READ; 356171169Smlaier } else if (n > EVBUFFER_MAX_READ && n > howmuch) { 357171169Smlaier /* 358171169Smlaier * It's possible that a lot of data is available for 359171169Smlaier * reading. We do not want to exhaust resources 360171169Smlaier * before the reader has a chance to do something 361171169Smlaier * about it. If the reader does not tell us how much 362171169Smlaier * data we should read, we artifically limit it. 363171169Smlaier */ 364171169Smlaier if (n > buf->totallen << 2) 365171169Smlaier n = buf->totallen << 2; 366171169Smlaier if (n < EVBUFFER_MAX_READ) 367171169Smlaier n = EVBUFFER_MAX_READ; 368171169Smlaier } 369171169Smlaier#endif 370171169Smlaier if (howmuch < 0 || howmuch > n) 371171169Smlaier howmuch = n; 372171169Smlaier 373171169Smlaier /* If we don't have FIONREAD, we might waste some space here */ 374171169Smlaier if (evbuffer_expand(buf, howmuch) == -1) 375171169Smlaier return (-1); 376171169Smlaier 377171169Smlaier /* We can append new data at this point */ 378171169Smlaier p = buf->buffer + buf->off; 379171169Smlaier 380171169Smlaier#ifndef WIN32 381171169Smlaier n = read(fd, p, howmuch); 382171169Smlaier if (n == -1) 383171169Smlaier return (-1); 384171169Smlaier if (n == 0) 385171169Smlaier return (0); 386171169Smlaier#else 387171169Smlaier n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL); 388171169Smlaier if (n == 0) 389171169Smlaier return (-1); 390171169Smlaier if (dwBytesRead == 0) 391171169Smlaier return (0); 392171169Smlaier n = dwBytesRead; 393171169Smlaier#endif 394171169Smlaier 395171169Smlaier buf->off += n; 396171169Smlaier 397171169Smlaier /* Tell someone about changes in this buffer */ 398171169Smlaier if (buf->off != oldoff && buf->cb != NULL) 399171169Smlaier (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 400171169Smlaier 401171169Smlaier return (n); 402171169Smlaier} 403171169Smlaier 404171169Smlaierint 405171169Smlaierevbuffer_write(struct evbuffer *buffer, int fd) 406171169Smlaier{ 407171169Smlaier int n; 408171169Smlaier#ifdef WIN32 409171169Smlaier DWORD dwBytesWritten; 410171169Smlaier#endif 411171169Smlaier 412171169Smlaier#ifndef WIN32 413171169Smlaier n = write(fd, buffer->buffer, buffer->off); 414171169Smlaier if (n == -1) 415171169Smlaier return (-1); 416171169Smlaier if (n == 0) 417171169Smlaier return (0); 418171169Smlaier#else 419171169Smlaier n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL); 420171169Smlaier if (n == 0) 421171169Smlaier return (-1); 422171169Smlaier if (dwBytesWritten == 0) 423171169Smlaier return (0); 424171169Smlaier n = dwBytesWritten; 425171169Smlaier#endif 426171169Smlaier evbuffer_drain(buffer, n); 427171169Smlaier 428171169Smlaier return (n); 429171169Smlaier} 430171169Smlaier 431171169Smlaieru_char * 432171169Smlaierevbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len) 433171169Smlaier{ 434171169Smlaier size_t remain = buffer->off; 435171169Smlaier u_char *search = buffer->buffer; 436171169Smlaier u_char *p; 437171169Smlaier 438171169Smlaier while ((p = memchr(search, *what, remain)) != NULL) { 439171169Smlaier remain = buffer->off - (size_t)(search - buffer->buffer); 440171169Smlaier if (remain < len) 441171169Smlaier break; 442171169Smlaier if (memcmp(p, what, len) == 0) 443171169Smlaier return (p); 444171169Smlaier search = p + 1; 445171169Smlaier } 446171169Smlaier 447171169Smlaier return (NULL); 448171169Smlaier} 449171169Smlaier 450171169Smlaiervoid evbuffer_setcb(struct evbuffer *buffer, 451171169Smlaier void (*cb)(struct evbuffer *, size_t, size_t, void *), 452171169Smlaier void *cbarg) 453171169Smlaier{ 454171169Smlaier buffer->cb = cb; 455171169Smlaier buffer->cbarg = cbarg; 456171169Smlaier} 457