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