1 /* $OpenBSD: buffer.c,v 1.1 2004/04/28 06:53:12 brad Exp $ */ 2 3 /* 4 * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/types.h> 31 32 #ifdef HAVE_CONFIG_H 33 #include "config.h" 34 #endif 35 36 #ifdef HAVE_SYS_TIME_H 37 #include <sys/time.h> 38 #endif 39 40 #include <err.h> 41 #include <errno.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #ifdef HAVE_STDARG_H 46 #include <stdarg.h> 47 #endif 48 #ifdef HAVE_UNISTD_H 49 #include <unistd.h> 50 #endif 51 52 #include "event.h" 53 54 struct evbuffer * 55 evbuffer_new(void) 56 { 57 struct evbuffer *buffer; 58 59 buffer = calloc(1, sizeof(struct evbuffer)); 60 61 return (buffer); 62 } 63 64 void 65 evbuffer_free(struct evbuffer *buffer) 66 { 67 if (buffer->buffer != NULL) 68 free(buffer->buffer); 69 free(buffer); 70 } 71 72 /* 73 * This is a destructive add. The data from one buffer moves into 74 * the other buffer. 75 */ 76 77 int 78 evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) 79 { 80 int res; 81 res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off); 82 if (res == 0) 83 evbuffer_drain(inbuf, inbuf->off); 84 85 return (res); 86 } 87 88 int 89 evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...) 90 { 91 int res = -1; 92 char *msg; 93 va_list ap; 94 95 va_start(ap, fmt); 96 97 if (vasprintf(&msg, fmt, ap) == -1) 98 goto end; 99 100 res = strlen(msg); 101 if (evbuffer_add(buf, msg, res) == -1) 102 res = -1; 103 free(msg); 104 105 end: 106 va_end(ap); 107 108 return (res); 109 } 110 111 int 112 evbuffer_add(struct evbuffer *buf, u_char *data, size_t datlen) 113 { 114 size_t need = buf->off + datlen; 115 size_t oldoff = buf->off; 116 117 if (buf->totallen < need) { 118 void *newbuf; 119 int length = buf->totallen; 120 121 if (length < 256) 122 length = 256; 123 while (length < need) 124 length <<= 1; 125 126 if ((newbuf = realloc(buf->buffer, length)) == NULL) 127 return (-1); 128 129 buf->buffer = newbuf; 130 buf->totallen = length; 131 } 132 133 memcpy(buf->buffer + buf->off, data, datlen); 134 buf->off += datlen; 135 136 if (datlen && buf->cb != NULL) 137 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 138 139 return (0); 140 } 141 142 void 143 evbuffer_drain(struct evbuffer *buf, size_t len) 144 { 145 size_t oldoff = buf->off; 146 147 if (len >= buf->off) { 148 buf->off = 0; 149 goto done; 150 } 151 152 memmove(buf->buffer, buf->buffer + len, buf->off - len); 153 buf->off -= len; 154 155 done: 156 /* Tell someone about changes in this buffer */ 157 if (buf->off != oldoff && buf->cb != NULL) 158 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 159 160 } 161 162 int 163 evbuffer_read(struct evbuffer *buffer, int fd, int howmuch) 164 { 165 u_char inbuf[4096]; 166 int n; 167 168 if (howmuch < 0 || howmuch > sizeof(inbuf)) 169 howmuch = sizeof(inbuf); 170 171 n = read(fd, inbuf, howmuch); 172 if (n == -1) 173 return (-1); 174 if (n == 0) 175 return (0); 176 177 evbuffer_add(buffer, inbuf, n); 178 179 return (n); 180 } 181 182 int 183 evbuffer_write(struct evbuffer *buffer, int fd) 184 { 185 int n; 186 187 n = write(fd, buffer->buffer, buffer->off); 188 if (n == -1) 189 return (-1); 190 if (n == 0) 191 return (0); 192 193 evbuffer_drain(buffer, n); 194 195 return (n); 196 } 197 198 u_char * 199 evbuffer_find(struct evbuffer *buffer, u_char *what, size_t len) 200 { 201 size_t remain = buffer->off; 202 u_char *search = buffer->buffer; 203 u_char *p; 204 205 while ((p = memchr(search, *what, remain)) != NULL && remain >= len) { 206 if (memcmp(p, what, len) == 0) 207 return (p); 208 209 search = p + 1; 210 remain = buffer->off - (size_t)(search - buffer->buffer); 211 } 212 213 return (NULL); 214 } 215 216 void evbuffer_setcb(struct evbuffer *buffer, 217 void (*cb)(struct evbuffer *, size_t, size_t, void *), 218 void *cbarg) 219 { 220 buffer->cb = cb; 221 buffer->cbarg = cbarg; 222 } 223