1 /* $OpenBSD: buffer.c,v 1.9 2005/08/11 16:26: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 *
buf_open(size_t len)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
buf_add(struct buf * buf,void * data,size_t len)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
buf_close(struct msgbuf * msgbuf,struct buf * buf)62 buf_close(struct msgbuf *msgbuf, struct buf *buf)
63 {
64 buf_enqueue(msgbuf, buf);
65 return (1);
66 }
67
68 void
buf_free(struct buf * buf)69 buf_free(struct buf *buf)
70 {
71 free(buf->buf);
72 free(buf);
73 }
74
75 void
msgbuf_init(struct msgbuf * msgbuf)76 msgbuf_init(struct msgbuf *msgbuf)
77 {
78 msgbuf->queued = 0;
79 msgbuf->fd = -1;
80 TAILQ_INIT(&msgbuf->bufs);
81 }
82
83 void
msgbuf_clear(struct msgbuf * msgbuf)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
msgbuf_write(struct msgbuf * msgbuf)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, entry) {
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 || errno == EINTR ||
111 errno == ENOBUFS) /* try again later */
112 return (0);
113 else
114 return (-1);
115 }
116
117 if (n == 0) { /* connection closed */
118 errno = 0;
119 return (-2);
120 }
121
122 for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
123 buf = next) {
124 next = TAILQ_NEXT(buf, entry);
125 if (buf->rpos + n >= buf->size) {
126 n -= buf->size - buf->rpos;
127 buf_dequeue(msgbuf, buf);
128 } else {
129 buf->rpos += n;
130 n = 0;
131 }
132 }
133
134 return (0);
135 }
136
137 void
buf_enqueue(struct msgbuf * msgbuf,struct buf * buf)138 buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
139 {
140 TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
141 msgbuf->queued++;
142 }
143
144 void
buf_dequeue(struct msgbuf * msgbuf,struct buf * buf)145 buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
146 {
147 TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
148 msgbuf->queued--;
149 buf_free(buf);
150 }
151