buffer.c revision 1.1 1 1.1 plunky /* $NetBSD: buffer.c,v 1.1 2009/11/02 10:00:52 plunky Exp $ */
2 1.1 plunky /*
3 1.1 plunky * Copyright (c) 2002, 2003 Niels Provos <provos (at) citi.umich.edu>
4 1.1 plunky * All rights reserved.
5 1.1 plunky *
6 1.1 plunky * Redistribution and use in source and binary forms, with or without
7 1.1 plunky * modification, are permitted provided that the following conditions
8 1.1 plunky * are met:
9 1.1 plunky * 1. Redistributions of source code must retain the above copyright
10 1.1 plunky * notice, this list of conditions and the following disclaimer.
11 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 plunky * notice, this list of conditions and the following disclaimer in the
13 1.1 plunky * documentation and/or other materials provided with the distribution.
14 1.1 plunky * 3. The name of the author may not be used to endorse or promote products
15 1.1 plunky * derived from this software without specific prior written permission.
16 1.1 plunky *
17 1.1 plunky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 1.1 plunky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 1.1 plunky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 1.1 plunky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 1.1 plunky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 1.1 plunky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 1.1 plunky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 1.1 plunky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 1.1 plunky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 1.1 plunky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 1.1 plunky */
28 1.1 plunky
29 1.1 plunky #ifdef HAVE_CONFIG_H
30 1.1 plunky #include "config.h"
31 1.1 plunky #endif
32 1.1 plunky
33 1.1 plunky #ifdef WIN32
34 1.1 plunky #include <winsock2.h>
35 1.1 plunky #include <windows.h>
36 1.1 plunky #endif
37 1.1 plunky
38 1.1 plunky #ifdef HAVE_VASPRINTF
39 1.1 plunky /* If we have vasprintf, we need to define this before we include stdio.h. */
40 1.1 plunky #define _GNU_SOURCE
41 1.1 plunky #endif
42 1.1 plunky
43 1.1 plunky #include <sys/types.h>
44 1.1 plunky
45 1.1 plunky #ifdef HAVE_SYS_TIME_H
46 1.1 plunky #include <sys/time.h>
47 1.1 plunky #endif
48 1.1 plunky
49 1.1 plunky #ifdef HAVE_SYS_IOCTL_H
50 1.1 plunky #include <sys/ioctl.h>
51 1.1 plunky #endif
52 1.1 plunky
53 1.1 plunky #include <assert.h>
54 1.1 plunky #include <errno.h>
55 1.1 plunky #include <stdio.h>
56 1.1 plunky #include <stdlib.h>
57 1.1 plunky #include <string.h>
58 1.1 plunky #ifdef HAVE_STDARG_H
59 1.1 plunky #include <stdarg.h>
60 1.1 plunky #endif
61 1.1 plunky #ifdef HAVE_UNISTD_H
62 1.1 plunky #include <unistd.h>
63 1.1 plunky #endif
64 1.1 plunky
65 1.1 plunky #include "event.h"
66 1.1 plunky #include "config.h"
67 1.1 plunky #include "evutil.h"
68 1.1 plunky
69 1.1 plunky struct evbuffer *
70 1.1 plunky evbuffer_new(void)
71 1.1 plunky {
72 1.1 plunky struct evbuffer *buffer;
73 1.1 plunky
74 1.1 plunky buffer = calloc(1, sizeof(struct evbuffer));
75 1.1 plunky
76 1.1 plunky return (buffer);
77 1.1 plunky }
78 1.1 plunky
79 1.1 plunky void
80 1.1 plunky evbuffer_free(struct evbuffer *buffer)
81 1.1 plunky {
82 1.1 plunky if (buffer->orig_buffer != NULL)
83 1.1 plunky free(buffer->orig_buffer);
84 1.1 plunky free(buffer);
85 1.1 plunky }
86 1.1 plunky
87 1.1 plunky /*
88 1.1 plunky * This is a destructive add. The data from one buffer moves into
89 1.1 plunky * the other buffer.
90 1.1 plunky */
91 1.1 plunky
92 1.1 plunky #define SWAP(x,y) do { \
93 1.1 plunky (x)->buffer = (y)->buffer; \
94 1.1 plunky (x)->orig_buffer = (y)->orig_buffer; \
95 1.1 plunky (x)->misalign = (y)->misalign; \
96 1.1 plunky (x)->totallen = (y)->totallen; \
97 1.1 plunky (x)->off = (y)->off; \
98 1.1 plunky } while (0)
99 1.1 plunky
100 1.1 plunky int
101 1.1 plunky evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
102 1.1 plunky {
103 1.1 plunky int res;
104 1.1 plunky
105 1.1 plunky /* Short cut for better performance */
106 1.1 plunky if (outbuf->off == 0) {
107 1.1 plunky struct evbuffer tmp;
108 1.1 plunky size_t oldoff = inbuf->off;
109 1.1 plunky
110 1.1 plunky /* Swap them directly */
111 1.1 plunky SWAP(&tmp, outbuf);
112 1.1 plunky SWAP(outbuf, inbuf);
113 1.1 plunky SWAP(inbuf, &tmp);
114 1.1 plunky
115 1.1 plunky /*
116 1.1 plunky * Optimization comes with a price; we need to notify the
117 1.1 plunky * buffer if necessary of the changes. oldoff is the amount
118 1.1 plunky * of data that we transfered from inbuf to outbuf
119 1.1 plunky */
120 1.1 plunky if (inbuf->off != oldoff && inbuf->cb != NULL)
121 1.1 plunky (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
122 1.1 plunky if (oldoff && outbuf->cb != NULL)
123 1.1 plunky (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
124 1.1 plunky
125 1.1 plunky return (0);
126 1.1 plunky }
127 1.1 plunky
128 1.1 plunky res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
129 1.1 plunky if (res == 0) {
130 1.1 plunky /* We drain the input buffer on success */
131 1.1 plunky evbuffer_drain(inbuf, inbuf->off);
132 1.1 plunky }
133 1.1 plunky
134 1.1 plunky return (res);
135 1.1 plunky }
136 1.1 plunky
137 1.1 plunky int
138 1.1 plunky evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
139 1.1 plunky {
140 1.1 plunky char *buffer;
141 1.1 plunky size_t space;
142 1.1 plunky size_t oldoff = buf->off;
143 1.1 plunky int sz;
144 1.1 plunky va_list aq;
145 1.1 plunky
146 1.1 plunky /* make sure that at least some space is available */
147 1.1 plunky evbuffer_expand(buf, 64);
148 1.1 plunky for (;;) {
149 1.1 plunky size_t used = buf->misalign + buf->off;
150 1.1 plunky buffer = (char *)buf->buffer + buf->off;
151 1.1 plunky assert(buf->totallen >= used);
152 1.1 plunky space = buf->totallen - used;
153 1.1 plunky
154 1.1 plunky #ifndef va_copy
155 1.1 plunky #define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
156 1.1 plunky #endif
157 1.1 plunky va_copy(aq, ap);
158 1.1 plunky
159 1.1 plunky sz = evutil_vsnprintf(buffer, space, fmt, aq);
160 1.1 plunky
161 1.1 plunky va_end(aq);
162 1.1 plunky
163 1.1 plunky if (sz < 0)
164 1.1 plunky return (-1);
165 1.1 plunky if ((size_t)sz < space) {
166 1.1 plunky buf->off += sz;
167 1.1 plunky if (buf->cb != NULL)
168 1.1 plunky (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
169 1.1 plunky return (sz);
170 1.1 plunky }
171 1.1 plunky if (evbuffer_expand(buf, sz + 1) == -1)
172 1.1 plunky return (-1);
173 1.1 plunky
174 1.1 plunky }
175 1.1 plunky /* NOTREACHED */
176 1.1 plunky }
177 1.1 plunky
178 1.1 plunky int
179 1.1 plunky evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
180 1.1 plunky {
181 1.1 plunky int res = -1;
182 1.1 plunky va_list ap;
183 1.1 plunky
184 1.1 plunky va_start(ap, fmt);
185 1.1 plunky res = evbuffer_add_vprintf(buf, fmt, ap);
186 1.1 plunky va_end(ap);
187 1.1 plunky
188 1.1 plunky return (res);
189 1.1 plunky }
190 1.1 plunky
191 1.1 plunky /* Reads data from an event buffer and drains the bytes read */
192 1.1 plunky
193 1.1 plunky int
194 1.1 plunky evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
195 1.1 plunky {
196 1.1 plunky size_t nread = datlen;
197 1.1 plunky if (nread >= buf->off)
198 1.1 plunky nread = buf->off;
199 1.1 plunky
200 1.1 plunky memcpy(data, buf->buffer, nread);
201 1.1 plunky evbuffer_drain(buf, nread);
202 1.1 plunky
203 1.1 plunky return (nread);
204 1.1 plunky }
205 1.1 plunky
206 1.1 plunky /*
207 1.1 plunky * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
208 1.1 plunky * The returned buffer needs to be freed by the called.
209 1.1 plunky */
210 1.1 plunky
211 1.1 plunky char *
212 1.1 plunky evbuffer_readline(struct evbuffer *buffer)
213 1.1 plunky {
214 1.1 plunky u_char *data = EVBUFFER_DATA(buffer);
215 1.1 plunky size_t len = EVBUFFER_LENGTH(buffer);
216 1.1 plunky char *line;
217 1.1 plunky unsigned int i;
218 1.1 plunky
219 1.1 plunky for (i = 0; i < len; i++) {
220 1.1 plunky if (data[i] == '\r' || data[i] == '\n')
221 1.1 plunky break;
222 1.1 plunky }
223 1.1 plunky
224 1.1 plunky if (i == len)
225 1.1 plunky return (NULL);
226 1.1 plunky
227 1.1 plunky if ((line = malloc(i + 1)) == NULL) {
228 1.1 plunky fprintf(stderr, "%s: out of memory\n", __func__);
229 1.1 plunky evbuffer_drain(buffer, i);
230 1.1 plunky return (NULL);
231 1.1 plunky }
232 1.1 plunky
233 1.1 plunky memcpy(line, data, i);
234 1.1 plunky line[i] = '\0';
235 1.1 plunky
236 1.1 plunky /*
237 1.1 plunky * Some protocols terminate a line with '\r\n', so check for
238 1.1 plunky * that, too.
239 1.1 plunky */
240 1.1 plunky if ( i < len - 1 ) {
241 1.1 plunky char fch = data[i], sch = data[i+1];
242 1.1 plunky
243 1.1 plunky /* Drain one more character if needed */
244 1.1 plunky if ( (sch == '\r' || sch == '\n') && sch != fch )
245 1.1 plunky i += 1;
246 1.1 plunky }
247 1.1 plunky
248 1.1 plunky evbuffer_drain(buffer, i + 1);
249 1.1 plunky
250 1.1 plunky return (line);
251 1.1 plunky }
252 1.1 plunky
253 1.1 plunky /* Adds data to an event buffer */
254 1.1 plunky
255 1.1 plunky static void
256 1.1 plunky evbuffer_align(struct evbuffer *buf)
257 1.1 plunky {
258 1.1 plunky memmove(buf->orig_buffer, buf->buffer, buf->off);
259 1.1 plunky buf->buffer = buf->orig_buffer;
260 1.1 plunky buf->misalign = 0;
261 1.1 plunky }
262 1.1 plunky
263 1.1 plunky /* Expands the available space in the event buffer to at least datlen */
264 1.1 plunky
265 1.1 plunky int
266 1.1 plunky evbuffer_expand(struct evbuffer *buf, size_t datlen)
267 1.1 plunky {
268 1.1 plunky size_t need = buf->misalign + buf->off + datlen;
269 1.1 plunky
270 1.1 plunky /* If we can fit all the data, then we don't have to do anything */
271 1.1 plunky if (buf->totallen >= need)
272 1.1 plunky return (0);
273 1.1 plunky
274 1.1 plunky /*
275 1.1 plunky * If the misalignment fulfills our data needs, we just force an
276 1.1 plunky * alignment to happen. Afterwards, we have enough space.
277 1.1 plunky */
278 1.1 plunky if (buf->misalign >= datlen) {
279 1.1 plunky evbuffer_align(buf);
280 1.1 plunky } else {
281 1.1 plunky void *newbuf;
282 1.1 plunky size_t length = buf->totallen;
283 1.1 plunky
284 1.1 plunky if (length < 256)
285 1.1 plunky length = 256;
286 1.1 plunky while (length < need)
287 1.1 plunky length <<= 1;
288 1.1 plunky
289 1.1 plunky if (buf->orig_buffer != buf->buffer)
290 1.1 plunky evbuffer_align(buf);
291 1.1 plunky if ((newbuf = realloc(buf->buffer, length)) == NULL)
292 1.1 plunky return (-1);
293 1.1 plunky
294 1.1 plunky buf->orig_buffer = buf->buffer = newbuf;
295 1.1 plunky buf->totallen = length;
296 1.1 plunky }
297 1.1 plunky
298 1.1 plunky return (0);
299 1.1 plunky }
300 1.1 plunky
301 1.1 plunky int
302 1.1 plunky evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
303 1.1 plunky {
304 1.1 plunky size_t need = buf->misalign + buf->off + datlen;
305 1.1 plunky size_t oldoff = buf->off;
306 1.1 plunky
307 1.1 plunky if (buf->totallen < need) {
308 1.1 plunky if (evbuffer_expand(buf, datlen) == -1)
309 1.1 plunky return (-1);
310 1.1 plunky }
311 1.1 plunky
312 1.1 plunky memcpy(buf->buffer + buf->off, data, datlen);
313 1.1 plunky buf->off += datlen;
314 1.1 plunky
315 1.1 plunky if (datlen && buf->cb != NULL)
316 1.1 plunky (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
317 1.1 plunky
318 1.1 plunky return (0);
319 1.1 plunky }
320 1.1 plunky
321 1.1 plunky void
322 1.1 plunky evbuffer_drain(struct evbuffer *buf, size_t len)
323 1.1 plunky {
324 1.1 plunky size_t oldoff = buf->off;
325 1.1 plunky
326 1.1 plunky if (len >= buf->off) {
327 1.1 plunky buf->off = 0;
328 1.1 plunky buf->buffer = buf->orig_buffer;
329 1.1 plunky buf->misalign = 0;
330 1.1 plunky goto done;
331 1.1 plunky }
332 1.1 plunky
333 1.1 plunky buf->buffer += len;
334 1.1 plunky buf->misalign += len;
335 1.1 plunky
336 1.1 plunky buf->off -= len;
337 1.1 plunky
338 1.1 plunky done:
339 1.1 plunky /* Tell someone about changes in this buffer */
340 1.1 plunky if (buf->off != oldoff && buf->cb != NULL)
341 1.1 plunky (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
342 1.1 plunky
343 1.1 plunky }
344 1.1 plunky
345 1.1 plunky /*
346 1.1 plunky * Reads data from a file descriptor into a buffer.
347 1.1 plunky */
348 1.1 plunky
349 1.1 plunky #define EVBUFFER_MAX_READ 4096
350 1.1 plunky
351 1.1 plunky int
352 1.1 plunky evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
353 1.1 plunky {
354 1.1 plunky u_char *p;
355 1.1 plunky size_t oldoff = buf->off;
356 1.1 plunky int n = EVBUFFER_MAX_READ;
357 1.1 plunky
358 1.1 plunky #if defined(FIONREAD)
359 1.1 plunky #ifdef WIN32
360 1.1 plunky long lng = n;
361 1.1 plunky if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) == 0) {
362 1.1 plunky #else
363 1.1 plunky if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
364 1.1 plunky #endif
365 1.1 plunky n = EVBUFFER_MAX_READ;
366 1.1 plunky } else if (n > EVBUFFER_MAX_READ && n > howmuch) {
367 1.1 plunky /*
368 1.1 plunky * It's possible that a lot of data is available for
369 1.1 plunky * reading. We do not want to exhaust resources
370 1.1 plunky * before the reader has a chance to do something
371 1.1 plunky * about it. If the reader does not tell us how much
372 1.1 plunky * data we should read, we artifically limit it.
373 1.1 plunky */
374 1.1 plunky if ((size_t)n > buf->totallen << 2)
375 1.1 plunky n = buf->totallen << 2;
376 1.1 plunky if (n < EVBUFFER_MAX_READ)
377 1.1 plunky n = EVBUFFER_MAX_READ;
378 1.1 plunky }
379 1.1 plunky #endif
380 1.1 plunky if (howmuch < 0 || howmuch > n)
381 1.1 plunky howmuch = n;
382 1.1 plunky
383 1.1 plunky /* If we don't have FIONREAD, we might waste some space here */
384 1.1 plunky if (evbuffer_expand(buf, howmuch) == -1)
385 1.1 plunky return (-1);
386 1.1 plunky
387 1.1 plunky /* We can append new data at this point */
388 1.1 plunky p = buf->buffer + buf->off;
389 1.1 plunky
390 1.1 plunky #ifndef WIN32
391 1.1 plunky n = read(fd, p, howmuch);
392 1.1 plunky #else
393 1.1 plunky n = recv(fd, p, howmuch, 0);
394 1.1 plunky #endif
395 1.1 plunky if (n == -1)
396 1.1 plunky return (-1);
397 1.1 plunky if (n == 0)
398 1.1 plunky return (0);
399 1.1 plunky
400 1.1 plunky buf->off += n;
401 1.1 plunky
402 1.1 plunky /* Tell someone about changes in this buffer */
403 1.1 plunky if (buf->off != oldoff && buf->cb != NULL)
404 1.1 plunky (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
405 1.1 plunky
406 1.1 plunky return (n);
407 1.1 plunky }
408 1.1 plunky
409 1.1 plunky int
410 1.1 plunky evbuffer_write(struct evbuffer *buffer, int fd)
411 1.1 plunky {
412 1.1 plunky int n;
413 1.1 plunky
414 1.1 plunky #ifndef WIN32
415 1.1 plunky n = write(fd, buffer->buffer, buffer->off);
416 1.1 plunky #else
417 1.1 plunky n = send(fd, buffer->buffer, buffer->off, 0);
418 1.1 plunky #endif
419 1.1 plunky if (n == -1)
420 1.1 plunky return (-1);
421 1.1 plunky if (n == 0)
422 1.1 plunky return (0);
423 1.1 plunky evbuffer_drain(buffer, n);
424 1.1 plunky
425 1.1 plunky return (n);
426 1.1 plunky }
427 1.1 plunky
428 1.1 plunky u_char *
429 1.1 plunky evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
430 1.1 plunky {
431 1.1 plunky u_char *search = buffer->buffer, *end = search + buffer->off;
432 1.1 plunky u_char *p;
433 1.1 plunky
434 1.1 plunky while (search < end &&
435 1.1 plunky (p = memchr(search, *what, end - search)) != NULL) {
436 1.1 plunky if (p + len > end)
437 1.1 plunky break;
438 1.1 plunky if (memcmp(p, what, len) == 0)
439 1.1 plunky return (p);
440 1.1 plunky search = p + 1;
441 1.1 plunky }
442 1.1 plunky
443 1.1 plunky return (NULL);
444 1.1 plunky }
445 1.1 plunky
446 1.1 plunky void evbuffer_setcb(struct evbuffer *buffer,
447 1.1 plunky void (*cb)(struct evbuffer *, size_t, size_t, void *),
448 1.1 plunky void *cbarg)
449 1.1 plunky {
450 1.1 plunky buffer->cb = cb;
451 1.1 plunky buffer->cbarg = cbarg;
452 1.1 plunky }
453