Import OpenNTPD 3.6 (the OpenBSD version, not the portable).
[dragonfly.git] / contrib / ntpd / buffer.c
1 /*      $OpenBSD: buffer.c,v 1.3 2004/08/10 19:18:23 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 int     buf_write(int, struct buf *);
32 void    buf_enqueue(struct msgbuf *, struct buf *);
33 void    buf_dequeue(struct msgbuf *, struct buf *);
34
35 struct buf *
36 buf_open(ssize_t len)
37 {
38         struct buf      *buf;
39
40         if ((buf = calloc(1, sizeof(struct buf))) == NULL)
41                 return (NULL);
42         if ((buf->buf = malloc(len)) == NULL) {
43                 free(buf);
44                 return (NULL);
45         }
46         buf->size = len;
47
48         return (buf);
49 }
50
51 int
52 buf_add(struct buf *buf, void *data, ssize_t len)
53 {
54         if (buf->wpos + len > buf->size)
55                 return (-1);
56
57         memcpy(buf->buf + buf->wpos, data, len);
58         buf->wpos += len;
59         return (0);
60 }
61
62 int
63 buf_close(struct msgbuf *msgbuf, struct buf *buf)
64 {
65         buf_enqueue(msgbuf, buf);
66         return (1);
67 }
68
69 int
70 buf_write(int sock, struct buf *buf)
71 {
72         ssize_t n;
73
74         if ((n = write(sock, buf->buf + buf->rpos,
75             buf->size - buf->rpos)) == -1) {
76                 if (errno == EAGAIN)    /* cannot write immediately */
77                         return (0);
78                 else
79                         return (-1);
80         }
81
82         if (n == 0) {                   /* connection closed */
83                 errno = 0;
84                 return (-2);
85         }
86
87         if (n < buf->size - buf->rpos) {        /* not all data written yet */
88                 buf->rpos += n;
89                 return (0);
90         } else
91                 return (1);
92 }
93
94 void
95 buf_free(struct buf *buf)
96 {
97         free(buf->buf);
98         free(buf);
99 }
100
101 void
102 msgbuf_init(struct msgbuf *msgbuf)
103 {
104         msgbuf->queued = 0;
105         msgbuf->fd = -1;
106         TAILQ_INIT(&msgbuf->bufs);
107 }
108
109 void
110 msgbuf_clear(struct msgbuf *msgbuf)
111 {
112         struct buf      *buf;
113
114         while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
115                 buf_dequeue(msgbuf, buf);
116 }
117
118 int
119 msgbuf_write(struct msgbuf *msgbuf)
120 {
121         /*
122          * possible race here
123          * when we cannot write out data completely from a buffer,
124          * we MUST return and NOT try to write out stuff from later buffers -
125          * the socket might have become writeable again
126          */
127         struct iovec     iov[IOV_MAX];
128         struct buf      *buf, *next;
129         int              i = 0;
130         ssize_t          n;
131
132         bzero(&iov, sizeof(iov));
133         TAILQ_FOREACH(buf, &msgbuf->bufs, entries) {
134                 if (i >= IOV_MAX)
135                         break;
136                 iov[i].iov_base = buf->buf + buf->rpos;
137                 iov[i].iov_len = buf->size - buf->rpos;
138                 i++;
139         }
140
141         if ((n = writev(msgbuf->fd, iov, i)) == -1) {
142                 if (errno == EAGAIN)    /* cannot write immediately */
143                         return (0);
144                 else
145                         return (-1);
146         }
147
148         if (n == 0) {                   /* connection closed */
149                 errno = 0;
150                 return (-2);
151         }
152
153         for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
154             buf = next) {
155                 next = TAILQ_NEXT(buf, entries);
156                 if (n >= buf->size - buf->rpos) {
157                         n -= buf->size - buf->rpos;
158                         buf_dequeue(msgbuf, buf);
159                 } else {
160                         buf->rpos += n;
161                         n = 0;
162                 }
163         }
164
165         return (0);
166 }
167
168 void
169 buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
170 {
171         TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entries);
172         msgbuf->queued++;
173 }
174
175 void
176 buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
177 {
178         TAILQ_REMOVE(&msgbuf->bufs, buf, entries);
179         msgbuf->queued--;
180         buf_free(buf);
181 }