1 /* $OpenBSD: iobuf.c,v 1.11 2019/06/12 17:42:53 eric Exp $ */
3 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
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.
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.
18 #include <sys/types.h>
19 #include <sys/socket.h>
31 #include <openssl/err.h>
32 #include <openssl/ssl.h>
37 #define IOBUF_MAX 65536
38 #define IOBUFQ_MIN 4096
40 struct ioqbuf *ioqbuf_alloc(struct iobuf *, size_t);
41 void iobuf_drain(struct iobuf *, size_t);
44 iobuf_init(struct iobuf *io, size_t size, size_t max)
46 memset(io, 0, sizeof *io);
57 if ((io->buf = calloc(size, 1)) == NULL)
67 iobuf_clear(struct iobuf *io)
73 while ((q = io->outq)) {
78 memset(io, 0, sizeof (*io));
82 iobuf_drain(struct iobuf *io, size_t n)
87 while ((q = io->outq) && left) {
88 if ((q->wpos - q->rpos) > left) {
92 left -= q->wpos - q->rpos;
98 io->queued -= (n - left);
104 iobuf_extend(struct iobuf *io, size_t n)
111 if (io->max - io->size < n)
114 t = recallocarray(io->buf, io->size, io->size + n, 1);
125 iobuf_left(struct iobuf *io)
127 return io->size - io->wpos;
131 iobuf_space(struct iobuf *io)
133 return io->size - (io->wpos - io->rpos);
137 iobuf_len(struct iobuf *io)
139 return io->wpos - io->rpos;
143 iobuf_data(struct iobuf *io)
145 return io->buf + io->rpos;
149 iobuf_drop(struct iobuf *io, size_t n)
151 if (n >= iobuf_len(io)) {
152 io->rpos = io->wpos = 0;
160 iobuf_getline(struct iobuf *iobuf, size_t *rlen)
165 buf = iobuf_data(iobuf);
166 len = iobuf_len(iobuf);
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().
177 iobuf_drop(iobuf, i + 1);
178 len = (i && buf[i - 1] == '\r') ? i - 1 : i;
189 iobuf_normalize(struct iobuf *io)
194 if (io->rpos == io->wpos) {
195 io->rpos = io->wpos = 0;
199 memmove(io->buf, io->buf + io->rpos, io->wpos - io->rpos);
200 io->wpos -= io->rpos;
205 iobuf_read(struct iobuf *io, int fd)
209 n = read(fd, io->buf + io->wpos, iobuf_left(io));
211 /* XXX is this really what we want? */
212 if (errno == EAGAIN || errno == EINTR)
213 return (IOBUF_WANT_READ);
214 return (IOBUF_ERROR);
217 return (IOBUF_CLOSED);
225 ioqbuf_alloc(struct iobuf *io, size_t len)
229 if (len < IOBUFQ_MIN)
232 if ((q = malloc(sizeof(*q) + len)) == NULL)
239 q->buf = (char *)(q) + sizeof(*q);
241 if (io->outqlast == NULL)
244 io->outqlast->next = q;
251 iobuf_queued(struct iobuf *io)
257 iobuf_reserve(struct iobuf *io, size_t len)
265 if (((q = io->outqlast) == NULL) || q->size - q->wpos <= len) {
266 if ((q = ioqbuf_alloc(io, len)) == NULL)
270 r = q->buf + q->wpos;
278 iobuf_queue(struct iobuf *io, const void *data, size_t len)
285 if ((buf = iobuf_reserve(io, len)) == NULL)
288 memmove(buf, data, len);
294 iobuf_queuev(struct iobuf *io, const struct iovec *iov, int iovcnt)
300 for (i = 0; i < iovcnt; i++)
301 len += iov[i].iov_len;
303 if ((buf = iobuf_reserve(io, len)) == NULL)
306 for (i = 0; i < iovcnt; i++) {
307 if (iov[i].iov_len == 0)
309 memmove(buf, iov[i].iov_base, iov[i].iov_len);
310 buf += iov[i].iov_len;
318 iobuf_fqueue(struct iobuf *io, const char *fmt, ...)
324 len = iobuf_vfqueue(io, fmt, ap);
331 iobuf_vfqueue(struct iobuf *io, const char *fmt, va_list ap)
336 len = vasprintf(&buf, fmt, ap);
341 len = iobuf_queue(io, buf, len);
348 iobuf_write(struct iobuf *io, int fd)
350 struct iovec iov[IOV_MAX];
356 for (q = io->outq; q ; q = q->next) {
359 iov[i].iov_base = q->buf + q->rpos;
360 iov[i].iov_len = q->wpos - q->rpos;
364 n = writev(fd, iov, i);
366 if (errno == EAGAIN || errno == EINTR)
367 return (IOBUF_WANT_WRITE);
369 return (IOBUF_CLOSED);
370 return (IOBUF_ERROR);
379 iobuf_flush(struct iobuf *io, int fd)
384 if ((s = iobuf_write(io, fd)) < 0)
393 iobuf_flush_tls(struct iobuf *io, void *tls)
398 if ((s = iobuf_write_tls(io, tls)) < 0)
405 iobuf_write_tls(struct iobuf *io, void *tls)
412 n = SSL_write(tls, q->buf + q->rpos, q->wpos - q->rpos);
414 switch ((r = SSL_get_error(tls, 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_TLSERROR);
426 return (IOBUF_ERROR);
428 return (IOBUF_TLSERROR);
437 iobuf_read_tls(struct iobuf *io, void *tls)
442 n = SSL_read(tls, io->buf + io->wpos, iobuf_left(io));
444 switch ((r = SSL_get_error(tls, 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_TLSERROR);
454 return (IOBUF_ERROR);
456 return (IOBUF_TLSERROR);
459 return (IOBUF_CLOSED);