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