Merge from vendor branch CVS:
[dragonfly.git] / contrib / ntpd / buffer.c
1 /*      $OpenBSD: buffer.c,v 1.4 2004/09/15 00:05:29 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         /*
96          * possible race here
97          * when we cannot write out data completely from a buffer,
98          * we MUST return and NOT try to write out stuff from later buffers -
99          * the socket might have become writeable again
100          */
101         struct iovec     iov[IOV_MAX];
102         struct buf      *buf, *next;
103         int              i = 0;
104         ssize_t          n;
105
106         bzero(&iov, sizeof(iov));
107         TAILQ_FOREACH(buf, &msgbuf->bufs, entries) {
108                 if (i >= IOV_MAX)
109                         break;
110                 iov[i].iov_base = buf->buf + buf->rpos;
111                 iov[i].iov_len = buf->size - buf->rpos;
112                 i++;
113         }
114
115         if ((n = writev(msgbuf->fd, iov, i)) == -1) {
116                 if (errno == EAGAIN)    /* cannot write immediately */
117                         return (0);
118                 else
119                         return (-1);
120         }
121
122         if (n == 0) {                   /* connection closed */
123                 errno = 0;
124                 return (-2);
125         }
126
127         for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
128             buf = next) {
129                 next = TAILQ_NEXT(buf, entries);
130                 if (buf->rpos + n >= buf->size) {
131                         n -= buf->size - buf->rpos;
132                         buf_dequeue(msgbuf, buf);
133                 } else {
134                         buf->rpos += n;
135                         n = 0;
136                 }
137         }
138
139         return (0);
140 }
141
142 void
143 buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
144 {
145         TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entries);
146         msgbuf->queued++;
147 }
148
149 void
150 buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
151 {
152         TAILQ_REMOVE(&msgbuf->bufs, buf, entries);
153         msgbuf->queued--;
154         buf_free(buf);
155 }