Merge from vendor branch BSDTAR:
[dragonfly.git] / contrib / ntpd / buffer.c
1 /*      $OpenBSD: src/usr.sbin/ntpd/buffer.c,v 1.6 2005/03/23 11:36:35 henning Exp $ */
2
3 /*
4  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include <sys/types.h>
20 #include <sys/uio.h>
21
22 #include <errno.h>
23 #include <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include "ntpd.h"
30
31 void    buf_enqueue(struct msgbuf *, struct buf *);
32 void    buf_dequeue(struct msgbuf *, struct buf *);
33
34 struct buf *
35 buf_open(size_t len)
36 {
37         struct buf      *buf;
38
39         if ((buf = calloc(1, sizeof(struct buf))) == NULL)
40                 return (NULL);
41         if ((buf->buf = malloc(len)) == NULL) {
42                 free(buf);
43                 return (NULL);
44         }
45         buf->size = len;
46
47         return (buf);
48 }
49
50 int
51 buf_add(struct buf *buf, void *data, size_t len)
52 {
53         if (buf->wpos + len > buf->size)
54                 return (-1);
55
56         memcpy(buf->buf + buf->wpos, data, len);
57         buf->wpos += len;
58         return (0);
59 }
60
61 int
62 buf_close(struct msgbuf *msgbuf, struct buf *buf)
63 {
64         buf_enqueue(msgbuf, buf);
65         return (1);
66 }
67
68 void
69 buf_free(struct buf *buf)
70 {
71         free(buf->buf);
72         free(buf);
73 }
74
75 void
76 msgbuf_init(struct msgbuf *msgbuf)
77 {
78         msgbuf->queued = 0;
79         msgbuf->fd = -1;
80         TAILQ_INIT(&msgbuf->bufs);
81 }
82
83 void
84 msgbuf_clear(struct msgbuf *msgbuf)
85 {
86         struct buf      *buf;
87
88         while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
89                 buf_dequeue(msgbuf, buf);
90 }
91
92 int
93 msgbuf_write(struct msgbuf *msgbuf)
94 {
95         struct iovec     iov[IOV_MAX];
96         struct buf      *buf, *next;
97         int              i = 0;
98         ssize_t          n;
99
100         bzero(&iov, sizeof(iov));
101         TAILQ_FOREACH(buf, &msgbuf->bufs, entries) {
102                 if (i >= IOV_MAX)
103                         break;
104                 iov[i].iov_base = buf->buf + buf->rpos;
105                 iov[i].iov_len = buf->size - buf->rpos;
106                 i++;
107         }
108
109         if ((n = writev(msgbuf->fd, iov, i)) == -1) {
110                 if (errno == EAGAIN)    /* cannot write immediately */
111                         return (0);
112                 else
113                         return (-1);
114         }
115
116         if (n == 0) {                   /* connection closed */
117                 errno = 0;
118                 return (-2);
119         }
120
121         for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
122             buf = next) {
123                 next = TAILQ_NEXT(buf, entries);
124                 if (buf->rpos + n >= buf->size) {
125                         n -= buf->size - buf->rpos;
126                         buf_dequeue(msgbuf, buf);
127                 } else {
128                         buf->rpos += n;
129                         n = 0;
130                 }
131         }
132
133         return (0);
134 }
135
136 void
137 buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
138 {
139         TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entries);
140         msgbuf->queued++;
141 }
142
143 void
144 buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
145 {
146         TAILQ_REMOVE(&msgbuf->bufs, buf, entries);
147         msgbuf->queued--;
148         buf_free(buf);
149 }