diff options
Diffstat (limited to 'smtpd/iobuf.c')
-rw-r--r-- | smtpd/iobuf.c | 462 |
1 files changed, 0 insertions, 462 deletions
diff --git a/smtpd/iobuf.c b/smtpd/iobuf.c deleted file mode 100644 index dec10660..00000000 --- a/smtpd/iobuf.c +++ /dev/null @@ -1,462 +0,0 @@ -/* $OpenBSD: iobuf.c,v 1.13 2020/04/24 11:34:07 eric Exp $ */ -/* - * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "includes.h" - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/uio.h> - -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#ifdef IO_TLS -#include <openssl/err.h> -#include <openssl/ssl.h> -#endif - -#include "iobuf.h" - -#define IOBUF_MAX 65536 -#define IOBUFQ_MIN 4096 - -struct ioqbuf *ioqbuf_alloc(struct iobuf *, size_t); -void iobuf_drain(struct iobuf *, size_t); - -int -iobuf_init(struct iobuf *io, size_t size, size_t max) -{ - memset(io, 0, sizeof *io); - - if (max == 0) - max = IOBUF_MAX; - - if (size == 0) - size = max; - - if (size > max) - return (-1); - - if ((io->buf = calloc(size, 1)) == NULL) - return (-1); - - io->size = size; - io->max = max; - - return (0); -} - -void -iobuf_clear(struct iobuf *io) -{ - struct ioqbuf *q; - - free(io->buf); - - while ((q = io->outq)) { - io->outq = q->next; - free(q); - } - - memset(io, 0, sizeof (*io)); -} - -void -iobuf_drain(struct iobuf *io, size_t n) -{ - struct ioqbuf *q; - size_t left = n; - - while ((q = io->outq) && left) { - if ((q->wpos - q->rpos) > left) { - q->rpos += left; - left = 0; - } else { - left -= q->wpos - q->rpos; - io->outq = q->next; - free(q); - } - } - - io->queued -= (n - left); - if (io->outq == NULL) - io->outqlast = NULL; -} - -int -iobuf_extend(struct iobuf *io, size_t n) -{ - char *t; - - if (n > io->max) - return (-1); - - if (io->max - io->size < n) - return (-1); - - t = recallocarray(io->buf, io->size, io->size + n, 1); - if (t == NULL) - return (-1); - - io->size += n; - io->buf = t; - - return (0); -} - -size_t -iobuf_left(struct iobuf *io) -{ - return io->size - io->wpos; -} - -size_t -iobuf_space(struct iobuf *io) -{ - return io->size - (io->wpos - io->rpos); -} - -size_t -iobuf_len(struct iobuf *io) -{ - return io->wpos - io->rpos; -} - -char * -iobuf_data(struct iobuf *io) -{ - return io->buf + io->rpos; -} - -void -iobuf_drop(struct iobuf *io, size_t n) -{ - if (n >= iobuf_len(io)) { - io->rpos = io->wpos = 0; - return; - } - - io->rpos += n; -} - -char * -iobuf_getline(struct iobuf *iobuf, size_t *rlen) -{ - char *buf; - size_t len, i; - - buf = iobuf_data(iobuf); - len = iobuf_len(iobuf); - - for (i = 0; i + 1 <= len; i++) - if (buf[i] == '\n') { - /* Note: the returned address points into the iobuf - * buffer. We NUL-end it for convenience, and discard - * the data from the iobuf, so that the caller doesn't - * have to do it. The data remains "valid" as long - * as the iobuf does not overwrite it, that is until - * the next call to iobuf_normalize() or iobuf_extend(). - */ - iobuf_drop(iobuf, i + 1); - buf[i] = '\0'; - if (rlen) - *rlen = i; - return (buf); - } - - return (NULL); -} - -void -iobuf_normalize(struct iobuf *io) -{ - if (io->rpos == 0) - return; - - if (io->rpos == io->wpos) { - io->rpos = io->wpos = 0; - return; - } - - memmove(io->buf, io->buf + io->rpos, io->wpos - io->rpos); - io->wpos -= io->rpos; - io->rpos = 0; -} - -ssize_t -iobuf_read(struct iobuf *io, int fd) -{ - ssize_t n; - - n = read(fd, io->buf + io->wpos, iobuf_left(io)); - if (n == -1) { - /* XXX is this really what we want? */ - if (errno == EAGAIN || errno == EINTR) - return (IOBUF_WANT_READ); - return (IOBUF_ERROR); - } - if (n == 0) - return (IOBUF_CLOSED); - - io->wpos += n; - - return (n); -} - -struct ioqbuf * -ioqbuf_alloc(struct iobuf *io, size_t len) -{ - struct ioqbuf *q; - - if (len < IOBUFQ_MIN) - len = IOBUFQ_MIN; - - if ((q = malloc(sizeof(*q) + len)) == NULL) - return (NULL); - - q->rpos = 0; - q->wpos = 0; - q->size = len; - q->next = NULL; - q->buf = (char *)(q) + sizeof(*q); - - if (io->outqlast == NULL) - io->outq = q; - else - io->outqlast->next = q; - io->outqlast = q; - - return (q); -} - -size_t -iobuf_queued(struct iobuf *io) -{ - return io->queued; -} - -void * -iobuf_reserve(struct iobuf *io, size_t len) -{ - struct ioqbuf *q; - void *r; - - if (len == 0) - return (NULL); - - if (((q = io->outqlast) == NULL) || q->size - q->wpos <= len) { - if ((q = ioqbuf_alloc(io, len)) == NULL) - return (NULL); - } - - r = q->buf + q->wpos; - q->wpos += len; - io->queued += len; - - return (r); -} - -int -iobuf_queue(struct iobuf *io, const void *data, size_t len) -{ - void *buf; - - if (len == 0) - return (0); - - if ((buf = iobuf_reserve(io, len)) == NULL) - return (-1); - - memmove(buf, data, len); - - return (len); -} - -int -iobuf_queuev(struct iobuf *io, const struct iovec *iov, int iovcnt) -{ - int i; - size_t len = 0; - char *buf; - - for (i = 0; i < iovcnt; i++) - len += iov[i].iov_len; - - if ((buf = iobuf_reserve(io, len)) == NULL) - return (-1); - - for (i = 0; i < iovcnt; i++) { - if (iov[i].iov_len == 0) - continue; - memmove(buf, iov[i].iov_base, iov[i].iov_len); - buf += iov[i].iov_len; - } - - return (0); - -} - -int -iobuf_fqueue(struct iobuf *io, const char *fmt, ...) -{ - va_list ap; - int len; - - va_start(ap, fmt); - len = iobuf_vfqueue(io, fmt, ap); - va_end(ap); - - return (len); -} - -int -iobuf_vfqueue(struct iobuf *io, const char *fmt, va_list ap) -{ - char *buf; - int len; - - len = vasprintf(&buf, fmt, ap); - - if (len == -1) - return (-1); - - len = iobuf_queue(io, buf, len); - free(buf); - - return (len); -} - -ssize_t -iobuf_write(struct iobuf *io, int fd) -{ - struct iovec iov[IOV_MAX]; - struct ioqbuf *q; - int i; - ssize_t n; - - i = 0; - for (q = io->outq; q ; q = q->next) { - if (i >= IOV_MAX) - break; - iov[i].iov_base = q->buf + q->rpos; - iov[i].iov_len = q->wpos - q->rpos; - i++; - } - - n = writev(fd, iov, i); - if (n == -1) { - if (errno == EAGAIN || errno == EINTR) - return (IOBUF_WANT_WRITE); - if (errno == EPIPE) - return (IOBUF_CLOSED); - return (IOBUF_ERROR); - } - - iobuf_drain(io, n); - - return (n); -} - -int -iobuf_flush(struct iobuf *io, int fd) -{ - ssize_t s; - - while (io->queued) - if ((s = iobuf_write(io, fd)) < 0) - return (s); - - return (0); -} - -#ifdef IO_TLS - -int -iobuf_flush_tls(struct iobuf *io, void *tls) -{ - ssize_t s; - - while (io->queued) - if ((s = iobuf_write_tls(io, tls)) < 0) - return (s); - - return (0); -} - -ssize_t -iobuf_write_tls(struct iobuf *io, void *tls) -{ - struct ioqbuf *q; - int r; - ssize_t n; - - q = io->outq; - n = SSL_write(tls, q->buf + q->rpos, q->wpos - q->rpos); - if (n <= 0) { - switch ((r = SSL_get_error(tls, n))) { - case SSL_ERROR_WANT_READ: - return (IOBUF_WANT_READ); - case SSL_ERROR_WANT_WRITE: - return (IOBUF_WANT_WRITE); - case SSL_ERROR_ZERO_RETURN: /* connection closed */ - return (IOBUF_CLOSED); - case SSL_ERROR_SYSCALL: - if (ERR_peek_last_error()) - return (IOBUF_TLSERROR); - return (IOBUF_ERROR); - default: - return (IOBUF_TLSERROR); - } - } - iobuf_drain(io, n); - - return (n); -} - -ssize_t -iobuf_read_tls(struct iobuf *io, void *tls) -{ - ssize_t n; - int r; - - n = SSL_read(tls, io->buf + io->wpos, iobuf_left(io)); - if (n < 0) { - switch ((r = SSL_get_error(tls, n))) { - case SSL_ERROR_WANT_READ: - return (IOBUF_WANT_READ); - case SSL_ERROR_WANT_WRITE: - return (IOBUF_WANT_WRITE); - case SSL_ERROR_SYSCALL: - if (ERR_peek_last_error()) - return (IOBUF_TLSERROR); - return (IOBUF_ERROR); - default: - return (IOBUF_TLSERROR); - } - } else if (n == 0) - return (IOBUF_CLOSED); - - io->wpos += n; - - return (n); -} - -#endif /* IO_TLS */ |