|
|
- /* $OpenBSD: buffer.c,v 1.2 2004/07/12 09:22:38 dtucker Exp $ */
-
- /*
- * Copyright (c) 2003, 2004 Henning Brauer <henning@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 MIND, 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 <sys/types.h>
- #include <sys/uio.h>
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <limits.h>
- #include <string.h>
- #include <unistd.h>
-
- #include "ntpd.h"
-
- int buf_write(int, struct buf *);
- void buf_enqueue(struct msgbuf *, struct buf *);
- void buf_dequeue(struct msgbuf *, struct buf *);
-
- struct buf *
- buf_open(ssize_t len)
- {
- struct buf *buf;
-
- if ((buf = calloc(1, sizeof(struct buf))) == NULL)
- return (NULL);
- if ((buf->buf = malloc(len)) == NULL) {
- free(buf);
- return (NULL);
- }
- buf->size = len;
-
- return (buf);
- }
-
- int
- buf_add(struct buf *buf, void *data, ssize_t len)
- {
- if (buf->wpos + len > buf->size)
- return (-1);
-
- memcpy(buf->buf + buf->wpos, data, len);
- buf->wpos += len;
- return (0);
- }
-
- int
- buf_close(struct msgbuf *msgbuf, struct buf *buf)
- {
- buf_enqueue(msgbuf, buf);
- return (1);
- }
-
- int
- buf_write(int sock, struct buf *buf)
- {
- ssize_t n;
-
- if ((n = write(sock, buf->buf + buf->rpos,
- buf->size - buf->rpos)) == -1) {
- if (errno == EAGAIN) /* cannot write immediately */
- return (0);
- else
- return (-1);
- }
-
- if (n == 0) { /* connection closed */
- errno = 0;
- return (-2);
- }
-
- if (n < buf->size - buf->rpos) { /* not all data written yet */
- buf->rpos += n;
- return (0);
- } else
- return (1);
- }
-
- void
- buf_free(struct buf *buf)
- {
- free(buf->buf);
- free(buf);
- }
-
- void
- msgbuf_init(struct msgbuf *msgbuf)
- {
- msgbuf->queued = 0;
- msgbuf->fd = -1;
- TAILQ_INIT(&msgbuf->bufs);
- }
-
- void
- msgbuf_clear(struct msgbuf *msgbuf)
- {
- struct buf *buf;
-
- while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
- buf_dequeue(msgbuf, buf);
- }
-
- int
- msgbuf_write(struct msgbuf *msgbuf)
- {
- /*
- * possible race here
- * when we cannot write out data completely from a buffer,
- * we MUST return and NOT try to write out stuff from later buffers -
- * the socket might have become writeable again
- */
- struct iovec iov[IOV_MAX];
- struct buf *buf, *next;
- int i = 0;
- ssize_t n;
-
- bzero(&iov, sizeof(iov));
- TAILQ_FOREACH(buf, &msgbuf->bufs, entries) {
- if (i >= IOV_MAX)
- break;
- iov[i].iov_base = buf->buf + buf->rpos;
- iov[i].iov_len = buf->size - buf->rpos;
- i++;
- }
-
- if ((n = writev(msgbuf->fd, iov, i)) == -1) {
- if (errno == EAGAIN) /* cannot write immediately */
- return (0);
- else
- return (-1);
- }
-
- if (n == 0) { /* connection closed */
- errno = 0;
- return (-2);
- }
-
- for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
- buf = next) {
- next = TAILQ_NEXT(buf, entries);
- if (n >= buf->size - buf->rpos) {
- n -= buf->size - buf->rpos;
- buf_dequeue(msgbuf, buf);
- } else {
- buf->rpos += n;
- n = 0;
- }
- }
-
- return (0);
- }
-
- void
- buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
- {
- TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entries);
- msgbuf->queued++;
- }
-
- void
- buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
- {
- TAILQ_REMOVE(&msgbuf->bufs, buf, entries);
- msgbuf->queued--;
- buf_free(buf);
- }
|