1 /* $OpenBSD: iobuf.c,v 1.1.1.1 2018/04/27 16:14:36 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <sys/uio.h> 22 23 #include <errno.h> 24 #include <limits.h> 25 #include <stdarg.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #ifdef IO_SSL 32 #include <openssl/err.h> 33 #include <openssl/ssl.h> 34 #endif 35 36 #include "iobuf.h" 37 38 #define IOBUF_MAX 65536 39 #define IOBUFQ_MIN 4096 40 41 struct ioqbuf *ioqbuf_alloc(struct iobuf *, size_t); 42 void iobuf_drain(struct iobuf *, size_t); 43 44 int 45 iobuf_init(struct iobuf *io, size_t size, size_t max) 46 { 47 memset(io, 0, sizeof *io); 48 49 if (max == 0) 50 max = IOBUF_MAX; 51 52 if (size == 0) 53 size = max; 54 55 if (size > max) 56 return (-1); 57 58 if ((io->buf = calloc(size, 1)) == NULL) 59 return (-1); 60 61 io->size = size; 62 io->max = max; 63 64 return (0); 65 } 66 67 void 68 iobuf_clear(struct iobuf *io) 69 { 70 struct ioqbuf *q; 71 72 free(io->buf); 73 74 while ((q = io->outq)) { 75 io->outq = q->next; 76 free(q); 77 } 78 79 memset(io, 0, sizeof (*io)); 80 } 81 82 void 83 iobuf_drain(struct iobuf *io, size_t n) 84 { 85 struct ioqbuf *q; 86 size_t left = n; 87 88 while ((q = io->outq) && left) { 89 if ((q->wpos - q->rpos) > left) { 90 q->rpos += left; 91 left = 0; 92 } else { 93 left -= q->wpos - q->rpos; 94 io->outq = q->next; 95 free(q); 96 } 97 } 98 99 io->queued -= (n - left); 100 if (io->outq == NULL) 101 io->outqlast = NULL; 102 } 103 104 int 105 iobuf_extend(struct iobuf *io, size_t n) 106 { 107 char *t; 108 109 if (n > io->max) 110 return (-1); 111 112 if (io->max - io->size < n) 113 return (-1); 114 115 t = recallocarray(io->buf, io->size, io->size + n, 1); 116 if (t == NULL) 117 return (-1); 118 119 io->size += n; 120 io->buf = t; 121 122 return (0); 123 } 124 125 size_t 126 iobuf_left(struct iobuf *io) 127 { 128 return io->size - io->wpos; 129 } 130 131 size_t 132 iobuf_space(struct iobuf *io) 133 { 134 return io->size - (io->wpos - io->rpos); 135 } 136 137 size_t 138 iobuf_len(struct iobuf *io) 139 { 140 return io->wpos - io->rpos; 141 } 142 143 char * 144 iobuf_data(struct iobuf *io) 145 { 146 return io->buf + io->rpos; 147 } 148 149 void 150 iobuf_drop(struct iobuf *io, size_t n) 151 { 152 if (n >= iobuf_len(io)) { 153 io->rpos = io->wpos = 0; 154 return; 155 } 156 157 io->rpos += n; 158 } 159 160 char * 161 iobuf_getline(struct iobuf *iobuf, size_t *rlen) 162 { 163 char *buf; 164 size_t len, i; 165 166 buf = iobuf_data(iobuf); 167 len = iobuf_len(iobuf); 168 169 for (i = 0; i + 1 <= len; i++) 170 if (buf[i] == '\n') { 171 /* Note: the returned address points into the iobuf 172 * buffer. We NUL-end it for convenience, and discard 173 * the data from the iobuf, so that the caller doesn't 174 * have to do it. The data remains "valid" as long 175 * as the iobuf does not overwrite it, that is until 176 * the next call to iobuf_normalize() or iobuf_extend(). 177 */ 178 iobuf_drop(iobuf, i + 1); 179 len = (i && buf[i - 1] == '\r') ? i - 1 : i; 180 buf[len] = '\0'; 181 if (rlen) 182 *rlen = len; 183 return (buf); 184 } 185 186 return (NULL); 187 } 188 189 void 190 iobuf_normalize(struct iobuf *io) 191 { 192 if (io->rpos == 0) 193 return; 194 195 if (io->rpos == io->wpos) { 196 io->rpos = io->wpos = 0; 197 return; 198 } 199 200 memmove(io->buf, io->buf + io->rpos, io->wpos - io->rpos); 201 io->wpos -= io->rpos; 202 io->rpos = 0; 203 } 204 205 ssize_t 206 iobuf_read(struct iobuf *io, int fd) 207 { 208 ssize_t n; 209 210 n = read(fd, io->buf + io->wpos, iobuf_left(io)); 211 if (n == -1) { 212 /* XXX is this really what we want? */ 213 if (errno == EAGAIN || errno == EINTR) 214 return (IOBUF_WANT_READ); 215 return (IOBUF_ERROR); 216 } 217 if (n == 0) 218 return (IOBUF_CLOSED); 219 220 io->wpos += n; 221 222 return (n); 223 } 224 225 struct ioqbuf * 226 ioqbuf_alloc(struct iobuf *io, size_t len) 227 { 228 struct ioqbuf *q; 229 230 if (len < IOBUFQ_MIN) 231 len = IOBUFQ_MIN; 232 233 if ((q = malloc(sizeof(*q) + len)) == NULL) 234 return (NULL); 235 236 q->rpos = 0; 237 q->wpos = 0; 238 q->size = len; 239 q->next = NULL; 240 q->buf = (char *)(q) + sizeof(*q); 241 242 if (io->outqlast == NULL) 243 io->outq = q; 244 else 245 io->outqlast->next = q; 246 io->outqlast = q; 247 248 return (q); 249 } 250 251 size_t 252 iobuf_queued(struct iobuf *io) 253 { 254 return io->queued; 255 } 256 257 void * 258 iobuf_reserve(struct iobuf *io, size_t len) 259 { 260 struct ioqbuf *q; 261 void *r; 262 263 if (len == 0) 264 return (NULL); 265 266 if (((q = io->outqlast) == NULL) || q->size - q->wpos <= len) { 267 if ((q = ioqbuf_alloc(io, len)) == NULL) 268 return (NULL); 269 } 270 271 r = q->buf + q->wpos; 272 q->wpos += len; 273 io->queued += len; 274 275 return (r); 276 } 277 278 int 279 iobuf_queue(struct iobuf *io, const void *data, size_t len) 280 { 281 void *buf; 282 283 if (len == 0) 284 return (0); 285 286 if ((buf = iobuf_reserve(io, len)) == NULL) 287 return (-1); 288 289 memmove(buf, data, len); 290 291 return (len); 292 } 293 294 int 295 iobuf_queuev(struct iobuf *io, const struct iovec *iov, int iovcnt) 296 { 297 int i; 298 size_t len = 0; 299 char *buf; 300 301 for (i = 0; i < iovcnt; i++) 302 len += iov[i].iov_len; 303 304 if ((buf = iobuf_reserve(io, len)) == NULL) 305 return (-1); 306 307 for (i = 0; i < iovcnt; i++) { 308 if (iov[i].iov_len == 0) 309 continue; 310 memmove(buf, iov[i].iov_base, iov[i].iov_len); 311 buf += iov[i].iov_len; 312 } 313 314 return (0); 315 316 } 317 318 int 319 iobuf_fqueue(struct iobuf *io, const char *fmt, ...) 320 { 321 va_list ap; 322 int len; 323 324 va_start(ap, fmt); 325 len = iobuf_vfqueue(io, fmt, ap); 326 va_end(ap); 327 328 return (len); 329 } 330 331 int 332 iobuf_vfqueue(struct iobuf *io, const char *fmt, va_list ap) 333 { 334 char *buf; 335 int len; 336 337 len = vasprintf(&buf, fmt, ap); 338 339 if (len == -1) 340 return (-1); 341 342 len = iobuf_queue(io, buf, len); 343 free(buf); 344 345 return (len); 346 } 347 348 ssize_t 349 iobuf_write(struct iobuf *io, int fd) 350 { 351 struct iovec iov[IOV_MAX]; 352 struct ioqbuf *q; 353 int i; 354 ssize_t n; 355 356 i = 0; 357 for (q = io->outq; q ; q = q->next) { 358 if (i >= IOV_MAX) 359 break; 360 iov[i].iov_base = q->buf + q->rpos; 361 iov[i].iov_len = q->wpos - q->rpos; 362 i++; 363 } 364 365 n = writev(fd, iov, i); 366 if (n == -1) { 367 if (errno == EAGAIN || errno == EINTR) 368 return (IOBUF_WANT_WRITE); 369 if (errno == EPIPE) 370 return (IOBUF_CLOSED); 371 return (IOBUF_ERROR); 372 } 373 374 iobuf_drain(io, n); 375 376 return (n); 377 } 378 379 int 380 iobuf_flush(struct iobuf *io, int fd) 381 { 382 ssize_t s; 383 384 while (io->queued) 385 if ((s = iobuf_write(io, fd)) < 0) 386 return (s); 387 388 return (0); 389 } 390 391 #ifdef IO_SSL 392 393 int 394 iobuf_flush_ssl(struct iobuf *io, void *ssl) 395 { 396 ssize_t s; 397 398 while (io->queued) 399 if ((s = iobuf_write_ssl(io, ssl)) < 0) 400 return (s); 401 402 return (0); 403 } 404 405 ssize_t 406 iobuf_write_ssl(struct iobuf *io, void *ssl) 407 { 408 struct ioqbuf *q; 409 int r; 410 ssize_t n; 411 412 q = io->outq; 413 n = SSL_write(ssl, q->buf + q->rpos, q->wpos - q->rpos); 414 if (n <= 0) { 415 switch ((r = SSL_get_error(ssl, n))) { 416 case SSL_ERROR_WANT_READ: 417 return (IOBUF_WANT_READ); 418 case SSL_ERROR_WANT_WRITE: 419 return (IOBUF_WANT_WRITE); 420 case SSL_ERROR_ZERO_RETURN: /* connection closed */ 421 return (IOBUF_CLOSED); 422 case SSL_ERROR_SYSCALL: 423 if (ERR_peek_last_error()) 424 return (IOBUF_SSLERROR); 425 if (r == 0) 426 errno = EPIPE; 427 return (IOBUF_ERROR); 428 default: 429 return (IOBUF_SSLERROR); 430 } 431 } 432 iobuf_drain(io, n); 433 434 return (n); 435 } 436 437 ssize_t 438 iobuf_read_ssl(struct iobuf *io, void *ssl) 439 { 440 ssize_t n; 441 int r; 442 443 n = SSL_read(ssl, io->buf + io->wpos, iobuf_left(io)); 444 if (n < 0) { 445 switch ((r = SSL_get_error(ssl, n))) { 446 case SSL_ERROR_WANT_READ: 447 return (IOBUF_WANT_READ); 448 case SSL_ERROR_WANT_WRITE: 449 return (IOBUF_WANT_WRITE); 450 case SSL_ERROR_SYSCALL: 451 if (ERR_peek_last_error()) 452 return (IOBUF_SSLERROR); 453 if (r == 0) 454 errno = EPIPE; 455 return (IOBUF_ERROR); 456 default: 457 return (IOBUF_SSLERROR); 458 } 459 } else if (n == 0) 460 return (IOBUF_CLOSED); 461 462 io->wpos += n; 463 464 return (n); 465 } 466 467 #endif /* IO_SSL */ 468