diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2004-05-31 13:46:17 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2004-05-31 13:46:17 +0000 |
commit | d7c7c4844a02b9eb783517c118c1b77d75ccf603 (patch) | |
tree | 01e41bb1c6145f1d6978b6b48215ef11cba63972 /usr.sbin/ntpd/buffer.c | |
parent | 33097da5af566af8bfa55c87ab1aa6cf6c6654cd (diff) |
initial cut at ntpd.
it is just capable of answering (s)ntp4 requests with the local time
for now.
imsg/buffer and logging framework from bgpd, ntp protocol hackery
with Alexander Guy
Diffstat (limited to 'usr.sbin/ntpd/buffer.c')
-rw-r--r-- | usr.sbin/ntpd/buffer.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/usr.sbin/ntpd/buffer.c b/usr.sbin/ntpd/buffer.c new file mode 100644 index 00000000000..efc1bfffc8c --- /dev/null +++ b/usr.sbin/ntpd/buffer.c @@ -0,0 +1,182 @@ +/* $OpenBSD: buffer.c,v 1.1 2004/05/31 13:46:16 henning 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 <err.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); +} |