1 /* $OpenBSD: buffer.c,v 1.14 2007/03/19 15:12:49 millert 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 #ifdef HAVE_CONFIG_H 31 #include "config.h" 32 #endif 33 34 #ifdef HAVE_VASPRINTF 35 /* If we have vasprintf, we need to define this before we include stdio.h. */ 36 #define _GNU_SOURCE 37 #endif 38 39 #include <sys/types.h> 40 41 #ifdef HAVE_SYS_TIME_H 42 #include <sys/time.h> 43 #endif 44 45 #ifdef HAVE_SYS_IOCTL_H 46 #include <sys/ioctl.h> 47 #endif 48 49 #include <errno.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #ifdef HAVE_STDARG_H 54 #include <stdarg.h> 55 #endif 56 #ifdef HAVE_UNISTD_H 57 #include <unistd.h> 58 #endif 59 60 #include "event.h" 61 62 struct evbuffer * 63 evbuffer_new(void) 64 { 65 struct evbuffer *buffer; 66 67 buffer = calloc(1, sizeof(struct evbuffer)); 68 69 return (buffer); 70 } 71 72 void 73 evbuffer_free(struct evbuffer *buffer) 74 { 75 if (buffer->orig_buffer != NULL) 76 free(buffer->orig_buffer); 77 free(buffer); 78 } 79 80 /* 81 * This is a destructive add. The data from one buffer moves into 82 * the other buffer. 83 */ 84 85 #define SWAP(x,y) do { \ 86 (x)->buffer = (y)->buffer; \ 87 (x)->orig_buffer = (y)->orig_buffer; \ 88 (x)->misalign = (y)->misalign; \ 89 (x)->totallen = (y)->totallen; \ 90 (x)->off = (y)->off; \ 91 } while (0) 92 93 int 94 evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) 95 { 96 int res; 97 98 /* Short cut for better performance */ 99 if (outbuf->off == 0) { 100 struct evbuffer tmp; 101 size_t oldoff = inbuf->off; 102 103 /* Swap them directly */ 104 SWAP(&tmp, outbuf); 105 SWAP(outbuf, inbuf); 106 SWAP(inbuf, &tmp); 107 108 /* 109 * Optimization comes with a price; we need to notify the 110 * buffer if necessary of the changes. oldoff is the amount 111 * of data that we transferred from inbuf to outbuf 112 */ 113 if (inbuf->off != oldoff && inbuf->cb != NULL) 114 (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg); 115 if (oldoff && outbuf->cb != NULL) 116 (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg); 117 118 return (0); 119 } 120 121 res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off); 122 if (res == 0) { 123 /* We drain the input buffer on success */ 124 evbuffer_drain(inbuf, inbuf->off); 125 } 126 127 return (res); 128 } 129 130 int 131 evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) 132 { 133 char *buffer; 134 size_t space; 135 size_t oldoff = buf->off; 136 int sz; 137 va_list aq; 138 139 for (;;) { 140 buffer = (char *)buf->buffer + buf->off; 141 space = buf->totallen - buf->misalign - buf->off; 142 143 #ifndef va_copy 144 #define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list)) 145 #endif 146 va_copy(aq, ap); 147 148 #ifdef WIN32 149 sz = vsnprintf(buffer, space - 1, fmt, aq); 150 buffer[space - 1] = '\0'; 151 #else 152 sz = vsnprintf(buffer, space, fmt, aq); 153 #endif 154 155 va_end(aq); 156 157 if (sz == -1) 158 return (-1); 159 if (sz < space) { 160 buf->off += sz; 161 if (buf->cb != NULL) 162 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 163 return (sz); 164 } 165 if (evbuffer_expand(buf, sz + 1) == -1) 166 return (-1); 167 168 } 169 /* NOTREACHED */ 170 } 171 172 int 173 evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...) 174 { 175 int res = -1; 176 va_list ap; 177 178 va_start(ap, fmt); 179 res = evbuffer_add_vprintf(buf, fmt, ap); 180 va_end(ap); 181 182 return (res); 183 } 184 185 /* Reads data from an event buffer and drains the bytes read */ 186 187 int 188 evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen) 189 { 190 size_t nread = datlen; 191 if (nread >= buf->off) 192 nread = buf->off; 193 194 memcpy(data, buf->buffer, nread); 195 evbuffer_drain(buf, nread); 196 197 return (nread); 198 } 199 200 /* 201 * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'. 202 * The returned buffer needs to be freed by the called. 203 */ 204 205 char * 206 evbuffer_readline(struct evbuffer *buffer) 207 { 208 u_char *data = EVBUFFER_DATA(buffer); 209 size_t len = EVBUFFER_LENGTH(buffer); 210 char *line; 211 unsigned int i; 212 213 for (i = 0; i < len; i++) { 214 if (data[i] == '\r' || data[i] == '\n') 215 break; 216 } 217 218 if (i == len) 219 return (NULL); 220 221 if ((line = malloc(i + 1)) == NULL) { 222 fprintf(stderr, "%s: out of memory\n", __func__); 223 evbuffer_drain(buffer, i); 224 return (NULL); 225 } 226 227 memcpy(line, data, i); 228 line[i] = '\0'; 229 230 /* 231 * Some protocols terminate a line with '\r\n', so check for 232 * that, too. 233 */ 234 if ( i < len - 1 ) { 235 char fch = data[i], sch = data[i+1]; 236 237 /* Drain one more character if needed */ 238 if ( (sch == '\r' || sch == '\n') && sch != fch ) 239 i += 1; 240 } 241 242 evbuffer_drain(buffer, i + 1); 243 244 return (line); 245 } 246 247 /* Adds data to an event buffer */ 248 249 static inline void 250 evbuffer_align(struct evbuffer *buf) 251 { 252 memmove(buf->orig_buffer, buf->buffer, buf->off); 253 buf->buffer = buf->orig_buffer; 254 buf->misalign = 0; 255 } 256 257 /* Expands the available space in the event buffer to at least datlen */ 258 259 int 260 evbuffer_expand(struct evbuffer *buf, size_t datlen) 261 { 262 size_t need = buf->misalign + buf->off + datlen; 263 264 /* If we can fit all the data, then we don't have to do anything */ 265 if (buf->totallen >= need) 266 return (0); 267 268 /* 269 * If the misalignment fulfills our data needs, we just force an 270 * alignment to happen. Afterwards, we have enough space. 271 */ 272 if (buf->misalign >= datlen) { 273 evbuffer_align(buf); 274 } else { 275 void *newbuf; 276 size_t length = buf->totallen; 277 278 if (length < 256) 279 length = 256; 280 while (length < need) 281 length <<= 1; 282 283 if (buf->orig_buffer != buf->buffer) 284 evbuffer_align(buf); 285 if ((newbuf = realloc(buf->buffer, length)) == NULL) 286 return (-1); 287 288 buf->orig_buffer = buf->buffer = newbuf; 289 buf->totallen = length; 290 } 291 292 return (0); 293 } 294 295 int 296 evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen) 297 { 298 size_t need = buf->misalign + buf->off + datlen; 299 size_t oldoff = buf->off; 300 301 if (buf->totallen < need) { 302 if (evbuffer_expand(buf, datlen) == -1) 303 return (-1); 304 } 305 306 memcpy(buf->buffer + buf->off, data, datlen); 307 buf->off += datlen; 308 309 if (datlen && buf->cb != NULL) 310 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 311 312 return (0); 313 } 314 315 void 316 evbuffer_drain(struct evbuffer *buf, size_t len) 317 { 318 size_t oldoff = buf->off; 319 320 if (len >= buf->off) { 321 buf->off = 0; 322 buf->buffer = buf->orig_buffer; 323 buf->misalign = 0; 324 goto done; 325 } 326 327 buf->buffer += len; 328 buf->misalign += len; 329 330 buf->off -= len; 331 332 done: 333 /* Tell someone about changes in this buffer */ 334 if (buf->off != oldoff && buf->cb != NULL) 335 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 336 337 } 338 339 /* 340 * Reads data from a file descriptor into a buffer. 341 */ 342 343 #define EVBUFFER_MAX_READ 4096 344 345 int 346 evbuffer_read(struct evbuffer *buf, int fd, int howmuch) 347 { 348 u_char *p; 349 size_t oldoff = buf->off; 350 int n = EVBUFFER_MAX_READ; 351 #ifdef WIN32 352 DWORD dwBytesRead; 353 #endif 354 355 #ifdef FIONREAD 356 if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) { 357 n = EVBUFFER_MAX_READ; 358 } else if (n > EVBUFFER_MAX_READ && n > howmuch) { 359 /* 360 * It's possible that a lot of data is available for 361 * reading. We do not want to exhaust resources 362 * before the reader has a chance to do something 363 * about it. If the reader does not tell us how much 364 * data we should read, we artifically limit it. 365 */ 366 if (n > buf->totallen << 2) 367 n = buf->totallen << 2; 368 if (n < EVBUFFER_MAX_READ) 369 n = EVBUFFER_MAX_READ; 370 } 371 #endif 372 if (howmuch < 0 || howmuch > n) 373 howmuch = n; 374 375 /* If we don't have FIONREAD, we might waste some space here */ 376 if (evbuffer_expand(buf, howmuch) == -1) 377 return (-1); 378 379 /* We can append new data at this point */ 380 p = buf->buffer + buf->off; 381 382 #ifndef WIN32 383 n = read(fd, p, howmuch); 384 if (n == -1) 385 return (-1); 386 if (n == 0) 387 return (0); 388 #else 389 n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL); 390 if (n == 0) 391 return (-1); 392 if (dwBytesRead == 0) 393 return (0); 394 n = dwBytesRead; 395 #endif 396 397 buf->off += n; 398 399 /* Tell someone about changes in this buffer */ 400 if (buf->off != oldoff && buf->cb != NULL) 401 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 402 403 return (n); 404 } 405 406 int 407 evbuffer_write(struct evbuffer *buffer, int fd) 408 { 409 int n; 410 #ifdef WIN32 411 DWORD dwBytesWritten; 412 #endif 413 414 #ifndef WIN32 415 n = write(fd, buffer->buffer, buffer->off); 416 if (n == -1) 417 return (-1); 418 if (n == 0) 419 return (0); 420 #else 421 n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL); 422 if (n == 0) 423 return (-1); 424 if (dwBytesWritten == 0) 425 return (0); 426 n = dwBytesWritten; 427 #endif 428 evbuffer_drain(buffer, n); 429 430 return (n); 431 } 432 433 u_char * 434 evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len) 435 { 436 size_t remain = buffer->off; 437 u_char *search = buffer->buffer; 438 u_char *p; 439 440 while ((p = memchr(search, *what, remain)) != NULL) { 441 remain = buffer->off - (size_t)(search - buffer->buffer); 442 if (remain < len) 443 break; 444 if (memcmp(p, what, len) == 0) 445 return (p); 446 search = p + 1; 447 } 448 449 return (NULL); 450 } 451 452 void evbuffer_setcb(struct evbuffer *buffer, 453 void (*cb)(struct evbuffer *, size_t, size_t, void *), 454 void *cbarg) 455 { 456 buffer->cb = cb; 457 buffer->cbarg = cbarg; 458 } 459