3 * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 /* If we have vasprintf, we need to define this before we include stdio.h. */
43 #include <sys/types.h>
45 #ifdef HAVE_SYS_TIME_H
49 #ifdef HAVE_SYS_IOCTL_H
50 #include <sys/ioctl.h>
72 struct evbuffer
*buffer
;
74 buffer
= calloc(1, sizeof(struct evbuffer
));
80 evbuffer_free(struct evbuffer
*buffer
)
82 if (buffer
->orig_buffer
!= NULL
)
83 free(buffer
->orig_buffer
);
88 * This is a destructive add. The data from one buffer moves into
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; \
101 evbuffer_add_buffer(struct evbuffer
*outbuf
, struct evbuffer
*inbuf
)
105 /* Short cut for better performance */
106 if (outbuf
->off
== 0) {
108 size_t oldoff
= inbuf
->off
;
110 /* Swap them directly */
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
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
);
128 res
= evbuffer_add(outbuf
, inbuf
->buffer
, inbuf
->off
);
130 /* We drain the input buffer on success */
131 evbuffer_drain(inbuf
, inbuf
->off
);
138 evbuffer_add_vprintf(struct evbuffer
*buf
, const char *fmt
, va_list ap
)
142 size_t oldoff
= buf
->off
;
146 /* make sure that at least some space is available */
147 evbuffer_expand(buf
, 64);
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
;
155 #define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
159 sz
= evutil_vsnprintf(buffer
, space
, fmt
, aq
);
165 if ((size_t)sz
< space
) {
168 (*buf
->cb
)(buf
, oldoff
, buf
->off
, buf
->cbarg
);
171 if (evbuffer_expand(buf
, sz
+ 1) == -1)
179 evbuffer_add_printf(struct evbuffer
*buf
, const char *fmt
, ...)
185 res
= evbuffer_add_vprintf(buf
, fmt
, ap
);
191 /* Reads data from an event buffer and drains the bytes read */
194 evbuffer_remove(struct evbuffer
*buf
, void *data
, size_t datlen
)
196 size_t nread
= datlen
;
197 if (nread
>= buf
->off
)
200 memcpy(data
, buf
->buffer
, nread
);
201 evbuffer_drain(buf
, nread
);
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.
212 evbuffer_readline(struct evbuffer
*buffer
)
214 u_char
*data
= EVBUFFER_DATA(buffer
);
215 size_t len
= EVBUFFER_LENGTH(buffer
);
219 for (i
= 0; i
< len
; i
++) {
220 if (data
[i
] == '\r' || data
[i
] == '\n')
227 if ((line
= malloc(i
+ 1)) == NULL
) {
228 fprintf(stderr
, "%s: out of memory\n", __func__
);
229 evbuffer_drain(buffer
, i
);
233 memcpy(line
, data
, i
);
237 * Some protocols terminate a line with '\r\n', so check for
241 char fch
= data
[i
], sch
= data
[i
+1];
243 /* Drain one more character if needed */
244 if ( (sch
== '\r' || sch
== '\n') && sch
!= fch
)
248 evbuffer_drain(buffer
, i
+ 1);
253 /* Adds data to an event buffer */
256 evbuffer_align(struct evbuffer
*buf
)
258 memmove(buf
->orig_buffer
, buf
->buffer
, buf
->off
);
259 buf
->buffer
= buf
->orig_buffer
;
263 /* Expands the available space in the event buffer to at least datlen */
266 evbuffer_expand(struct evbuffer
*buf
, size_t datlen
)
268 size_t need
= buf
->misalign
+ buf
->off
+ datlen
;
270 /* If we can fit all the data, then we don't have to do anything */
271 if (buf
->totallen
>= need
)
275 * If the misalignment fulfills our data needs, we just force an
276 * alignment to happen. Afterwards, we have enough space.
278 if (buf
->misalign
>= datlen
) {
282 size_t length
= buf
->totallen
;
286 while (length
< need
)
289 if (buf
->orig_buffer
!= buf
->buffer
)
291 if ((newbuf
= realloc(buf
->buffer
, length
)) == NULL
)
294 buf
->orig_buffer
= buf
->buffer
= newbuf
;
295 buf
->totallen
= length
;
302 evbuffer_add(struct evbuffer
*buf
, const void *data
, size_t datlen
)
304 size_t need
= buf
->misalign
+ buf
->off
+ datlen
;
305 size_t oldoff
= buf
->off
;
307 if (buf
->totallen
< need
) {
308 if (evbuffer_expand(buf
, datlen
) == -1)
312 memcpy(buf
->buffer
+ buf
->off
, data
, datlen
);
315 if (datlen
&& buf
->cb
!= NULL
)
316 (*buf
->cb
)(buf
, oldoff
, buf
->off
, buf
->cbarg
);
322 evbuffer_drain(struct evbuffer
*buf
, size_t len
)
324 size_t oldoff
= buf
->off
;
326 if (len
>= buf
->off
) {
328 buf
->buffer
= buf
->orig_buffer
;
334 buf
->misalign
+= len
;
339 /* Tell someone about changes in this buffer */
340 if (buf
->off
!= oldoff
&& buf
->cb
!= NULL
)
341 (*buf
->cb
)(buf
, oldoff
, buf
->off
, buf
->cbarg
);
346 * Reads data from a file descriptor into a buffer.
349 #define EVBUFFER_MAX_READ 4096
352 evbuffer_read(struct evbuffer
*buf
, int fd
, int howmuch
)
355 size_t oldoff
= buf
->off
;
356 int n
= EVBUFFER_MAX_READ
;
358 #if defined(FIONREAD)
361 if (ioctlsocket(fd
, FIONREAD
, &lng
) == -1 || (n
=lng
) == 0) {
363 if (ioctl(fd
, FIONREAD
, &n
) == -1 || n
== 0) {
365 n
= EVBUFFER_MAX_READ
;
366 } else if (n
> EVBUFFER_MAX_READ
&& n
> howmuch
) {
368 * It's possible that a lot of data is available for
369 * reading. We do not want to exhaust resources
370 * before the reader has a chance to do something
371 * about it. If the reader does not tell us how much
372 * data we should read, we artifically limit it.
374 if ((size_t)n
> buf
->totallen
<< 2)
375 n
= buf
->totallen
<< 2;
376 if (n
< EVBUFFER_MAX_READ
)
377 n
= EVBUFFER_MAX_READ
;
380 if (howmuch
< 0 || howmuch
> n
)
383 /* If we don't have FIONREAD, we might waste some space here */
384 if (evbuffer_expand(buf
, howmuch
) == -1)
387 /* We can append new data at this point */
388 p
= buf
->buffer
+ buf
->off
;
391 n
= read(fd
, p
, howmuch
);
393 n
= recv(fd
, p
, howmuch
, 0);
402 /* Tell someone about changes in this buffer */
403 if (buf
->off
!= oldoff
&& buf
->cb
!= NULL
)
404 (*buf
->cb
)(buf
, oldoff
, buf
->off
, buf
->cbarg
);
410 evbuffer_write(struct evbuffer
*buffer
, int fd
)
415 n
= write(fd
, buffer
->buffer
, buffer
->off
);
417 n
= send(fd
, buffer
->buffer
, buffer
->off
, 0);
423 evbuffer_drain(buffer
, n
);
429 evbuffer_find(struct evbuffer
*buffer
, const u_char
*what
, size_t len
)
431 u_char
*search
= buffer
->buffer
, *end
= search
+ buffer
->off
;
434 while (search
< end
&&
435 (p
= memchr(search
, *what
, end
- search
)) != NULL
) {
438 if (memcmp(p
, what
, len
) == 0)
446 void evbuffer_setcb(struct evbuffer
*buffer
,
447 void (*cb
)(struct evbuffer
*, size_t, size_t, void *),
451 buffer
->cbarg
= cbarg
;