mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
improved code for evbuffer; avoids memcpy
svn:r674
This commit is contained in:
parent
eb9b958089
commit
5c70ea4c9d
@ -53,6 +53,7 @@ Changes in current version:
|
||||
o increase listen queue for http sockets to 128; if that is not enough the evhttp_accpet_socket() api can be used with a prepared socket.
|
||||
o Patch from Tani Hosokawa: make some functions in http.c threadsafe.
|
||||
o test support for PUT/DELETE requests; from Josh Rotenberg
|
||||
o rewrite of the evbuffer code to reduce memory copies
|
||||
|
||||
Changes in 1.4.0:
|
||||
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
|
||||
|
3
Doxyfile
3
Doxyfile
@ -54,7 +54,8 @@ SORT_BRIEF_DOCS = YES
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = event.h evdns.h evhttp.h evrpc.h
|
||||
INPUT = event.h evdns.h evhttp.h evrpc.h \
|
||||
include/event2/buffer.h
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
|
@ -49,7 +49,7 @@ EXTRA_DIST = autogen.sh event.h event-internal.h log.h evsignal.h evdns.3 \
|
||||
|
||||
lib_LTLIBRARIES = libevent.la libevent_core.la libevent_extra.la
|
||||
|
||||
SUBDIRS = . sample test
|
||||
SUBDIRS = . include sample test
|
||||
|
||||
if BUILD_WIN32
|
||||
|
||||
@ -100,7 +100,7 @@ libevent_extra_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
|
||||
|
||||
include_HEADERS = event.h evhttp.h evdns.h evrpc.h evutil.h event-config.h
|
||||
|
||||
INCLUDES = -I$(srcdir)/compat $(SYS_INCLUDES)
|
||||
INCLUDES = -I$(srcdir)/compat -I$(srcdir)/include $(SYS_INCLUDES)
|
||||
|
||||
man_MANS = event.3 evdns.3
|
||||
|
||||
|
@ -39,7 +39,7 @@ AC_CHECK_LIB(nsl, inet_ntoa)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in6.h sys/socket.h)
|
||||
AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in6.h sys/socket.h sys/uio.h)
|
||||
if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
|
||||
AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
|
||||
AC_EGREP_CPP(yes,
|
||||
@ -384,4 +384,4 @@ if test x$enable_gcc_warnings = xyes; then
|
||||
|
||||
fi
|
||||
|
||||
AC_OUTPUT(Makefile test/Makefile sample/Makefile)
|
||||
AC_OUTPUT(Makefile include/Makefile test/Makefile sample/Makefile)
|
||||
|
76
evbuffer-internal.h
Normal file
76
evbuffer-internal.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _EVBUFFER_INTERNAL_H_
|
||||
#define _EVBUFFER_INTERNAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* minimum allocation */
|
||||
#define MIN_BUFFER_SIZE 256
|
||||
|
||||
/* number of iovec we use for writev, fragmentation is going to determine
|
||||
* how much we end up writing */
|
||||
#define NUM_IOVEC 128
|
||||
|
||||
struct evbuffer_chain;
|
||||
struct evbuffer {
|
||||
struct evbuffer_chain *first;
|
||||
struct evbuffer_chain *last;
|
||||
|
||||
size_t total_len; /* total length of all buffers */
|
||||
|
||||
void (*cb)(struct evbuffer *, size_t, size_t, void *);
|
||||
void *cbarg;
|
||||
};
|
||||
|
||||
struct evbuffer_chain {
|
||||
/** points to next buffer in the chain */
|
||||
struct evbuffer_chain *next;
|
||||
|
||||
size_t buffer_len;
|
||||
|
||||
size_t misalign;/** unused space at the beginning of buffer */
|
||||
size_t off; /** write pointer into buffer + misalign */
|
||||
|
||||
u_char buffer[1];
|
||||
};
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t)(&((type *)0)->field))
|
||||
#endif
|
||||
|
||||
#define EVBUFFER_CHAIN_SIZE offsetof(struct evbuffer_chain, buffer[0])
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVBUFFER_INTERNAL_H_ */
|
21
evbuffer.c
21
evbuffer.c
@ -313,30 +313,13 @@ bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
|
||||
int
|
||||
bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = bufferevent_write(bufev, buf->buffer, buf->off);
|
||||
if (res != -1)
|
||||
evbuffer_drain(buf, buf->off);
|
||||
|
||||
return (res);
|
||||
return (evbuffer_add_buffer(bufev->output, buf));
|
||||
}
|
||||
|
||||
size_t
|
||||
bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
|
||||
{
|
||||
struct evbuffer *buf = bufev->input;
|
||||
|
||||
if (buf->off < size)
|
||||
size = buf->off;
|
||||
|
||||
/* Copy the available data to the user buffer */
|
||||
memcpy(data, buf->buffer, size);
|
||||
|
||||
if (size)
|
||||
evbuffer_drain(buf, size);
|
||||
|
||||
return (size);
|
||||
return (evbuffer_remove(bufev->input, data, size));
|
||||
}
|
||||
|
||||
int
|
||||
|
208
event.h
208
event.h
@ -138,6 +138,9 @@
|
||||
event.h
|
||||
The primary libevent header
|
||||
|
||||
event2/buffer.h
|
||||
Buffer management for network reading and writing
|
||||
|
||||
evdns.h
|
||||
Asynchronous DNS resolution
|
||||
|
||||
@ -721,19 +724,10 @@ int event_base_priority_init(struct event_base *, int);
|
||||
int event_priority_set(struct event *, int);
|
||||
|
||||
|
||||
#include <event2/buffer.h>
|
||||
|
||||
/* These functions deal with buffering input and output */
|
||||
|
||||
struct evbuffer {
|
||||
u_char *buffer;
|
||||
|
||||
size_t misalign;
|
||||
size_t totallen;
|
||||
size_t off;
|
||||
|
||||
void (*cb)(struct evbuffer *, size_t, size_t, void *);
|
||||
void *cbarg;
|
||||
};
|
||||
|
||||
/* Just for error reporting - use other constants otherwise */
|
||||
#define EVBUFFER_READ 0x01
|
||||
#define EVBUFFER_WRITE 0x02
|
||||
@ -913,190 +907,9 @@ void bufferevent_settimeout(struct bufferevent *bufev,
|
||||
int timeout_read, int timeout_write);
|
||||
|
||||
|
||||
#define EVBUFFER_LENGTH(x) (x)->off
|
||||
#define EVBUFFER_DATA(x) ((x)->buffer + (x)->misalign)
|
||||
#define EVBUFFER_INPUT(x) (x)->input
|
||||
#define EVBUFFER_OUTPUT(x) (x)->output
|
||||
|
||||
|
||||
/**
|
||||
Allocate storage for a new evbuffer.
|
||||
|
||||
@return a pointer to a newly allocated evbuffer struct, or NULL if an error
|
||||
occurred
|
||||
*/
|
||||
struct evbuffer *evbuffer_new(void);
|
||||
|
||||
|
||||
/**
|
||||
Deallocate storage for an evbuffer.
|
||||
|
||||
@param pointer to the evbuffer to be freed
|
||||
*/
|
||||
void evbuffer_free(struct evbuffer *);
|
||||
|
||||
|
||||
/**
|
||||
Expands the available space in an event buffer.
|
||||
|
||||
Expands the available space in the event buffer to at least datlen
|
||||
|
||||
@param buf the event buffer to be expanded
|
||||
@param datlen the new minimum length requirement
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int evbuffer_expand(struct evbuffer *, size_t);
|
||||
|
||||
|
||||
/**
|
||||
Append data to the end of an evbuffer.
|
||||
|
||||
@param buf the event buffer to be appended to
|
||||
@param data pointer to the beginning of the data buffer
|
||||
@param datlen the number of bytes to be copied from the data buffer
|
||||
*/
|
||||
int evbuffer_add(struct evbuffer *, const void *, size_t);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Read data from an event buffer and drain the bytes read.
|
||||
|
||||
@param buf the event buffer to be read from
|
||||
@param data the destination buffer to store the result
|
||||
@param datlen the maximum size of the destination buffer
|
||||
@return the number of bytes read
|
||||
*/
|
||||
int evbuffer_remove(struct evbuffer *, void *, size_t);
|
||||
|
||||
/** Used to tell evbuffer_readln what kind of line-ending to look for.
|
||||
*/
|
||||
enum evbuffer_eol_style {
|
||||
/** Any sequence of CR and LF characters is acceptable as an EOL. */
|
||||
EVBUFFER_EOL_ANY,
|
||||
/** An EOL is an LF, optionally preceded by a CR. This style is
|
||||
* most useful for implementing text-based internet protocols. */
|
||||
EVBUFFER_EOL_CRLF,
|
||||
/** An EOL is a CR followed by an LF. */
|
||||
EVBUFFER_EOL_CRLF_STRICT,
|
||||
/** An EOL is a LF. */
|
||||
EVBUFFER_EOL_LF
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a single line from an event buffer.
|
||||
*
|
||||
* Reads a line terminated by an EOL as determined by the evbuffer_eol_style
|
||||
* argument. Returns a newly allocated nul-terminated string; the caller must
|
||||
* free the returned value. The EOL is not included in the returned string.
|
||||
*
|
||||
* @param buffer the evbuffer to read from
|
||||
* @param n_read_out if non-NULL, points to a size_t that is set to the
|
||||
* number of characters in the returned string. This is useful for
|
||||
* strings that can contain NUL characters.
|
||||
* @param eol_style the style of line-ending to use.
|
||||
* @return pointer to a single line, or NULL if an error occurred
|
||||
*/
|
||||
char *evbuffer_readln(struct evbuffer *, size_t *, enum evbuffer_eol_style);
|
||||
|
||||
/**
|
||||
Obsolete alias for evbuffer_readln(buffer, NULL, EOL_STYLE_ANY).
|
||||
**/
|
||||
char *evbuffer_readline(struct evbuffer *);
|
||||
|
||||
/**
|
||||
Move data from one evbuffer into another evbuffer.
|
||||
|
||||
This is a destructive add. The data from one buffer moves into
|
||||
the other buffer. The destination buffer is expanded as needed.
|
||||
|
||||
@param outbuf the output buffer
|
||||
@param inbuf the input buffer
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
|
||||
|
||||
|
||||
/**
|
||||
Append a formatted string to the end of an evbuffer.
|
||||
|
||||
@param buf the evbuffer that will be appended to
|
||||
@param fmt a format string
|
||||
@param ... arguments that will be passed to printf(3)
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Append a va_list formatted string to the end of an evbuffer.
|
||||
|
||||
@param buf the evbuffer that will be appended to
|
||||
@param fmt a format string
|
||||
@param ap a varargs va_list argument array that will be passed to vprintf(3)
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap);
|
||||
|
||||
|
||||
/**
|
||||
Remove a specified number of bytes data from the beginning of an evbuffer.
|
||||
|
||||
@param buf the evbuffer to be drained
|
||||
@param len the number of bytes to drain from the beginning of the buffer
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
void evbuffer_drain(struct evbuffer *, size_t);
|
||||
|
||||
|
||||
/**
|
||||
Write the contents of an evbuffer to a file descriptor.
|
||||
|
||||
The evbuffer will be drained after the bytes have been successfully written.
|
||||
|
||||
@param buffer the evbuffer to be written and drained
|
||||
@param fd the file descriptor to be written to
|
||||
@return the number of bytes written, or -1 if an error occurred
|
||||
@see evbuffer_read()
|
||||
*/
|
||||
int evbuffer_write(struct evbuffer *, evutil_socket_t);
|
||||
|
||||
|
||||
/**
|
||||
Read from a file descriptor and store the result in an evbuffer.
|
||||
|
||||
@param buf the evbuffer to store the result
|
||||
@param fd the file descriptor to read from
|
||||
@param howmuch the number of bytes to be read
|
||||
@return the number of bytes read, or -1 if an error occurred
|
||||
@see evbuffer_write()
|
||||
*/
|
||||
int evbuffer_read(struct evbuffer *, evutil_socket_t, int);
|
||||
|
||||
|
||||
/**
|
||||
Find a string within an evbuffer.
|
||||
|
||||
@param buffer the evbuffer to be searched
|
||||
@param what the string to be searched for
|
||||
@param len the length of the search string
|
||||
@return a pointer to the beginning of the search string, or NULL if the search failed.
|
||||
*/
|
||||
u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t);
|
||||
|
||||
/**
|
||||
Set a callback to invoke when the evbuffer is modified.
|
||||
|
||||
@param buffer the evbuffer to be monitored
|
||||
@param cb the callback function to invoke when the evbuffer is modified
|
||||
@param cbarg an argument to be provided to the callback function
|
||||
*/
|
||||
void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *);
|
||||
|
||||
/*
|
||||
* Marshaling tagged data - We assume that all tags are inserted in their
|
||||
* numeric order - so that unknown tags will always be higher than the
|
||||
@ -1105,8 +918,19 @@ void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_
|
||||
|
||||
void evtag_init(void);
|
||||
|
||||
/**
|
||||
Unmarshals the header and returns the length of the payload
|
||||
|
||||
@param evbuf the buffer from which to unmarshal data
|
||||
@param ptag a pointer in which the tag id is being stored
|
||||
@returns -1 on failure or the number of bytes in the remaining payload.
|
||||
*/
|
||||
int evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag);
|
||||
|
||||
void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data,
|
||||
ev_uint32_t len);
|
||||
void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag,
|
||||
struct evbuffer *data);
|
||||
|
||||
/**
|
||||
Encode an integer and store it in an evbuffer.
|
||||
|
@ -304,10 +304,8 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
|
||||
'{\n'
|
||||
' struct evbuffer *_buf = evbuffer_new();\n'
|
||||
' assert(_buf != NULL);\n'
|
||||
' evbuffer_drain(_buf, -1);\n'
|
||||
' %(name)s_marshal(_buf, msg);\n'
|
||||
' evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), '
|
||||
'EVBUFFER_LENGTH(_buf));\n'
|
||||
' evtag_marshal_buffer(evbuf, tag, _buf);\n '
|
||||
' evbuffer_free(_buf);\n'
|
||||
'}\n' ) % { 'name' : self._name }
|
||||
|
||||
|
153
event_tagging.c
153
event_tagging.c
@ -87,11 +87,10 @@ evtag_init(void)
|
||||
* integers. This function is byte-order independent.
|
||||
*/
|
||||
|
||||
void
|
||||
encode_int(struct evbuffer *evbuf, ev_uint32_t number)
|
||||
static inline int
|
||||
encode_int_internal(ev_uint8_t *data, ev_uint32_t number)
|
||||
{
|
||||
int off = 1, nibbles = 0;
|
||||
ev_uint8_t data[5];
|
||||
|
||||
memset(data, 0, sizeof(data));
|
||||
while (number) {
|
||||
@ -110,7 +109,15 @@ encode_int(struct evbuffer *evbuf, ev_uint32_t number)
|
||||
/* Off - 1 is the number of encoded nibbles */
|
||||
data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4);
|
||||
|
||||
evbuffer_add(evbuf, data, (off + 1) / 2);
|
||||
return ((off + 1) / 2);
|
||||
}
|
||||
|
||||
void
|
||||
encode_int(struct evbuffer *evbuf, ev_uint32_t number)
|
||||
{
|
||||
ev_uint8_t data[5];
|
||||
int len = encode_int_internal(data, number);
|
||||
evbuffer_add(evbuf, data, len);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -145,10 +152,17 @@ static int
|
||||
decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
|
||||
{
|
||||
ev_uint32_t number = 0;
|
||||
ev_uint8_t *data = EVBUFFER_DATA(evbuf);
|
||||
int len = EVBUFFER_LENGTH(evbuf);
|
||||
ev_uint8_t *data;
|
||||
int count = 0, shift = 0, done = 0;
|
||||
|
||||
/*
|
||||
* the encoding of a number is at most one byte more than its
|
||||
* storage size. however, it may also be much smaller.
|
||||
*/
|
||||
data = evbuffer_pullup(
|
||||
evbuf, len < sizeof(number) + 1 ? len : sizeof(number) + 1);
|
||||
|
||||
while (count++ < len) {
|
||||
ev_uint8_t lower = *data++;
|
||||
number |= (lower & 0x7f) << shift;
|
||||
@ -193,16 +207,25 @@ evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag,
|
||||
evbuffer_add(evbuf, (void *)data, len);
|
||||
}
|
||||
|
||||
void
|
||||
evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag,
|
||||
struct evbuffer *data)
|
||||
{
|
||||
evtag_encode_tag(evbuf, tag);
|
||||
encode_int(evbuf, EVBUFFER_LENGTH(data));
|
||||
evbuffer_add_buffer(evbuf, data);
|
||||
}
|
||||
|
||||
/* Marshaling for integers */
|
||||
void
|
||||
evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
|
||||
{
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
encode_int(_buf, integer);
|
||||
ev_uint8_t data[5];
|
||||
int len = encode_int_internal(data, integer);
|
||||
|
||||
evtag_encode_tag(evbuf, tag);
|
||||
encode_int(evbuf, EVBUFFER_LENGTH(_buf));
|
||||
evbuffer_add_buffer(evbuf, _buf);
|
||||
encode_int(evbuf, len);
|
||||
evbuffer_add(evbuf, data, len);
|
||||
}
|
||||
|
||||
void
|
||||
@ -214,31 +237,33 @@ evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
|
||||
void
|
||||
evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
|
||||
{
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
|
||||
encode_int(_buf, tv->tv_sec);
|
||||
encode_int(_buf, tv->tv_usec);
|
||||
|
||||
evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf),
|
||||
EVBUFFER_LENGTH(_buf));
|
||||
ev_uint8_t data[10];
|
||||
int len = encode_int_internal(data, tv->tv_sec);
|
||||
len += encode_int_internal(data + len, tv->tv_usec);
|
||||
evtag_marshal(evbuf, tag, data, len);
|
||||
}
|
||||
|
||||
static int
|
||||
decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
|
||||
decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int offset)
|
||||
{
|
||||
ev_uint32_t number = 0;
|
||||
ev_uint8_t *data = EVBUFFER_DATA(evbuf);
|
||||
int len = EVBUFFER_LENGTH(evbuf);
|
||||
ev_uint8_t *data;
|
||||
int len = EVBUFFER_LENGTH(evbuf) - offset;
|
||||
int nibbles = 0;
|
||||
|
||||
if (!len)
|
||||
if (len <= 0)
|
||||
return (-1);
|
||||
|
||||
/* XXX(niels): faster? */
|
||||
data = evbuffer_pullup(evbuf, offset + 1) + offset;
|
||||
|
||||
nibbles = ((data[0] & 0xf0) >> 4) + 1;
|
||||
if (nibbles > 8 || (nibbles >> 1) + 1 > len)
|
||||
return (-1);
|
||||
len = (nibbles >> 1) + 1;
|
||||
|
||||
data = evbuffer_pullup(evbuf, offset + len) + offset;
|
||||
|
||||
while (nibbles > 0) {
|
||||
number <<= 4;
|
||||
if (nibbles & 0x1)
|
||||
@ -248,9 +273,6 @@ decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
|
||||
nibbles--;
|
||||
}
|
||||
|
||||
if (dodrain)
|
||||
evbuffer_drain(evbuf, len);
|
||||
|
||||
*pnumber = number;
|
||||
|
||||
return (len);
|
||||
@ -259,7 +281,11 @@ decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
|
||||
int
|
||||
evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
|
||||
{
|
||||
return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0);
|
||||
int res = decode_int_internal(pnumber, evbuf, 0);
|
||||
if (res != -1)
|
||||
evbuffer_drain(evbuf, res);
|
||||
|
||||
return (res == -1 ? -1 : 0);
|
||||
}
|
||||
|
||||
int
|
||||
@ -271,18 +297,13 @@ evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag)
|
||||
int
|
||||
evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
|
||||
{
|
||||
struct evbuffer tmp;
|
||||
int res, len;
|
||||
|
||||
len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
|
||||
if (len == -1)
|
||||
return (-1);
|
||||
|
||||
tmp = *evbuf;
|
||||
tmp.buffer += len;
|
||||
tmp.off -= len;
|
||||
|
||||
res = decode_int_internal(plength, &tmp, 0);
|
||||
res = decode_int_internal(plength, evbuf, len);
|
||||
if (res == -1)
|
||||
return (-1);
|
||||
|
||||
@ -294,31 +315,42 @@ evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
|
||||
int
|
||||
evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
|
||||
{
|
||||
struct evbuffer tmp;
|
||||
int res, len;
|
||||
|
||||
len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
|
||||
if (len == -1)
|
||||
return (-1);
|
||||
|
||||
tmp = *evbuf;
|
||||
tmp.buffer += len;
|
||||
tmp.off -= len;
|
||||
|
||||
res = decode_int_internal(plength, &tmp, 0);
|
||||
res = decode_int_internal(plength, evbuf, len);
|
||||
if (res == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* just unmarshals the header and returns the length of the remaining data */
|
||||
|
||||
int
|
||||
evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag)
|
||||
{
|
||||
ev_uint32_t len;
|
||||
|
||||
if (decode_tag_internal(ptag, evbuf, 1 /* dodrain */) == -1)
|
||||
return (-1);
|
||||
if (evtag_decode_int(&len, evbuf) == -1)
|
||||
return (-1);
|
||||
|
||||
if (EVBUFFER_LENGTH(evbuf) < len)
|
||||
return (-1);
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
int
|
||||
evtag_consume(struct evbuffer *evbuf)
|
||||
{
|
||||
ev_uint32_t len;
|
||||
if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1)
|
||||
return (-1);
|
||||
if (evtag_decode_int(&len, evbuf) == -1)
|
||||
int len;
|
||||
if ((len = evtag_unmarshal_header(evbuf, NULL)) == -1)
|
||||
return (-1);
|
||||
evbuffer_drain(evbuf, len);
|
||||
|
||||
@ -330,19 +362,12 @@ evtag_consume(struct evbuffer *evbuf)
|
||||
int
|
||||
evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst)
|
||||
{
|
||||
ev_uint32_t len;
|
||||
ev_uint32_t integer;
|
||||
int len;
|
||||
|
||||
if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1)
|
||||
return (-1);
|
||||
if (evtag_decode_int(&integer, src) == -1)
|
||||
return (-1);
|
||||
len = integer;
|
||||
|
||||
if (EVBUFFER_LENGTH(src) < len)
|
||||
if ((len = evtag_unmarshal_header(src, ptag)) == -1)
|
||||
return (-1);
|
||||
|
||||
if (evbuffer_add(dst, EVBUFFER_DATA(src), len) == -1)
|
||||
if (evbuffer_add(dst, evbuffer_pullup(src, len), len) == -1)
|
||||
return (-1);
|
||||
|
||||
evbuffer_drain(src, len);
|
||||
@ -372,7 +397,7 @@ evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
|
||||
return (-1);
|
||||
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
if (evbuffer_add(_buf, EVBUFFER_DATA(evbuf), len) == -1)
|
||||
if (evbuffer_add(_buf, evbuffer_pullup(evbuf, len), len) == -1)
|
||||
return (-1);
|
||||
|
||||
evbuffer_drain(evbuf, len);
|
||||
@ -387,18 +412,17 @@ evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data,
|
||||
size_t len)
|
||||
{
|
||||
ev_uint32_t tag;
|
||||
|
||||
/* Initialize this event buffer so that we can read into it */
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
int tag_len;
|
||||
|
||||
/* Now unmarshal a tag and check that it matches the tag we want */
|
||||
if (evtag_unmarshal(src, &tag, _buf) == -1 || tag != need_tag)
|
||||
if ((tag_len = evtag_unmarshal_header(src, &tag)) == -1 ||
|
||||
tag != need_tag)
|
||||
return (-1);
|
||||
|
||||
if (EVBUFFER_LENGTH(_buf) != len)
|
||||
if (tag_len != len)
|
||||
return (-1);
|
||||
|
||||
memcpy(data, EVBUFFER_DATA(_buf), len);
|
||||
|
||||
evbuffer_remove(src, data, len);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -407,16 +431,17 @@ evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
|
||||
char **pstring)
|
||||
{
|
||||
ev_uint32_t tag;
|
||||
int tag_len;
|
||||
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
|
||||
if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
|
||||
if ((tag_len = evtag_unmarshal_header(evbuf, &tag)) == -1 ||
|
||||
tag != need_tag)
|
||||
return (-1);
|
||||
|
||||
*pstring = event_calloc(EVBUFFER_LENGTH(_buf) + 1, 1);
|
||||
*pstring = event_malloc(tag_len + 1);
|
||||
if (*pstring == NULL)
|
||||
event_err(1, "%s: calloc", __func__);
|
||||
evbuffer_remove(_buf, *pstring, EVBUFFER_LENGTH(_buf));
|
||||
event_err(1, "%s: malloc", __func__);
|
||||
evbuffer_remove(evbuf, *pstring, tag_len);
|
||||
(*pstring)[tag_len] = '\0';
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
20
http.c
20
http.c
@ -313,7 +313,6 @@ static void
|
||||
evhttp_make_header_request(struct evhttp_connection *evcon,
|
||||
struct evhttp_request *req)
|
||||
{
|
||||
char line[1024];
|
||||
const char *method;
|
||||
|
||||
evhttp_remove_header(req->output_headers, "Accept-Encoding");
|
||||
@ -321,9 +320,8 @@ evhttp_make_header_request(struct evhttp_connection *evcon,
|
||||
|
||||
/* Generate request line */
|
||||
method = evhttp_method(req->type);
|
||||
snprintf(line, sizeof(line), "%s %s HTTP/%d.%d\r\n",
|
||||
evbuffer_add_printf(evcon->output_buffer, "%s %s HTTP/%d.%d\r\n",
|
||||
method, req->uri, req->major, req->minor);
|
||||
evbuffer_add(evcon->output_buffer, line, strlen(line));
|
||||
|
||||
/* Add the content length on a post or put request if missing */
|
||||
if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) &&
|
||||
@ -399,11 +397,9 @@ static void
|
||||
evhttp_make_header_response(struct evhttp_connection *evcon,
|
||||
struct evhttp_request *req)
|
||||
{
|
||||
char line[1024];
|
||||
snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n",
|
||||
evbuffer_add_printf(evcon->output_buffer, "HTTP/%d.%d %d %s\r\n",
|
||||
req->major, req->minor, req->response_code,
|
||||
req->response_code_line);
|
||||
evbuffer_add(evcon->output_buffer, line, strlen(line));
|
||||
|
||||
if (req->major == 1 && req->minor == 1)
|
||||
evhttp_maybe_add_date_header(req->output_headers);
|
||||
@ -441,7 +437,6 @@ evhttp_make_header_response(struct evhttp_connection *evcon,
|
||||
void
|
||||
evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
{
|
||||
char line[1024];
|
||||
struct evkeyval *header;
|
||||
|
||||
/*
|
||||
@ -455,9 +450,8 @@ evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(header, req->output_headers, next) {
|
||||
snprintf(line, sizeof(line), "%s: %s\r\n",
|
||||
evbuffer_add_printf(evcon->output_buffer, "%s: %s\r\n",
|
||||
header->key, header->value);
|
||||
evbuffer_add(evcon->output_buffer, line, strlen(line));
|
||||
}
|
||||
evbuffer_add(evcon->output_buffer, "\r\n", 2);
|
||||
|
||||
@ -735,9 +729,7 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
|
||||
return (0);
|
||||
|
||||
/* Completed chunk */
|
||||
evbuffer_add(req->input_buffer,
|
||||
EVBUFFER_DATA(buf), req->ntoread);
|
||||
evbuffer_drain(buf, req->ntoread);
|
||||
evbuffer_remove_buffer(buf, req->input_buffer, req->ntoread);
|
||||
req->ntoread = -1;
|
||||
if (req->chunk_cb != NULL) {
|
||||
(*req->chunk_cb)(req, req->cb_arg);
|
||||
@ -771,9 +763,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
evbuffer_add_buffer(req->input_buffer, buf);
|
||||
} else if (EVBUFFER_LENGTH(buf) >= req->ntoread) {
|
||||
/* Completed content length */
|
||||
evbuffer_add(req->input_buffer, EVBUFFER_DATA(buf),
|
||||
req->ntoread);
|
||||
evbuffer_drain(buf, req->ntoread);
|
||||
evbuffer_remove_buffer(buf, req->input_buffer, req->ntoread);
|
||||
req->ntoread = 0;
|
||||
evhttp_connection_done(evcon);
|
||||
return;
|
||||
|
4
include/Makefile.am
Normal file
4
include/Makefile.am
Normal file
@ -0,0 +1,4 @@
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
|
||||
EXTRA_SRC = event2/buffer.h
|
||||
nobase_include_HEADERS = event2/buffer.h
|
312
include/event2/buffer.h
Normal file
312
include/event2/buffer.h
Normal file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _EVENT2_BUFFER_H_
|
||||
#define _EVENT2_BUFFER_H_
|
||||
|
||||
/** @file buffer.h
|
||||
|
||||
Functions for buffering data for network sending or receiving.
|
||||
|
||||
An evbuffer can be used for preparing data before sending it to
|
||||
the network or conversely for reading data from the network.
|
||||
Evbuffers try to avoid memory copies as much as possible. As a
|
||||
result evbuffers can be used to pass data around witout actually
|
||||
incurring the overhead of copying the data.
|
||||
|
||||
A new evbuffer can be allocated with evbuffer_new(), and can be
|
||||
freed with evbuffer_free().
|
||||
|
||||
There are several guide lines for using evbuffers.
|
||||
|
||||
- if you already know how much data you are going to add as a result
|
||||
of calling evbuffer_add() multiple times, it makes sense to use
|
||||
evbuffer_expand() first to make sure that enough memory is allocated
|
||||
before hand.
|
||||
|
||||
- evbuffer_add_buffer() adds the contents of one buffer to the other
|
||||
without incurring any memory copies.
|
||||
|
||||
- evbuffer_add() and evbuffer_add_buffer() do not mix very well.
|
||||
|
||||
As the contents of an evbuffer can be stored into multiple different
|
||||
memory blocks, it cannot be accessed directly. Instead, evbuffer_pullup()
|
||||
can be used to force a specified number of bytes to be continuous. This
|
||||
will cause memory reallocation and memory copies if the data is split
|
||||
across multiple blocks.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <event-config.h>
|
||||
|
||||
struct evbuffer;
|
||||
|
||||
/**
|
||||
Allocate storage for a new evbuffer.
|
||||
|
||||
@return a pointer to a newly allocated evbuffer struct, or NULL if an error
|
||||
occurred
|
||||
*/
|
||||
struct evbuffer *evbuffer_new(void);
|
||||
|
||||
|
||||
/**
|
||||
Deallocate storage for an evbuffer.
|
||||
|
||||
@param buf pointer to the evbuffer to be freed
|
||||
*/
|
||||
void evbuffer_free(struct evbuffer *buf);
|
||||
|
||||
/**
|
||||
Returns the total number of bytes stored in the event buffer
|
||||
|
||||
@param buf pointer to the evbuffer
|
||||
@return the number of bytes stored in the event buffer
|
||||
*/
|
||||
size_t evbuffer_length(struct evbuffer *buf);
|
||||
|
||||
/**
|
||||
Expands the available space in an event buffer.
|
||||
|
||||
Expands the available space in the event buffer to at least datlen
|
||||
|
||||
@param buf the event buffer to be expanded
|
||||
@param datlen the new minimum length requirement
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int evbuffer_expand(struct evbuffer *buf, size_t datlen);
|
||||
|
||||
|
||||
/**
|
||||
Append data to the end of an evbuffer.
|
||||
|
||||
@param buf the event buffer to be appended to
|
||||
@param data pointer to the beginning of the data buffer
|
||||
@param datlen the number of bytes to be copied from the data buffer
|
||||
*/
|
||||
int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen);
|
||||
|
||||
|
||||
/**
|
||||
Read data from an event buffer and drain the bytes read.
|
||||
|
||||
@param buf the event buffer to be read from
|
||||
@param data the destination buffer to store the result
|
||||
@param datlen the maximum size of the destination buffer
|
||||
@return the number of bytes read
|
||||
*/
|
||||
int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen);
|
||||
|
||||
/**
|
||||
Read data from an event buffer into another event buffer draining
|
||||
the bytes from the src buffer read. This function avoids memcpy
|
||||
as possible.
|
||||
|
||||
@param src the event buffer to be read from
|
||||
@param dst the destination event buffer to store the result into
|
||||
@param datlen the maximum numbers of bytes to transfer
|
||||
@return the number of bytes read
|
||||
*/
|
||||
int evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
|
||||
size_t datlen);
|
||||
|
||||
/** Used to tell evbuffer_readln what kind of line-ending to look for.
|
||||
*/
|
||||
enum evbuffer_eol_style {
|
||||
/** Any sequence of CR and LF characters is acceptable as an EOL. */
|
||||
EVBUFFER_EOL_ANY,
|
||||
/** An EOL is an LF, optionally preceded by a CR. This style is
|
||||
* most useful for implementing text-based internet protocols. */
|
||||
EVBUFFER_EOL_CRLF,
|
||||
/** An EOL is a CR followed by an LF. */
|
||||
EVBUFFER_EOL_CRLF_STRICT,
|
||||
/** An EOL is a LF. */
|
||||
EVBUFFER_EOL_LF
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a single line from an event buffer.
|
||||
*
|
||||
* Reads a line terminated by an EOL as determined by the evbuffer_eol_style
|
||||
* argument. Returns a newly allocated nul-terminated string; the caller must
|
||||
* free the returned value. The EOL is not included in the returned string.
|
||||
*
|
||||
* @param buffer the evbuffer to read from
|
||||
* @param n_read_out if non-NULL, points to a size_t that is set to the
|
||||
* number of characters in the returned string. This is useful for
|
||||
* strings that can contain NUL characters.
|
||||
* @param eol_style the style of line-ending to use.
|
||||
* @return pointer to a single line, or NULL if an error occurred
|
||||
*/
|
||||
char *evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
|
||||
enum evbuffer_eol_style eol_style);
|
||||
|
||||
/**
|
||||
Obsolete alias for evbuffer_readln(buffer, NULL, EOL_STYLE_ANY).
|
||||
|
||||
@param buffer the evbuffer to read from
|
||||
@return pointer to a single line, or NULL if an error occurred
|
||||
*/
|
||||
char *evbuffer_readline(struct evbuffer *buffer);
|
||||
|
||||
/**
|
||||
Move data from one evbuffer into another evbuffer.
|
||||
|
||||
This is a destructive add. The data from one buffer moves into
|
||||
the other buffer. However, no memory copies occur.
|
||||
|
||||
@param outbuf the output buffer
|
||||
@param inbuf the input buffer
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf);
|
||||
|
||||
|
||||
/**
|
||||
Append a formatted string to the end of an evbuffer.
|
||||
|
||||
@param buf the evbuffer that will be appended to
|
||||
@param fmt a format string
|
||||
@param ... arguments that will be passed to printf(3)
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Append a va_list formatted string to the end of an evbuffer.
|
||||
|
||||
@param buf the evbuffer that will be appended to
|
||||
@param fmt a format string
|
||||
@param ap a varargs va_list argument array that will be passed to vprintf(3)
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap);
|
||||
|
||||
|
||||
/**
|
||||
Remove a specified number of bytes data from the beginning of an evbuffer.
|
||||
|
||||
@param buf the evbuffer to be drained
|
||||
@param len the number of bytes to drain from the beginning of the buffer
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
void evbuffer_drain(struct evbuffer *buf, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
Write the contents of an evbuffer to a file descriptor.
|
||||
|
||||
The evbuffer will be drained after the bytes have been successfully written.
|
||||
|
||||
@param buffer the evbuffer to be written and drained
|
||||
@param fd the file descriptor to be written to
|
||||
@return the number of bytes written, or -1 if an error occurred
|
||||
@see evbuffer_read()
|
||||
*/
|
||||
int evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd);
|
||||
|
||||
|
||||
/**
|
||||
Read from a file descriptor and store the result in an evbuffer.
|
||||
|
||||
@param buf the evbuffer to store the result
|
||||
@param fd the file descriptor to read from
|
||||
@param howmuch the number of bytes to be read
|
||||
@return the number of bytes read, or -1 if an error occurred
|
||||
@see evbuffer_write()
|
||||
*/
|
||||
int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch);
|
||||
|
||||
|
||||
/**
|
||||
Find a string within an evbuffer.
|
||||
|
||||
@param buffer the evbuffer to be searched
|
||||
@param what the string to be searched for
|
||||
@param len the length of the search string
|
||||
@return a pointer to the beginning of the search string, or NULL if the search failed.
|
||||
*/
|
||||
u_char *evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len);
|
||||
|
||||
/**
|
||||
Set a callback to invoke when the evbuffer is modified.
|
||||
|
||||
@param buffer the evbuffer to be monitored
|
||||
@param cb the callback function to invoke when the evbuffer is modified
|
||||
@param cbarg an argument to be provided to the callback function
|
||||
*/
|
||||
void evbuffer_setcb(struct evbuffer *buffer,
|
||||
void (*cb)(struct evbuffer *, size_t, size_t, void *), void *cbarg);
|
||||
|
||||
/**
|
||||
Makes the memory in an evbuffer contiguous
|
||||
|
||||
@param buf the evbuffer to make contiguous
|
||||
@param size the number of bytes to make contiguous
|
||||
@return a pointer to the contigous memory areay
|
||||
*/
|
||||
|
||||
u_char *evbuffer_pullup(struct evbuffer *buf, int size);
|
||||
|
||||
/**
|
||||
Prepends data to the beginning of the evbuffer
|
||||
|
||||
@param buf the evbuffer to which to prepend data
|
||||
@param data a pointer to the memory to prepend
|
||||
@param size the number of bytes to prepend
|
||||
@return 0 if successful, or -1 otherwise
|
||||
*/
|
||||
|
||||
int evbuffer_prepend(struct evbuffer *buf, const void *data, size_t size);
|
||||
|
||||
/**
|
||||
Prepends the src evbuffer to the beginning of the dst evbuffer
|
||||
|
||||
@param dst the evbuffer to which to prepend data
|
||||
@param src the evbuffer to prepend; it will be emptied as a result
|
||||
*/
|
||||
|
||||
void evbuffer_prepend_buffer(struct evbuffer *dst, struct evbuffer* src);
|
||||
|
||||
/** deprecated in favor of calling the functions directly */
|
||||
#define EVBUFFER_LENGTH(x) evbuffer_length(x)
|
||||
#define EVBUFFER_DATA(x) evbuffer_pullup(x, -1)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVENT2_BUFFER_H_ */
|
@ -891,10 +891,12 @@ test_nonpersist_readd(void)
|
||||
}
|
||||
|
||||
static void
|
||||
test_evbuffer(void) {
|
||||
|
||||
test_evbuffer(void)
|
||||
{
|
||||
static char buffer[512], *tmp;
|
||||
struct evbuffer *evb = evbuffer_new();
|
||||
struct evbuffer *evb_two = evbuffer_new();
|
||||
int i;
|
||||
setup_test("Testing Evbuffer: ");
|
||||
|
||||
evbuffer_add_printf(evb, "%s/%d", "hello", 1);
|
||||
@ -916,6 +918,50 @@ test_evbuffer(void) {
|
||||
strcmp((char*)EVBUFFER_DATA(evb), "1/hello") != 0)
|
||||
goto out;
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
evbuffer_add(evb, buffer, sizeof(buffer));
|
||||
if (EVBUFFER_LENGTH(evb) != 7 + 512)
|
||||
goto out;
|
||||
|
||||
tmp = (char *)evbuffer_pullup(evb, 7 + 512);
|
||||
if (tmp == NULL)
|
||||
goto out;
|
||||
if (strncmp(tmp, "1/hello", 7) != 0)
|
||||
goto out;
|
||||
if (memcmp(tmp + 7, buffer, sizeof(buffer)) != 0)
|
||||
goto out;
|
||||
|
||||
evbuffer_prepend(evb, "something", 9);
|
||||
evbuffer_prepend(evb, "else", 4);
|
||||
|
||||
tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7);
|
||||
if (strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7) != 0)
|
||||
goto out;
|
||||
|
||||
evbuffer_drain(evb, -1);
|
||||
evbuffer_drain(evb_two, -1);
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
evbuffer_add(evb_two, buffer, sizeof(buffer));
|
||||
evbuffer_add_buffer(evb, evb_two);
|
||||
}
|
||||
|
||||
if (EVBUFFER_LENGTH(evb_two) != 0 ||
|
||||
EVBUFFER_LENGTH(evb) != i * sizeof(buffer))
|
||||
goto out;
|
||||
|
||||
/* test remove buffer */
|
||||
evbuffer_remove_buffer(evb, evb_two, sizeof(buffer) * 2.5);
|
||||
if (EVBUFFER_LENGTH(evb_two) != sizeof(buffer) * 2.5 ||
|
||||
EVBUFFER_LENGTH(evb) != sizeof(buffer) * 0.5)
|
||||
goto out;
|
||||
|
||||
if (memcmp(evbuffer_pullup(
|
||||
evb, -1), buffer, sizeof(buffer) / 2) != 0 ||
|
||||
memcmp(evbuffer_pullup(
|
||||
evb_two, -1), buffer, sizeof(buffer) != 0))
|
||||
goto out;
|
||||
|
||||
test_ok = 1;
|
||||
|
||||
out:
|
||||
@ -929,6 +975,7 @@ static void
|
||||
test_evbuffer_readln(void)
|
||||
{
|
||||
struct evbuffer *evb = evbuffer_new();
|
||||
struct evbuffer *evb_tmp = evbuffer_new();
|
||||
const char *s;
|
||||
char *cp = NULL;
|
||||
size_t sz;
|
||||
@ -1027,9 +1074,41 @@ test_evbuffer_readln(void)
|
||||
if (!cp || sz != strlen(cp) || strcmp(cp, "Text"))
|
||||
goto done;
|
||||
|
||||
/* Test CRLF_STRICT - across boundaries*/
|
||||
s = " and a bad crlf\nand a good one\r";
|
||||
evbuffer_add(evb_tmp, s, strlen(s));
|
||||
evbuffer_add_buffer(evb, evb_tmp);
|
||||
s = "\n\r";
|
||||
evbuffer_add(evb_tmp, s, strlen(s));
|
||||
evbuffer_add_buffer(evb, evb_tmp);
|
||||
s = "\nMore\r";
|
||||
evbuffer_add(evb_tmp, s, strlen(s));
|
||||
evbuffer_add_buffer(evb, evb_tmp);
|
||||
|
||||
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
||||
if (!cp || sz != strlen(cp) ||
|
||||
strcmp(cp, " and a bad crlf\nand a good one"))
|
||||
goto done;
|
||||
free(cp);
|
||||
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
||||
if (!cp || sz != strlen(cp) || strcmp(cp, ""))
|
||||
goto done;
|
||||
free(cp);
|
||||
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
||||
if (cp)
|
||||
goto done;
|
||||
evbuffer_add(evb, "\n", 1);
|
||||
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
||||
if (!cp || sz != strlen(cp) || strcmp(cp, "More"))
|
||||
goto done;
|
||||
if (EVBUFFER_LENGTH(evb) != 0)
|
||||
goto done;
|
||||
|
||||
|
||||
test_ok = 1;
|
||||
done:
|
||||
evbuffer_free(evb);
|
||||
evbuffer_free(evb_tmp);
|
||||
if (cp) free(cp);
|
||||
cleanup_test();
|
||||
}
|
||||
@ -1371,7 +1450,7 @@ evtag_fuzz(void)
|
||||
evtag_marshal_timeval(tmp, 0, &tv);
|
||||
evbuffer_add(tmp, buffer, sizeof(buffer));
|
||||
|
||||
EVBUFFER_DATA(tmp)[1] = 0xff;
|
||||
((char *)EVBUFFER_DATA(tmp))[1] = 0xff;
|
||||
if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) {
|
||||
fprintf(stderr, "evtag_unmarshal_timeval should have failed");
|
||||
exit(1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user