1 /* $OpenBSD: iobuf.c,v 1.5 2013/05/24 17:03:14 eric 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 if (io->buf) 71 free(io->buf); 72 73 while ((q = io->outq)) { 74 io->outq = q->next; 75 free(q); 76 } 77 78 memset(io, 0, sizeof (*io)); 79 } 80 81 void 82 iobuf_drain(struct iobuf *io, size_t n) 83 { 84 struct ioqbuf *q; 85 size_t left = n; 86 87 while ((q = io->outq) && left) { 88 if ((q->wpos - q->rpos) > left) { 89 q->rpos += left; 90 left = 0; 91 } else { 92 left -= q->wpos - q->rpos; 93 io->outq = q->next; 94 free(q); 95 } 96 } 97 98 io->queued -= (n - left); 99 if (io->outq == NULL) 100 io->outqlast = NULL; 101 } 102 103 int 104 iobuf_extend(struct iobuf *io, size_t n) 105 { 106 char *t; 107 108 if (n > io->max) 109 return (-1); 110 111 if (io->max - io->size < n) 112 return (-1); 113 114 t = realloc(io->buf, io->size + n); 115 if (t == NULL) 116 return (-1); 117 118 io->size += n; 119 io->buf = t; 120 121 return (0); 122 } 123 124 size_t 125 iobuf_left(struct iobuf *io) 126 { 127 return io->size - io->wpos; 128 } 129 130 size_t 131 iobuf_space(struct iobuf *io) 132 { 133 return io->size - (io->wpos - io->rpos); 134 } 135 136 size_t 137 iobuf_len(struct iobuf *io) 138 { 139 return io->wpos - io->rpos; 140 } 141 142 char * 143 iobuf_data(struct iobuf *io) 144 { 145 return io->buf + io->rpos; 146 } 147 148 void 149 iobuf_drop(struct iobuf *io, size_t n) 150 { 151 if (n >= iobuf_len(io)) { 152 io->rpos = io->wpos = 0; 153 return; 154 } 155 156 io->rpos += n; 157 } 158 159 char * 160 iobuf_getline(struct iobuf *iobuf, size_t *rlen) 161 { 162 char *buf; 163 size_t len, i; 164 165 buf = iobuf_data(iobuf); 166 len = iobuf_len(iobuf); 167 168 for (i = 0; i + 1 <= len; i++) 169 if (buf[i] == '\n') { 170 /* Note: the returned address points into the iobuf 171 * buffer. We NUL-end it for convenience, and discard 172 * the data from the iobuf, so that the caller doesn't 173 * have to do it. The data remains "valid" as long 174 * as the iobuf does not overwrite it, that is until 175 * the next call to iobuf_normalize() or iobuf_extend(). 176 */ 177 iobuf_drop(iobuf, i + 1); 178 len = (i && buf[i - 1] == '\r') ? i - 1 : i; 179 buf[len] = '\0'; 180 if (rlen) 181 *rlen = len; 182 return (buf); 183 } 184 185 return (NULL); 186 } 187 188 void 189 iobuf_normalize(struct iobuf *io) 190 { 191 if (io->rpos == 0) 192 return; 193 194 if (io->rpos == io->wpos) { 195 io->rpos = io->wpos = 0; 196 return; 197 } 198 199 memmove(io->buf, io->buf + io->rpos, io->wpos - io->rpos); 200 io->wpos -= io->rpos; 201 io->rpos = 0; 202 } 203 204 ssize_t 205 iobuf_read(struct iobuf *io, int fd) 206 { 207 ssize_t n; 208 209 n = read(fd, io->buf + io->wpos, iobuf_left(io)); 210 if (n == -1) { 211 /* XXX is this really what we want? */ 212 if (errno == EAGAIN || errno == EINTR) 213 return (IOBUF_WANT_READ); 214 return (IOBUF_ERROR); 215 } 216 if (n == 0) 217 return (IOBUF_CLOSED); 218 219 io->wpos += n; 220 221 return (n); 222 } 223 224 struct ioqbuf * 225 ioqbuf_alloc(struct iobuf *io, size_t len) 226 { 227 struct ioqbuf *q; 228 229 if (len < IOBUFQ_MIN) 230 len = IOBUFQ_MIN; 231 232 if ((q = malloc(sizeof(*q) + len)) == NULL) 233 return (NULL); 234 235 q->rpos = 0; 236 q->wpos = 0; 237 q->size = len; 238 q->next = NULL; 239 q->buf = (char *)(q) + sizeof(*q); 240 241 if (io->outqlast == NULL) 242 io->outq = q; 243 else 244 io->outqlast->next = q; 245 io->outqlast = q; 246 247 return (q); 248 } 249 250 size_t 251 iobuf_queued(struct iobuf *io) 252 { 253 return io->queued; 254 } 255 256 void * 257 iobuf_reserve(struct iobuf *io, size_t len) 258 { 259 struct ioqbuf *q; 260 void *r; 261 262 if (len == 0) 263 return (NULL); 264 265 if (((q = io->outqlast) == NULL) || q->size - q->wpos <= len) { 266 if ((q = ioqbuf_alloc(io, len)) == NULL) 267 return (NULL); 268 } 269 270 r = q->buf + q->wpos; 271 q->wpos += len; 272 io->queued += len; 273 274 return (r); 275 } 276 277 int 278 iobuf_queue(struct iobuf *io, const void *data, size_t len) 279 { 280 void *buf; 281 282 if (len == 0) 283 return (0); 284 285 if ((buf = iobuf_reserve(io, len)) == NULL) 286 return (-1); 287 288 memmove(buf, data, len); 289 290 return (0); 291 } 292 293 int 294 iobuf_queuev(struct iobuf *io, const struct iovec *iov, int iovcnt) 295 { 296 int i; 297 size_t len = 0; 298 char *buf; 299 300 for (i = 0; i < iovcnt; i++) 301 len += iov[i].iov_len; 302 303 if ((buf = iobuf_reserve(io, len)) == NULL) 304 return (-1); 305 306 for (i = 0; i < iovcnt; i++) { 307 if (iov[i].iov_len == 0) 308 continue; 309 memmove(buf, iov[i].iov_base, iov[i].iov_len); 310 buf += iov[i].iov_len; 311 } 312 313 return (0); 314 315 } 316 317 int 318 iobuf_fqueue(struct iobuf *io, const char *fmt, ...) 319 { 320 va_list ap; 321 int len; 322 323 va_start(ap, fmt); 324 len = iobuf_vfqueue(io, fmt, ap); 325 va_end(ap); 326 327 return (len); 328 } 329 330 int 331 iobuf_vfqueue(struct iobuf *io, const char *fmt, va_list ap) 332 { 333 char *buf; 334 int len; 335 336 len = vasprintf(&buf, fmt, ap); 337 338 if (len == -1) 339 return (-1); 340 341 len = iobuf_queue(io, buf, len); 342 free(buf); 343 344 return (len); 345 } 346 347 ssize_t 348 iobuf_write(struct iobuf *io, int fd) 349 { 350 struct iovec iov[IOV_MAX]; 351 struct ioqbuf *q; 352 int i; 353 ssize_t n; 354 355 i = 0; 356 for (q = io->outq; q ; q = q->next) { 357 if (i >= IOV_MAX) 358 break; 359 iov[i].iov_base = q->buf + q->rpos; 360 iov[i].iov_len = q->wpos - q->rpos; 361 i++; 362 } 363 364 n = writev(fd, iov, i); 365 if (n == -1) { 366 if (errno == EAGAIN || errno == EINTR) 367 return (IOBUF_WANT_WRITE); 368 if (errno == EPIPE) 369 return (IOBUF_CLOSED); 370 return (IOBUF_ERROR); 371 } 372 373 iobuf_drain(io, n); 374 375 return (n); 376 } 377 378 int 379 iobuf_flush(struct iobuf *io, int fd) 380 { 381 ssize_t s; 382 383 while (io->queued) 384 if ((s = iobuf_write(io, fd)) < 0) 385 return (s); 386 387 return (0); 388 } 389 390 #ifdef IO_SSL 391 392 int 393 iobuf_flush_ssl(struct iobuf *io, void *ssl) 394 { 395 ssize_t s; 396 397 while (io->queued) 398 if ((s = iobuf_write_ssl(io, ssl) < 0)) 399 return (s); 400 401 return (0); 402 } 403 404 ssize_t 405 iobuf_write_ssl(struct iobuf *io, void *ssl) 406 { 407 struct ioqbuf *q; 408 int r; 409 ssize_t n; 410 411 q = io->outq; 412 n = SSL_write(ssl, q->buf + q->rpos, q->wpos - q->rpos); 413 if (n <= 0) { 414 switch ((r = SSL_get_error(ssl, n))) { 415 case SSL_ERROR_WANT_READ: 416 return (IOBUF_WANT_READ); 417 case SSL_ERROR_WANT_WRITE: 418 return (IOBUF_WANT_WRITE); 419 case SSL_ERROR_ZERO_RETURN: /* connection closed */ 420 return (IOBUF_CLOSED); 421 case SSL_ERROR_SYSCALL: 422 if (ERR_peek_last_error()) 423 return (IOBUF_SSLERROR); 424 if (r == 0) 425 errno = EPIPE; 426 return (IOBUF_ERROR); 427 default: 428 return (IOBUF_SSLERROR); 429 } 430 } 431 iobuf_drain(io, n); 432 433 return (n); 434 } 435 436 ssize_t 437 iobuf_read_ssl(struct iobuf *io, void *ssl) 438 { 439 ssize_t n; 440 int r; 441 442 n = SSL_read(ssl, io->buf + io->wpos, iobuf_left(io)); 443 if (n < 0) { 444 switch ((r = SSL_get_error(ssl, n))) { 445 case SSL_ERROR_WANT_READ: 446 return (IOBUF_WANT_READ); 447 case SSL_ERROR_WANT_WRITE: 448 return (IOBUF_WANT_WRITE); 449 case SSL_ERROR_SYSCALL: 450 if (ERR_peek_last_error()) 451 return (IOBUF_SSLERROR); 452 if (r == 0) 453 errno = EPIPE; 454 return (IOBUF_ERROR); 455 default: 456 return (IOBUF_SSLERROR); 457 } 458 } else if (n == 0) 459 return (IOBUF_CLOSED); 460 461 io->wpos += n; 462 463 return (n); 464 } 465 466 #endif /* IO_SSL */ 467