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