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