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