1 ce062d50 2019-08-21 martijn /* $OpenBSD: iobuf.c,v 1.11 2019/06/12 17:42:53 eric Exp $ */
3 ce062d50 2019-08-21 martijn * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
5 ce062d50 2019-08-21 martijn * Permission to use, copy, modify, and distribute this software for any
6 ce062d50 2019-08-21 martijn * purpose with or without fee is hereby granted, provided that the above
7 ce062d50 2019-08-21 martijn * copyright notice and this permission notice appear in all copies.
9 ce062d50 2019-08-21 martijn * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 ce062d50 2019-08-21 martijn * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 ce062d50 2019-08-21 martijn * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 ce062d50 2019-08-21 martijn * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 ce062d50 2019-08-21 martijn * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 ce062d50 2019-08-21 martijn * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 ce062d50 2019-08-21 martijn * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 957c2372 2019-11-14 martijn #define _GNU_SOURCE 1
19 13f08f83 2019-11-14 martijn #define _BSD_SOURCE 1
21 ce062d50 2019-08-21 martijn #include <sys/types.h>
22 ce062d50 2019-08-21 martijn #include <sys/socket.h>
23 ce062d50 2019-08-21 martijn #include <sys/uio.h>
25 ce062d50 2019-08-21 martijn #include <errno.h>
26 ce062d50 2019-08-21 martijn #include <limits.h>
27 ce062d50 2019-08-21 martijn #include <stdarg.h>
28 ce062d50 2019-08-21 martijn #include <stdio.h>
29 ce062d50 2019-08-21 martijn #include <stdlib.h>
30 ce062d50 2019-08-21 martijn #include <string.h>
31 ce062d50 2019-08-21 martijn #include <unistd.h>
33 ce062d50 2019-08-21 martijn #ifdef IO_TLS
34 ce062d50 2019-08-21 martijn #include <openssl/err.h>
35 ce062d50 2019-08-21 martijn #include <openssl/ssl.h>
38 957c2372 2019-11-14 martijn #include "openbsd-compat.h"
39 ce062d50 2019-08-21 martijn #include "iobuf.h"
41 ce062d50 2019-08-21 martijn #define IOBUF_MAX 65536
42 ce062d50 2019-08-21 martijn #define IOBUFQ_MIN 4096
44 ce062d50 2019-08-21 martijn struct ioqbuf *ioqbuf_alloc(struct iobuf *, size_t);
45 ce062d50 2019-08-21 martijn void iobuf_drain(struct iobuf *, size_t);
48 ce062d50 2019-08-21 martijn iobuf_init(struct iobuf *io, size_t size, size_t max)
50 ce062d50 2019-08-21 martijn memset(io, 0, sizeof *io);
52 ce062d50 2019-08-21 martijn if (max == 0)
53 ce062d50 2019-08-21 martijn max = IOBUF_MAX;
55 ce062d50 2019-08-21 martijn if (size == 0)
56 ce062d50 2019-08-21 martijn size = max;
58 ce062d50 2019-08-21 martijn if (size > max)
59 ce062d50 2019-08-21 martijn return (-1);
61 ce062d50 2019-08-21 martijn if ((io->buf = calloc(size, 1)) == NULL)
62 ce062d50 2019-08-21 martijn return (-1);
64 ce062d50 2019-08-21 martijn io->size = size;
65 ce062d50 2019-08-21 martijn io->max = max;
67 ce062d50 2019-08-21 martijn return (0);
71 ce062d50 2019-08-21 martijn iobuf_clear(struct iobuf *io)
73 ce062d50 2019-08-21 martijn struct ioqbuf *q;
75 ce062d50 2019-08-21 martijn free(io->buf);
77 ce062d50 2019-08-21 martijn while ((q = io->outq)) {
78 ce062d50 2019-08-21 martijn io->outq = q->next;
82 ce062d50 2019-08-21 martijn memset(io, 0, sizeof (*io));
86 ce062d50 2019-08-21 martijn iobuf_drain(struct iobuf *io, size_t n)
88 ce062d50 2019-08-21 martijn struct ioqbuf *q;
89 ce062d50 2019-08-21 martijn size_t left = n;
91 ce062d50 2019-08-21 martijn while ((q = io->outq) && left) {
92 ce062d50 2019-08-21 martijn if ((q->wpos - q->rpos) > left) {
93 ce062d50 2019-08-21 martijn q->rpos += left;
94 ce062d50 2019-08-21 martijn left = 0;
96 ce062d50 2019-08-21 martijn left -= q->wpos - q->rpos;
97 ce062d50 2019-08-21 martijn io->outq = q->next;
102 ce062d50 2019-08-21 martijn io->queued -= (n - left);
103 ce062d50 2019-08-21 martijn if (io->outq == NULL)
104 ce062d50 2019-08-21 martijn io->outqlast = NULL;
108 ce062d50 2019-08-21 martijn iobuf_extend(struct iobuf *io, size_t n)
110 ce062d50 2019-08-21 martijn char *t;
112 ce062d50 2019-08-21 martijn if (n > io->max)
113 ce062d50 2019-08-21 martijn return (-1);
115 ce062d50 2019-08-21 martijn if (io->max - io->size < n)
116 ce062d50 2019-08-21 martijn return (-1);
118 ce062d50 2019-08-21 martijn t = recallocarray(io->buf, io->size, io->size + n, 1);
119 ce062d50 2019-08-21 martijn if (t == NULL)
120 ce062d50 2019-08-21 martijn return (-1);
122 ce062d50 2019-08-21 martijn io->size += n;
123 ce062d50 2019-08-21 martijn io->buf = t;
125 ce062d50 2019-08-21 martijn return (0);
129 ce062d50 2019-08-21 martijn iobuf_left(struct iobuf *io)
131 ce062d50 2019-08-21 martijn return io->size - io->wpos;
135 ce062d50 2019-08-21 martijn iobuf_space(struct iobuf *io)
137 ce062d50 2019-08-21 martijn return io->size - (io->wpos - io->rpos);
141 ce062d50 2019-08-21 martijn iobuf_len(struct iobuf *io)
143 ce062d50 2019-08-21 martijn return io->wpos - io->rpos;
147 ce062d50 2019-08-21 martijn iobuf_data(struct iobuf *io)
149 ce062d50 2019-08-21 martijn return io->buf + io->rpos;
153 ce062d50 2019-08-21 martijn iobuf_drop(struct iobuf *io, size_t n)
155 ce062d50 2019-08-21 martijn if (n >= iobuf_len(io)) {
156 ce062d50 2019-08-21 martijn io->rpos = io->wpos = 0;
160 ce062d50 2019-08-21 martijn io->rpos += n;
164 ce062d50 2019-08-21 martijn iobuf_getline(struct iobuf *iobuf, size_t *rlen)
166 ce062d50 2019-08-21 martijn char *buf;
167 ce062d50 2019-08-21 martijn size_t len, i;
169 ce062d50 2019-08-21 martijn buf = iobuf_data(iobuf);
170 ce062d50 2019-08-21 martijn len = iobuf_len(iobuf);
172 ce062d50 2019-08-21 martijn for (i = 0; i + 1 <= len; i++)
173 ce062d50 2019-08-21 martijn if (buf[i] == '\n') {
174 ce062d50 2019-08-21 martijn /* Note: the returned address points into the iobuf
175 ce062d50 2019-08-21 martijn * buffer. We NUL-end it for convenience, and discard
176 ce062d50 2019-08-21 martijn * the data from the iobuf, so that the caller doesn't
177 ce062d50 2019-08-21 martijn * have to do it. The data remains "valid" as long
178 ce062d50 2019-08-21 martijn * as the iobuf does not overwrite it, that is until
179 ce062d50 2019-08-21 martijn * the next call to iobuf_normalize() or iobuf_extend().
181 ce062d50 2019-08-21 martijn iobuf_drop(iobuf, i + 1);
182 ce062d50 2019-08-21 martijn len = (i && buf[i - 1] == '\r') ? i - 1 : i;
183 ce062d50 2019-08-21 martijn buf[len] = '\0';
184 ce062d50 2019-08-21 martijn if (rlen)
185 ce062d50 2019-08-21 martijn *rlen = len;
186 ce062d50 2019-08-21 martijn return (buf);
189 ce062d50 2019-08-21 martijn return (NULL);
193 ce062d50 2019-08-21 martijn iobuf_normalize(struct iobuf *io)
195 ce062d50 2019-08-21 martijn if (io->rpos == 0)
198 ce062d50 2019-08-21 martijn if (io->rpos == io->wpos) {
199 ce062d50 2019-08-21 martijn io->rpos = io->wpos = 0;
203 ce062d50 2019-08-21 martijn memmove(io->buf, io->buf + io->rpos, io->wpos - io->rpos);
204 ce062d50 2019-08-21 martijn io->wpos -= io->rpos;
205 ce062d50 2019-08-21 martijn io->rpos = 0;
209 ce062d50 2019-08-21 martijn iobuf_read(struct iobuf *io, int fd)
211 ce062d50 2019-08-21 martijn ssize_t n;
213 ce062d50 2019-08-21 martijn n = read(fd, io->buf + io->wpos, iobuf_left(io));
214 ce062d50 2019-08-21 martijn if (n == -1) {
215 ce062d50 2019-08-21 martijn /* XXX is this really what we want? */
216 ce062d50 2019-08-21 martijn if (errno == EAGAIN || errno == EINTR)
217 ce062d50 2019-08-21 martijn return (IOBUF_WANT_READ);
218 ce062d50 2019-08-21 martijn return (IOBUF_ERROR);
220 ce062d50 2019-08-21 martijn if (n == 0)
221 ce062d50 2019-08-21 martijn return (IOBUF_CLOSED);
223 ce062d50 2019-08-21 martijn io->wpos += n;
225 ce062d50 2019-08-21 martijn return (n);
228 ce062d50 2019-08-21 martijn struct ioqbuf *
229 ce062d50 2019-08-21 martijn ioqbuf_alloc(struct iobuf *io, size_t len)
231 ce062d50 2019-08-21 martijn struct ioqbuf *q;
233 ce062d50 2019-08-21 martijn if (len < IOBUFQ_MIN)
234 ce062d50 2019-08-21 martijn len = IOBUFQ_MIN;
236 ce062d50 2019-08-21 martijn if ((q = malloc(sizeof(*q) + len)) == NULL)
237 ce062d50 2019-08-21 martijn return (NULL);
239 ce062d50 2019-08-21 martijn q->rpos = 0;
240 ce062d50 2019-08-21 martijn q->wpos = 0;
241 ce062d50 2019-08-21 martijn q->size = len;
242 ce062d50 2019-08-21 martijn q->next = NULL;
243 ce062d50 2019-08-21 martijn q->buf = (char *)(q) + sizeof(*q);
245 ce062d50 2019-08-21 martijn if (io->outqlast == NULL)
246 ce062d50 2019-08-21 martijn io->outq = q;
248 ce062d50 2019-08-21 martijn io->outqlast->next = q;
249 ce062d50 2019-08-21 martijn io->outqlast = q;
251 ce062d50 2019-08-21 martijn return (q);
255 ce062d50 2019-08-21 martijn iobuf_queued(struct iobuf *io)
257 ce062d50 2019-08-21 martijn return io->queued;
261 ce062d50 2019-08-21 martijn iobuf_reserve(struct iobuf *io, size_t len)
263 ce062d50 2019-08-21 martijn struct ioqbuf *q;
264 ce062d50 2019-08-21 martijn void *r;
266 ce062d50 2019-08-21 martijn if (len == 0)
267 ce062d50 2019-08-21 martijn return (NULL);
269 ce062d50 2019-08-21 martijn if (((q = io->outqlast) == NULL) || q->size - q->wpos <= len) {
270 ce062d50 2019-08-21 martijn if ((q = ioqbuf_alloc(io, len)) == NULL)
271 ce062d50 2019-08-21 martijn return (NULL);
274 ce062d50 2019-08-21 martijn r = q->buf + q->wpos;
275 ce062d50 2019-08-21 martijn q->wpos += len;
276 ce062d50 2019-08-21 martijn io->queued += len;
278 ce062d50 2019-08-21 martijn return (r);
282 ce062d50 2019-08-21 martijn iobuf_queue(struct iobuf *io, const void *data, size_t len)
284 ce062d50 2019-08-21 martijn void *buf;
286 ce062d50 2019-08-21 martijn if (len == 0)
287 ce062d50 2019-08-21 martijn return (0);
289 ce062d50 2019-08-21 martijn if ((buf = iobuf_reserve(io, len)) == NULL)
290 ce062d50 2019-08-21 martijn return (-1);
292 ce062d50 2019-08-21 martijn memmove(buf, data, len);
294 ce062d50 2019-08-21 martijn return (len);
298 ce062d50 2019-08-21 martijn iobuf_queuev(struct iobuf *io, const struct iovec *iov, int iovcnt)
301 ce062d50 2019-08-21 martijn size_t len = 0;
302 ce062d50 2019-08-21 martijn char *buf;
304 ce062d50 2019-08-21 martijn for (i = 0; i < iovcnt; i++)
305 ce062d50 2019-08-21 martijn len += iov[i].iov_len;
307 ce062d50 2019-08-21 martijn if ((buf = iobuf_reserve(io, len)) == NULL)
308 ce062d50 2019-08-21 martijn return (-1);
310 ce062d50 2019-08-21 martijn for (i = 0; i < iovcnt; i++) {
311 ce062d50 2019-08-21 martijn if (iov[i].iov_len == 0)
312 ce062d50 2019-08-21 martijn continue;
313 ce062d50 2019-08-21 martijn memmove(buf, iov[i].iov_base, iov[i].iov_len);
314 ce062d50 2019-08-21 martijn buf += iov[i].iov_len;
317 ce062d50 2019-08-21 martijn return (0);
322 ce062d50 2019-08-21 martijn iobuf_fqueue(struct iobuf *io, const char *fmt, ...)
324 ce062d50 2019-08-21 martijn va_list ap;
325 ce062d50 2019-08-21 martijn int len;
327 ce062d50 2019-08-21 martijn va_start(ap, fmt);
328 ce062d50 2019-08-21 martijn len = iobuf_vfqueue(io, fmt, ap);
329 ce062d50 2019-08-21 martijn va_end(ap);
331 ce062d50 2019-08-21 martijn return (len);
335 ce062d50 2019-08-21 martijn iobuf_vfqueue(struct iobuf *io, const char *fmt, va_list ap)
337 ce062d50 2019-08-21 martijn char *buf;
338 ce062d50 2019-08-21 martijn int len;
340 ce062d50 2019-08-21 martijn len = vasprintf(&buf, fmt, ap);
342 ce062d50 2019-08-21 martijn if (len == -1)
343 ce062d50 2019-08-21 martijn return (-1);
345 ce062d50 2019-08-21 martijn len = iobuf_queue(io, buf, len);
346 ce062d50 2019-08-21 martijn free(buf);
348 ce062d50 2019-08-21 martijn return (len);
352 ce062d50 2019-08-21 martijn iobuf_write(struct iobuf *io, int fd)
354 ce062d50 2019-08-21 martijn struct iovec iov[IOV_MAX];
355 ce062d50 2019-08-21 martijn struct ioqbuf *q;
357 ce062d50 2019-08-21 martijn ssize_t n;
360 ce062d50 2019-08-21 martijn for (q = io->outq; q ; q = q->next) {
361 ce062d50 2019-08-21 martijn if (i >= IOV_MAX)
363 ce062d50 2019-08-21 martijn iov[i].iov_base = q->buf + q->rpos;
364 ce062d50 2019-08-21 martijn iov[i].iov_len = q->wpos - q->rpos;
368 ce062d50 2019-08-21 martijn n = writev(fd, iov, i);
369 ce062d50 2019-08-21 martijn if (n == -1) {
370 ce062d50 2019-08-21 martijn if (errno == EAGAIN || errno == EINTR)
371 ce062d50 2019-08-21 martijn return (IOBUF_WANT_WRITE);
372 ce062d50 2019-08-21 martijn if (errno == EPIPE)
373 ce062d50 2019-08-21 martijn return (IOBUF_CLOSED);
374 ce062d50 2019-08-21 martijn return (IOBUF_ERROR);
377 ce062d50 2019-08-21 martijn iobuf_drain(io, n);
379 ce062d50 2019-08-21 martijn return (n);
383 ce062d50 2019-08-21 martijn iobuf_flush(struct iobuf *io, int fd)
385 ce062d50 2019-08-21 martijn ssize_t s;
387 ce062d50 2019-08-21 martijn while (io->queued)
388 ce062d50 2019-08-21 martijn if ((s = iobuf_write(io, fd)) < 0)
389 ce062d50 2019-08-21 martijn return (s);
391 ce062d50 2019-08-21 martijn return (0);
394 ce062d50 2019-08-21 martijn #ifdef IO_TLS
397 ce062d50 2019-08-21 martijn iobuf_flush_tls(struct iobuf *io, void *tls)
399 ce062d50 2019-08-21 martijn ssize_t s;
401 ce062d50 2019-08-21 martijn while (io->queued)
402 ce062d50 2019-08-21 martijn if ((s = iobuf_write_tls(io, tls)) < 0)
403 ce062d50 2019-08-21 martijn return (s);
405 ce062d50 2019-08-21 martijn return (0);
409 ce062d50 2019-08-21 martijn iobuf_write_tls(struct iobuf *io, void *tls)
411 ce062d50 2019-08-21 martijn struct ioqbuf *q;
413 ce062d50 2019-08-21 martijn ssize_t n;
415 ce062d50 2019-08-21 martijn q = io->outq;
416 ce062d50 2019-08-21 martijn n = SSL_write(tls, q->buf + q->rpos, q->wpos - q->rpos);
417 ce062d50 2019-08-21 martijn if (n <= 0) {
418 ce062d50 2019-08-21 martijn switch ((r = SSL_get_error(tls, n))) {
419 ce062d50 2019-08-21 martijn case SSL_ERROR_WANT_READ:
420 ce062d50 2019-08-21 martijn return (IOBUF_WANT_READ);
421 ce062d50 2019-08-21 martijn case SSL_ERROR_WANT_WRITE:
422 ce062d50 2019-08-21 martijn return (IOBUF_WANT_WRITE);
423 ce062d50 2019-08-21 martijn case SSL_ERROR_ZERO_RETURN: /* connection closed */
424 ce062d50 2019-08-21 martijn return (IOBUF_CLOSED);
425 ce062d50 2019-08-21 martijn case SSL_ERROR_SYSCALL:
426 ce062d50 2019-08-21 martijn if (ERR_peek_last_error())
427 ce062d50 2019-08-21 martijn return (IOBUF_TLSERROR);
428 ce062d50 2019-08-21 martijn if (r == 0)
429 ce062d50 2019-08-21 martijn errno = EPIPE;
430 ce062d50 2019-08-21 martijn return (IOBUF_ERROR);
431 ce062d50 2019-08-21 martijn default:
432 ce062d50 2019-08-21 martijn return (IOBUF_TLSERROR);
435 ce062d50 2019-08-21 martijn iobuf_drain(io, n);
437 ce062d50 2019-08-21 martijn return (n);
441 ce062d50 2019-08-21 martijn iobuf_read_tls(struct iobuf *io, void *tls)
443 ce062d50 2019-08-21 martijn ssize_t n;
446 ce062d50 2019-08-21 martijn n = SSL_read(tls, io->buf + io->wpos, iobuf_left(io));
447 ce062d50 2019-08-21 martijn if (n < 0) {
448 ce062d50 2019-08-21 martijn switch ((r = SSL_get_error(tls, n))) {
449 ce062d50 2019-08-21 martijn case SSL_ERROR_WANT_READ:
450 ce062d50 2019-08-21 martijn return (IOBUF_WANT_READ);
451 ce062d50 2019-08-21 martijn case SSL_ERROR_WANT_WRITE:
452 ce062d50 2019-08-21 martijn return (IOBUF_WANT_WRITE);
453 ce062d50 2019-08-21 martijn case SSL_ERROR_SYSCALL:
454 ce062d50 2019-08-21 martijn if (ERR_peek_last_error())
455 ce062d50 2019-08-21 martijn return (IOBUF_TLSERROR);
456 ce062d50 2019-08-21 martijn if (r == 0)
457 ce062d50 2019-08-21 martijn errno = EPIPE;
458 ce062d50 2019-08-21 martijn return (IOBUF_ERROR);
459 ce062d50 2019-08-21 martijn default:
460 ce062d50 2019-08-21 martijn return (IOBUF_TLSERROR);
462 ce062d50 2019-08-21 martijn } else if (n == 0)
463 ce062d50 2019-08-21 martijn return (IOBUF_CLOSED);
465 ce062d50 2019-08-21 martijn io->wpos += n;
467 ce062d50 2019-08-21 martijn return (n);
470 ce062d50 2019-08-21 martijn #endif /* IO_TLS */