xref: /openbsd-src/lib/libevent/buffer.c (revision b725ae7711052a2233e31a66fefb8a752c388d7a)
1 /*	$OpenBSD: buffer.c,v 1.1 2004/04/28 06:53:12 brad Exp $	*/
2 
3 /*
4  * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/types.h>
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #ifdef HAVE_SYS_TIME_H
37 #include <sys/time.h>
38 #endif
39 
40 #include <err.h>
41 #include <errno.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #ifdef HAVE_STDARG_H
46 #include <stdarg.h>
47 #endif
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 
52 #include "event.h"
53 
54 struct evbuffer *
55 evbuffer_new(void)
56 {
57 	struct evbuffer *buffer;
58 
59 	buffer = calloc(1, sizeof(struct evbuffer));
60 
61 	return (buffer);
62 }
63 
64 void
65 evbuffer_free(struct evbuffer *buffer)
66 {
67 	if (buffer->buffer != NULL)
68 		free(buffer->buffer);
69 	free(buffer);
70 }
71 
72 /*
73  * This is a destructive add.  The data from one buffer moves into
74  * the other buffer.
75  */
76 
77 int
78 evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
79 {
80 	int res;
81 	res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
82 	if (res == 0)
83 		evbuffer_drain(inbuf, inbuf->off);
84 
85 	return (res);
86 }
87 
88 int
89 evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...)
90 {
91 	int res = -1;
92 	char *msg;
93 	va_list ap;
94 
95 	va_start(ap, fmt);
96 
97 	if (vasprintf(&msg, fmt, ap) == -1)
98 		goto end;
99 
100 	res = strlen(msg);
101 	if (evbuffer_add(buf, msg, res) == -1)
102 		res = -1;
103 	free(msg);
104 
105  end:
106 	va_end(ap);
107 
108 	return (res);
109 }
110 
111 int
112 evbuffer_add(struct evbuffer *buf, u_char *data, size_t datlen)
113 {
114 	size_t need = buf->off + datlen;
115 	size_t oldoff = buf->off;
116 
117 	if (buf->totallen < need) {
118 		void *newbuf;
119 		int length = buf->totallen;
120 
121 		if (length < 256)
122 			length = 256;
123 		while (length < need)
124 			length <<= 1;
125 
126 		if ((newbuf = realloc(buf->buffer, length)) == NULL)
127 			return (-1);
128 
129 		buf->buffer = newbuf;
130 		buf->totallen = length;
131 	}
132 
133 	memcpy(buf->buffer + buf->off, data, datlen);
134 	buf->off += datlen;
135 
136 	if (datlen && buf->cb != NULL)
137 		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
138 
139 	return (0);
140 }
141 
142 void
143 evbuffer_drain(struct evbuffer *buf, size_t len)
144 {
145 	size_t oldoff = buf->off;
146 
147 	if (len >= buf->off) {
148 		buf->off = 0;
149 		goto done;
150 	}
151 
152 	memmove(buf->buffer, buf->buffer + len, buf->off - len);
153 	buf->off -= len;
154 
155  done:
156 	/* Tell someone about changes in this buffer */
157 	if (buf->off != oldoff && buf->cb != NULL)
158 		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
159 
160 }
161 
162 int
163 evbuffer_read(struct evbuffer *buffer, int fd, int howmuch)
164 {
165 	u_char inbuf[4096];
166 	int n;
167 
168 	if (howmuch < 0 || howmuch > sizeof(inbuf))
169 		howmuch = sizeof(inbuf);
170 
171 	n = read(fd, inbuf, howmuch);
172 	if (n == -1)
173 		return (-1);
174 	if (n == 0)
175 		return (0);
176 
177 	evbuffer_add(buffer, inbuf, n);
178 
179 	return (n);
180 }
181 
182 int
183 evbuffer_write(struct evbuffer *buffer, int fd)
184 {
185 	int n;
186 
187 	n = write(fd, buffer->buffer, buffer->off);
188 	if (n == -1)
189 		return (-1);
190 	if (n == 0)
191 		return (0);
192 
193 	evbuffer_drain(buffer, n);
194 
195 	return (n);
196 }
197 
198 u_char *
199 evbuffer_find(struct evbuffer *buffer, u_char *what, size_t len)
200 {
201 	size_t remain = buffer->off;
202 	u_char *search = buffer->buffer;
203 	u_char *p;
204 
205 	while ((p = memchr(search, *what, remain)) != NULL && remain >= len) {
206 		if (memcmp(p, what, len) == 0)
207 			return (p);
208 
209 		search = p + 1;
210 		remain = buffer->off - (size_t)(search - buffer->buffer);
211 	}
212 
213 	return (NULL);
214 }
215 
216 void evbuffer_setcb(struct evbuffer *buffer,
217     void (*cb)(struct evbuffer *, size_t, size_t, void *),
218     void *cbarg)
219 {
220 	buffer->cb = cb;
221 	buffer->cbarg = cbarg;
222 }
223