Index: lib/libevent/Makefile =================================================================== RCS file: /home/dcvs/src/lib/libevent/Makefile,v retrieving revision 1.2 diff -u -r1.2 Makefile --- lib/libevent/Makefile 31 Jan 2008 08:25:12 -0000 1.2 +++ lib/libevent/Makefile 30 Jun 2008 23:55:05 -0000 @@ -4,9 +4,9 @@ .PATH: ${SRCDIR} LIB= event -SRCS= buffer.c evbuffer.c evdns.c event-internal.h event.c +SRCS= buffer.c evbuffer.c evdns.c event-internal.h event.c evrpc.c evutil.c http.c SRCS+= event_tagging.c kqueue.c log.c log.h poll.c select.c signal.c -INCS= event.h evdns.h +INCS= event.h evdns.h event-config.h evutil.h CFLAGS= -I${.CURDIR} -I. -I${SRCDIR} -DHAVE_CONFIG_H Index: lib/libevent/config.h =================================================================== RCS file: /home/dcvs/src/lib/libevent/config.h,v retrieving revision 1.1 diff -u -r1.1 config.h --- lib/libevent/config.h 30 Jan 2008 12:57:50 -0000 1.1 +++ lib/libevent/config.h 30 Jun 2008 19:57:37 -0000 @@ -1,86 +1,5 @@ -/* $DragonFly: src/lib/libevent/config.h,v 1.1 2008/01/30 12:57:50 hasso Exp $ */ - /* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ -/* Define if kqueue works correctly with pipes */ -#define HAVE_WORKING_KQUEUE 1 - -/* Define to `unsigned long long' if doesn't define. */ -/* #undef u_int64_t */ - -/* Define to `unsigned int' if doesn't define. */ -/* #undef u_int32_t */ - -/* Define to `unsigned short' if doesn't define. */ -/* #undef u_int16_t */ - -/* Define to `unsigned char' if doesn't define. */ -/* #undef u_int8_t */ - -/* Define if timeradd is defined in */ -#define HAVE_TIMERADD 1 -#ifndef HAVE_TIMERADD -/* #undef timersub */ -#define timeradd(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ - if ((vvp)->tv_usec >= 1000000) { \ - (vvp)->tv_sec++; \ - (vvp)->tv_usec -= 1000000; \ - } \ - } while (0) -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ - } while (0) -#endif /* !HAVE_TIMERADD */ - -#define HAVE_TIMERCLEAR 1 -#ifndef HAVE_TIMERCLEAR -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif - -#define HAVE_TIMERCMP 1 -#ifndef HAVE_TIMERCMP -/* #undef timercmp */ -#define timercmp(tvp, uvp, cmp) \ - (((tvp)->tv_sec == (uvp)->tv_sec) ? \ - ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ - ((tvp)->tv_sec cmp (uvp)->tv_sec)) -#endif - -#define HAVE_TIMERISSET 1 -#ifndef HAVE_TIMERISSET -/* #undef timerisset */ -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#endif - -/* Define if TAILQ_FOREACH is defined in */ -#define HAVE_TAILQFOREACH 1 -#ifndef HAVE_TAILQFOREACH -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) NULL -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_FOREACH(var, head, field) \ - for((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_NEXT(var, field)) -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (0) -#endif /* TAILQ_FOREACH */ - -/* Define to __FUNCTION__ or __file__ if your compiler doesn't have __func__ */ -/* #undef __func__ */ /* Define if clock_gettime is available in libc */ #define DNS_USE_CPU_CLOCK_FOR_ID 1 @@ -160,21 +79,21 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_PORT_H */ -/* Define if your system supports POSIX realtime signals */ -/* #undef HAVE_RTSIG */ - /* Define to 1 if you have the `select' function. */ #define HAVE_SELECT 1 /* Define if F_SETFD is defined in */ #define HAVE_SETFD 1 +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `signal' function. */ +#define HAVE_SIGNAL 1 + /* Define to 1 if you have the header file. */ #define HAVE_SIGNAL_H 1 -/* Define to 1 if you have the `sigtimedwait' function. */ -/* #undef HAVE_SIGTIMEDWAIT */ - /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 @@ -199,6 +118,9 @@ /* Define to 1 if you have the `strtok_r' function. */ #define HAVE_STRTOK_R 1 +/* Define to 1 if you have the `strtoll' function. */ +#define HAVE_STRTOLL 1 + /* Define to 1 if the system has the type `struct in6_addr'. */ #define HAVE_STRUCT_IN6_ADDR 1 @@ -214,12 +136,18 @@ /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_SYS_QUEUE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 @@ -244,6 +172,18 @@ /* Define if timerisset is defined in */ #define HAVE_TIMERISSET 1 +/* Define to 1 if the system has the type `uint16_t'. */ +#define HAVE_UINT16_T 1 + +/* Define to 1 if the system has the type `uint32_t'. */ +#define HAVE_UINT32_T 1 + +/* Define to 1 if the system has the type `uint64_t'. */ +#define HAVE_UINT64_T 1 + +/* Define to 1 if the system has the type `uint8_t'. */ +#define HAVE_UINT8_T 1 + /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 @@ -253,9 +193,6 @@ /* Define if kqueue works correctly with pipes */ #define HAVE_WORKING_KQUEUE 1 -/* Define if realtime signals work on pipes */ -/* #undef HAVE_WORKING_RTSIG */ - /* Name of package */ #define PACKAGE "libevent" @@ -274,6 +211,18 @@ /* Define to the version of this package. */ #define PACKAGE_VERSION "" +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* The size of `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG 8 + +/* The size of `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 @@ -281,7 +230,7 @@ #define TIME_WITH_SYS_TIME 1 /* Version number of package */ -#define VERSION "1.3e" +#define VERSION "1.4.5-stable" /* Define to appropriate substitue if compiler doesnt have __func__ */ /* #undef __func__ */ @@ -303,15 +252,3 @@ /* Define to unsigned int if you dont have it */ /* #undef socklen_t */ - -/* Define to `unsigned short' if does not define. */ -/* #undef uint16_t */ - -/* Define to `unsigned int' if does not define. */ -/* #undef uint32_t */ - -/* Define to `unsigned long long' if does not define. */ -/* #undef uint64_t */ - -/* Define to `unsigned char' if does not define. */ -/* #undef uint8_t */ Index: contrib/libevent/README.DELETED =================================================================== RCS file: /home/dcvs/src/contrib/libevent/README.DELETED,v retrieving revision 1.1 diff -u -r1.1 README.DELETED --- contrib/libevent/README.DELETED 30 Jan 2008 12:52:45 -0000 1.1 +++ contrib/libevent/README.DELETED 30 Jun 2008 21:10:27 -0000 @@ -1,3 +1,4 @@ +autogen.sh ChangeLog Makefile.am Makefile.in @@ -16,15 +17,13 @@ epoll.c epoll_sub.c event_rpcgen.py -evhttp.h evport.c -http-internal.h -http.c install-sh ltmain.sh missing rtsig.c sample/ -strlcpy-internal.h strlcpy.c test/ +stamp-* +mkinstalldirs Index: contrib/libevent/buffer.c =================================================================== RCS file: /home/dcvs/src/contrib/libevent/buffer.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 buffer.c --- contrib/libevent/buffer.c 30 Jan 2008 12:35:18 -0000 1.1.1.1 +++ contrib/libevent/buffer.c 12 Nov 2007 02:37:32 -0000 @@ -29,6 +29,11 @@ #include "config.h" #endif +#ifdef WIN32 +#include +#include +#endif + #ifdef HAVE_VASPRINTF /* If we have vasprintf, we need to define this before we include stdio.h. */ #define _GNU_SOURCE @@ -57,6 +62,7 @@ #endif #include "event.h" +#include "config.h" struct evbuffer * evbuffer_new(void) @@ -351,12 +357,14 @@ u_char *p; size_t oldoff = buf->off; int n = EVBUFFER_MAX_READ; -#ifdef WIN32 - DWORD dwBytesRead; -#endif -#ifdef FIONREAD +#if defined(FIONREAD) +#ifdef WIN32 + long lng = n; + if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) == 0) { +#else if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) { +#endif n = EVBUFFER_MAX_READ; } else if (n > EVBUFFER_MAX_READ && n > howmuch) { /* @@ -384,18 +392,13 @@ #ifndef WIN32 n = read(fd, p, howmuch); +#else + n = recv(fd, p, howmuch, 0); +#endif if (n == -1) return (-1); if (n == 0) return (0); -#else - n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL); - if (n == 0) - return (-1); - if (dwBytesRead == 0) - return (0); - n = dwBytesRead; -#endif buf->off += n; @@ -410,24 +413,16 @@ evbuffer_write(struct evbuffer *buffer, int fd) { int n; -#ifdef WIN32 - DWORD dwBytesWritten; -#endif #ifndef WIN32 n = write(fd, buffer->buffer, buffer->off); +#else + n = send(fd, buffer->buffer, buffer->off, 0); +#endif if (n == -1) return (-1); if (n == 0) return (0); -#else - n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL); - if (n == 0) - return (-1); - if (dwBytesWritten == 0) - return (0); - n = dwBytesWritten; -#endif evbuffer_drain(buffer, n); return (n); Index: contrib/libevent/evbuffer.c =================================================================== RCS file: /home/dcvs/src/contrib/libevent/evbuffer.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 evbuffer.c --- contrib/libevent/evbuffer.c 30 Jan 2008 12:35:18 -0000 1.1.1.1 +++ contrib/libevent/evbuffer.c 28 Apr 2008 02:17:27 -0000 @@ -43,11 +43,15 @@ #include #endif +#ifdef WIN32 +#include +#endif + +#include "evutil.h" #include "event.h" /* prototypes */ -void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t); void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *); static int @@ -56,7 +60,7 @@ struct timeval tv, *ptv = NULL; if (timeout) { - timerclear(&tv); + evutil_timerclear(&tv); tv.tv_sec = timeout; ptv = &tv; } @@ -103,8 +107,17 @@ * If we have a high watermark configured then we don't want to * read more data than would make us reach the watermark. */ - if (bufev->wm_read.high != 0) - howmuch = bufev->wm_read.high; + if (bufev->wm_read.high != 0) { + howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input); + /* we might have lowered the watermark, stop reading */ + if (howmuch <= 0) { + struct evbuffer *buf = bufev->input; + event_del(&bufev->ev_read); + evbuffer_setcb(buf, + bufferevent_read_pressure_cb, bufev); + return; + } + } res = evbuffer_read(bufev->input, fd, howmuch); if (res == -1) { @@ -126,13 +139,12 @@ len = EVBUFFER_LENGTH(bufev->input); if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) return; - if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) { + if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) { struct evbuffer *buf = bufev->input; event_del(&bufev->ev_read); - /* Now schedule a callback for us */ + /* Now schedule a callback for us when the buffer changes */ evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); - return; } /* Invoke the user callback - must always be called last */ @@ -241,11 +253,7 @@ event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev); event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev); - bufev->readcb = readcb; - bufev->writecb = writecb; - bufev->errorcb = errorcb; - - bufev->cbarg = cbarg; + bufferevent_setcb(bufev, readcb, writecb, errorcb, cbarg); /* * Set to EV_WRITE so that using bufferevent_write is going to @@ -257,6 +265,33 @@ return (bufev); } +void +bufferevent_setcb(struct bufferevent *bufev, + evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg) +{ + bufev->readcb = readcb; + bufev->writecb = writecb; + bufev->errorcb = errorcb; + + bufev->cbarg = cbarg; +} + +void +bufferevent_setfd(struct bufferevent *bufev, int fd) +{ + event_del(&bufev->ev_read); + event_del(&bufev->ev_write); + + event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev); + event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev); + if (bufev->ev_base != NULL) { + event_base_set(bufev->ev_base, &bufev->ev_read); + event_base_set(bufev->ev_base, &bufev->ev_write); + } + + /* might have to manually trigger event registration */ +} + int bufferevent_priority_set(struct bufferevent *bufev, int priority) { @@ -288,7 +323,7 @@ */ int -bufferevent_write(struct bufferevent *bufev, void *data, size_t size) +bufferevent_write(struct bufferevent *bufev, const void *data, size_t size) { int res; @@ -404,6 +439,8 @@ { int res; + bufev->ev_base = base; + res = event_base_set(base, &bufev->ev_read); if (res == -1) return (res); Index: contrib/libevent/evdns.c =================================================================== RCS file: /home/dcvs/src/contrib/libevent/evdns.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 evdns.c --- contrib/libevent/evdns.c 30 Jan 2008 12:35:18 -0000 1.1.1.1 +++ contrib/libevent/evdns.c 14 May 2008 04:07:41 -0000 @@ -39,20 +39,20 @@ #include "config.h" #endif -#ifdef WIN32 -#include "misc.h" +#ifdef DNS_USE_FTIME_FOR_ID +#include #endif -/* #define NDEBUG */ - #ifndef DNS_USE_CPU_CLOCK_FOR_ID #ifndef DNS_USE_GETTIMEOFDAY_FOR_ID #ifndef DNS_USE_OPENSSL_FOR_ID +#ifndef DNS_USE_FTIME_FOR_ID #error Must configure at least one id generation method. #error Please see the documentation. #endif #endif #endif +#endif /* #define _POSIX_C_SOURCE 200507 */ #define _GNU_SOURCE @@ -78,7 +78,9 @@ #include #include +#ifdef HAVE_SYS_TIME_H #include +#endif #ifdef HAVE_STDINT_H #include #endif @@ -86,7 +88,9 @@ #include #include #include +#ifdef HAVE_UNISTD_H #include +#endif #include #include #include @@ -94,11 +98,13 @@ #include #include "evdns.h" +#include "evutil.h" #include "log.h" #ifdef WIN32 -#include #include +#include #include +#include #else #include #include @@ -109,10 +115,6 @@ #include #endif -#ifdef WIN32 -typedef int socklen_t; -#endif - #define EVDNS_LOG_DEBUG 0 #define EVDNS_LOG_WARN 1 @@ -120,26 +122,32 @@ #define HOST_NAME_MAX 255 #endif -#ifndef NDEBUG #include -#endif #undef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #ifdef __USE_ISOC99B /* libevent doesn't work without this */ -typedef uint8_t u_char; +typedef ev_uint8_t u_char; typedef unsigned int uint; #endif #include -#define u64 uint64_t -#define u32 uint32_t -#define u16 uint16_t -#define u8 uint8_t +#define u64 ev_uint64_t +#define u32 ev_uint32_t +#define u16 ev_uint16_t +#define u8 ev_uint8_t + +#ifdef WIN32 +#define snprintf _snprintf +#define open _open +#define read _read +#define close _close +#define strdup _strdup +#endif -#define MAX_ADDRS 4 /* maximum number of addresses from a single packet */ +#define MAX_ADDRS 32 /* maximum number of addresses from a single packet */ /* which we bother recording */ #define TYPE_A EVDNS_TYPE_A @@ -319,7 +327,7 @@ static void evdns_requests_pump_waiting_queue(void); static u16 transaction_id_pick(void); static struct request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr); -static void request_submit(struct request *req); +static void request_submit(struct request *const req); static int server_request_free(struct server_request *req); static void server_request_free_answers(struct server_request *req); @@ -352,7 +360,7 @@ static int inet_aton(const char *c, struct in_addr *addr) { - uint32_t r; + ev_uint32_t r; if (strcmp(c, "255.255.255.255") == 0) { addr->s_addr = 0xffffffffu; } else { @@ -363,17 +371,15 @@ } return 1; } -#define CLOSE_SOCKET(x) closesocket(x) #else #define last_error(sock) (errno) #define error_is_eagain(err) ((err) == EAGAIN) -#define CLOSE_SOCKET(x) close(x) #endif +#define CLOSE_SOCKET(s) EVUTIL_CLOSESOCKET(s) #define ISSPACE(c) isspace((int)(unsigned char)(c)) #define ISDIGIT(c) isdigit((int)(unsigned char)(c)) -#ifndef NDEBUG static const char * debug_ntoa(u32 address) { @@ -386,7 +392,6 @@ (int)(u8)((a )&0xff)); return buf; } -#endif static evdns_debug_log_fn_type evdns_log_fn = NULL; @@ -852,7 +857,7 @@ */ SKIP_NAME; j += 4; - if (j >= length) goto err; + if (j > length) goto err; } /* now we have the answer section which looks like @@ -953,8 +958,7 @@ GET16(additional); if (flags & 0x8000) return -1; /* Must not be an answer. */ - if (flags & 0x7800) return -1; /* only standard queries are supported */ - flags &= 0x0300; /* Only TC and RD get preserved. */ + flags &= 0x0110; /* Only RD and CD get preserved. */ server_req = malloc(sizeof(struct server_request)); if (server_req == NULL) return -1; @@ -983,7 +987,7 @@ if (!q) goto err; q->type = type; - q->class = class; + q->dns_question_class = class; memcpy(q->name, tmp_name, namelen+1); server_req->base.questions[server_req->base.nquestions++] = q; } @@ -992,6 +996,13 @@ server_req->port = port; port->refcnt++; + + /* Only standard queries are supported. */ + if (flags & 0x7800) { + evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL); + return -1; + } + port->user_callback(&(server_req->base), port->user_data); return 0; @@ -1012,41 +1023,65 @@ #undef GET8 } -/* Try to choose a strong transaction id which isn't already in flight */ static u16 -transaction_id_pick(void) { - for (;;) { - const struct request *req = req_head, *started_at; +default_transaction_id_fn(void) +{ + u16 trans_id; #ifdef DNS_USE_CPU_CLOCK_FOR_ID - struct timespec ts; - u16 trans_id; + struct timespec ts; #ifdef CLOCK_MONOTONIC - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) #else - if (clock_gettime(CLOCK_REALTIME, &ts) == -1) + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) #endif - event_err(1, "clock_gettime"); - trans_id = ts.tv_nsec & 0xffff; + event_err(1, "clock_gettime"); + trans_id = ts.tv_nsec & 0xffff; +#endif + +#ifdef DNS_USE_FTIME_FOR_ID + struct _timeb tb; + _ftime(&tb); + trans_id = tb.millitm & 0xffff; #endif #ifdef DNS_USE_GETTIMEOFDAY_FOR_ID - struct timeval tv; - u16 trans_id; - gettimeofday(&tv, NULL); - trans_id = tv.tv_usec & 0xffff; + struct timeval tv; + evutil_gettimeofday(&tv, NULL); + trans_id = tv.tv_usec & 0xffff; #endif #ifdef DNS_USE_OPENSSL_FOR_ID - u16 trans_id; - if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) { - /* in the case that the RAND call fails we back */ - /* down to using gettimeofday. */ - struct timeval tv; - gettimeofday(&tv, NULL); - trans_id = tv.tv_usec & 0xffff; */ - abort(); - } + if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) { + /* in the case that the RAND call fails we back */ + /* down to using gettimeofday. */ + /* + struct timeval tv; + evutil_gettimeofday(&tv, NULL); + trans_id = tv.tv_usec & 0xffff; + */ + abort(); + } #endif + return trans_id; +} + +static ev_uint16_t (*trans_id_function)(void) = default_transaction_id_fn; + +void +evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void)) +{ + if (fn) + trans_id_function = fn; + else + trans_id_function = default_transaction_id_fn; +} + +/* Try to choose a strong transaction id which isn't already in flight */ +static u16 +transaction_id_pick(void) { + for (;;) { + const struct request *req = req_head, *started_at; + u16 trans_id = trans_id_function(); if (trans_id == 0xffff) continue; /* now check to see if that id is already inflight */ @@ -1472,7 +1507,7 @@ return -1; } item->type = type; - item->class = class; + item->dns_question_class = class; item->ttl = ttl; item->is_name = is_name != 0; item->datalen = 0; @@ -1587,7 +1622,7 @@ return (int) j; } APPEND16(req->base.questions[i]->type); - APPEND16(req->base.questions[i]->class); + APPEND16(req->base.questions[i]->dns_question_class); } /* Add answer, authority, and additional sections. */ @@ -1606,7 +1641,7 @@ j = r; APPEND16(item->type); - APPEND16(item->class); + APPEND16(item->dns_question_class); APPEND32(item->ttl); if (item->is_name) { off_t len_idx = j, name_start; @@ -1616,7 +1651,7 @@ if (r < 0) goto overflow; j = r; - _t = htons( (j-name_start) ); + _t = htons( (short) (j-name_start) ); memcpy(buf+len_idx, &_t, 2); } else { APPEND16(item->datalen); @@ -1663,8 +1698,8 @@ r = sendto(port->socket, req->response, req->response_len, 0, (struct sockaddr*) &req->addr, req->addrlen); if (r<0) { - int err = last_error(port->socket); - if (! error_is_eagain(err)) + int sock_err = last_error(port->socket); + if (! error_is_eagain(sock_err)) return -1; if (port->pending_replies) { @@ -1981,7 +2016,8 @@ while (1) { struct nameserver *next = server->next; (void) event_del(&server->event); - (void) evtimer_del(&server->timeout_event); + if (evtimer_initialized(&server->timeout_event)) + (void) evtimer_del(&server->timeout_event); if (server->socket >= 0) CLOSE_SOCKET(server->socket); free(server); @@ -2050,14 +2086,7 @@ ns->socket = socket(PF_INET, SOCK_DGRAM, 0); if (ns->socket < 0) { err = 1; goto out1; } -#ifdef WIN32 - { - u_long nonblocking = 1; - ioctlsocket(ns->socket, FIONBIO, &nonblocking); - } -#else - fcntl(ns->socket, F_SETFL, O_NONBLOCK); -#endif + evutil_make_socket_nonblocking(ns->socket); sin.sin_addr.s_addr = address; sin.sin_port = htons(port); sin.sin_family = AF_INET; @@ -2267,7 +2296,8 @@ } int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { - char buf[64]; + /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */ + char buf[73]; char *cp; struct request *req; int i; @@ -2280,8 +2310,8 @@ *cp++ = "0123456789abcdef"[byte >> 4]; *cp++ = '.'; } - assert(cp + strlen(".ip6.arpa") < buf+sizeof(buf)); - memcpy(cp, ".ip6.arpa", strlen(".ip6.arpa")+1); + assert(cp + strlen("ip6.arpa") < buf+sizeof(buf)); + memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1); log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); req = request_new(TYPE_PTR, buf, flags, callback, ptr); if (!req) return 1; @@ -2495,7 +2525,7 @@ /* this name without a postfix */ if (string_num_dots(req->search_origname) < req->search_state->ndots) { /* yep, we need to try it raw */ - struct request *const newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer); + newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer); log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname); if (newreq) { request_submit(newreq); @@ -2917,7 +2947,7 @@ #undef TRY } -int +static int evdns_config_windows_nameservers(void) { if (load_nameservers_with_getnetworkparams() == 0) @@ -2931,7 +2961,7 @@ { int res = 0; #ifdef WIN32 - evdns_config_windows_nameservers(); + res = evdns_config_windows_nameservers(); #else res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); #endif @@ -3029,20 +3059,20 @@ for (i = 0; i < req->nquestions; ++i) { u32 ans = htonl(0xc0a80b0bUL); if (req->questions[i]->type == EVDNS_TYPE_A && - req->questions[i]->class == EVDNS_CLASS_INET) { + req->questions[i]->dns_question_class == EVDNS_CLASS_INET) { printf(" -- replying for %s (A)\n", req->questions[i]->name); r = evdns_server_request_add_a_reply(req, req->questions[i]->name, 1, &ans, 10); if (r<0) printf("eeep, didn't work.\n"); } else if (req->questions[i]->type == EVDNS_TYPE_PTR && - req->questions[i]->class == EVDNS_CLASS_INET) { + req->questions[i]->dns_question_class == EVDNS_CLASS_INET) { printf(" -- replying for %s (PTR)\n", req->questions[i]->name); r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name, "foo.bar.example.com", 10); } else { printf(" -- skipping %s [%d %d]\n", req->questions[i]->name, - req->questions[i]->type, req->questions[i]->class); + req->questions[i]->type, req->questions[i]->dns_question_class); } } @@ -3085,7 +3115,7 @@ int sock; struct sockaddr_in my_addr; sock = socket(PF_INET, SOCK_DGRAM, 0); - fcntl(sock, F_SETFL, O_NONBLOCK); + evutil_make_socket_nonblocking(sock); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(10053); my_addr.sin_addr.s_addr = INADDR_ANY; Index: contrib/libevent/evdns.h =================================================================== RCS file: /home/dcvs/src/contrib/libevent/evdns.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 evdns.h --- contrib/libevent/evdns.h 30 Jan 2008 12:35:18 -0000 1.1.1.1 +++ contrib/libevent/evdns.h 12 Nov 2007 02:37:32 -0000 @@ -47,7 +47,8 @@ * the source verbatim in their source distributions) */ -/* +/** @file evdns.h + * * Welcome, gentle reader * * Async DNS lookups are really a whole lot harder than they should be, @@ -136,85 +137,6 @@ * Query: www.abc * Order: www.abc., www.abc.myhome.net * - * API reference: - * - * int evdns_nameserver_add(unsigned long int address) - * Add a nameserver. The address should be an IP address in - * network byte order. The type of address is chosen so that - * it matches in_addr.s_addr. - * Returns non-zero on error. - * - * int evdns_nameserver_ip_add(const char *ip_as_string) - * This wraps the above function by parsing a string as an IP - * address and adds it as a nameserver. - * Returns non-zero on error - * - * int evdns_resolve(const char *name, int flags, - * evdns_callback_type callback, - * void *ptr) - * Resolve a name. The name parameter should be a DNS name. - * The flags parameter should be 0, or DNS_QUERY_NO_SEARCH - * which disables searching for this query. (see defn of - * searching above). - * - * The callback argument is a function which is called when - * this query completes and ptr is an argument which is passed - * to that callback function. - * - * Returns non-zero on error - * - * void evdns_search_clear() - * Clears the list of search domains - * - * void evdns_search_add(const char *domain) - * Add a domain to the list of search domains - * - * void evdns_search_ndots_set(int ndots) - * Set the number of dots which, when found in a name, causes - * the first query to be without any search domain. - * - * int evdns_count_nameservers(void) - * Return the number of configured nameservers (not necessarily the - * number of running nameservers). This is useful for double-checking - * whether our calls to the various nameserver configuration functions - * have been successful. - * - * int evdns_clear_nameservers_and_suspend(void) - * Remove all currently configured nameservers, and suspend all pending - * resolves. Resolves will not necessarily be re-attempted until - * evdns_resume() is called. - * - * int evdns_resume(void) - * Re-attempt resolves left in limbo after an earlier call to - * evdns_clear_nameservers_and_suspend(). - * - * int evdns_config_windows_nameservers(void) - * Attempt to configure a set of nameservers based on platform settings on - * a win32 host. Preferentially tries to use GetNetworkParams; if that fails, - * looks in the registry. Returns 0 on success, nonzero on failure. - * - * int evdns_resolv_conf_parse(int flags, const char *filename) - * Parse a resolv.conf like file from the given filename. - * - * See the man page for resolv.conf for the format of this file. - * The flags argument determines what information is parsed from - * this file: - * DNS_OPTION_SEARCH - domain, search and ndots options - * DNS_OPTION_NAMESERVERS - nameserver lines - * DNS_OPTION_MISC - timeout and attempts options - * DNS_OPTIONS_ALL - all of the above - * The following directives are not parsed from the file: - * sortlist, rotate, no-check-names, inet6, debug - * - * Returns non-zero on error: - * 0 no errors - * 1 failed to open file - * 2 failed to stat file - * 3 file too large - * 4 out of memory - * 5 short read from file - * 6 no nameservers in file - * * Internals: * * Requests are kept in two queues. The first is the inflight queue. In @@ -242,27 +164,30 @@ extern "C" { #endif -/* Error codes 0-5 are as described in RFC 1035. */ +/* For integer types. */ +#include + +/** Error codes 0-5 are as described in RFC 1035. */ #define DNS_ERR_NONE 0 -/* The name server was unable to interpret the query */ +/** The name server was unable to interpret the query */ #define DNS_ERR_FORMAT 1 -/* The name server was unable to process this query due to a problem with the +/** The name server was unable to process this query due to a problem with the * name server */ #define DNS_ERR_SERVERFAILED 2 -/* The domain name does not exist */ +/** The domain name does not exist */ #define DNS_ERR_NOTEXIST 3 -/* The name server does not support the requested kind of query */ +/** The name server does not support the requested kind of query */ #define DNS_ERR_NOTIMPL 4 -/* The name server refuses to reform the specified operation for policy +/** The name server refuses to reform the specified operation for policy * reasons */ #define DNS_ERR_REFUSED 5 -/* The reply was truncated or ill-formated */ +/** The reply was truncated or ill-formated */ #define DNS_ERR_TRUNCATED 65 -/* An unknown error occurred */ +/** An unknown error occurred */ #define DNS_ERR_UNKNOWN 66 -/* Communication with the server timed out */ +/** Communication with the server timed out */ #define DNS_ERR_TIMEOUT 67 -/* The request was canceled because the DNS subsystem was shut down. */ +/** The request was canceled because the DNS subsystem was shut down. */ #define DNS_ERR_SHUTDOWN 68 #define DNS_IPv4_A 1 @@ -276,7 +201,7 @@ #define DNS_OPTION_MISC 4 #define DNS_OPTIONS_ALL 7 -/* +/** * The callback that contains the results from a lookup. * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA * - count contains the number of addresses of form type @@ -285,37 +210,261 @@ */ typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg); +/** + Initialize the asynchronous DNS library. + + This function initializes support for non-blocking name resolution by + calling evdns_resolv_conf_parse() on UNIX and + evdns_config_windows_nameservers() on Windows. + + @return 0 if successful, or -1 if an error occurred + @see evdns_shutdown() + */ int evdns_init(void); + + +/** + Shut down the asynchronous DNS resolver and terminate all active requests. + + If the 'fail_requests' option is enabled, all active requests will return + an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise, + the requests will be silently discarded. + + @param fail_requests if zero, active requests will be aborted; if non-zero, + active requests will return DNS_ERR_SHUTDOWN. + @see evdns_init() + */ void evdns_shutdown(int fail_requests); + + +/** + Convert a DNS error code to a string. + + @param err the DNS error code + @return a string containing an explanation of the error code +*/ const char *evdns_err_to_string(int err); + + +/** + Add a nameserver. + + The address should be an IPv4 address in network byte order. + The type of address is chosen so that it matches in_addr.s_addr. + + @param address an IP address in network byte order + @return 0 if successful, or -1 if an error occurred + @see evdns_nameserver_ip_add() + */ int evdns_nameserver_add(unsigned long int address); + + +/** + Get the number of configured nameservers. + + This returns the number of configured nameservers (not necessarily the + number of running nameservers). This is useful for double-checking + whether our calls to the various nameserver configuration functions + have been successful. + + @return the number of configured nameservers + @see evdns_nameserver_add() + */ int evdns_count_nameservers(void); + + +/** + Remove all configured nameservers, and suspend all pending resolves. + + Resolves will not necessarily be re-attempted until evdns_resume() is called. + + @return 0 if successful, or -1 if an error occurred + @see evdns_resume() + */ int evdns_clear_nameservers_and_suspend(void); + + +/** + Resume normal operation and continue any suspended resolve requests. + + Re-attempt resolves left in limbo after an earlier call to + evdns_clear_nameservers_and_suspend(). + + @return 0 if successful, or -1 if an error occurred + @see evdns_clear_nameservers_and_suspend() + */ int evdns_resume(void); + + +/** + Add a nameserver. + + This wraps the evdns_nameserver_add() function by parsing a string as an IP + address and adds it as a nameserver. + + @return 0 if successful, or -1 if an error occurred + @see evdns_nameserver_add() + */ int evdns_nameserver_ip_add(const char *ip_as_string); + + +/** + Lookup an A record for a given name. + + @param name a DNS hostname + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() + */ int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr); + + +/** + Lookup an AAAA record for a given name. + + @param name a DNS hostname + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() + */ int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr); + struct in_addr; struct in6_addr; + +/** + Lookup a PTR record for a given IP address. + + @param in an IPv4 address + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_reverse_ipv6() + */ int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); + + +/** + Lookup a PTR record for a given IPv6 address. + + @param in an IPv6 address + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_reverse_ipv6() + */ int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); + + +/** + Set the value of a configuration option. + + The currently available configuration options are: + + ndots, timeout, max-timeouts, max-inflight, and attempts + + @param option the name of the configuration option to be modified + @param val the value to be set + @param flags either 0 | DNS_OPTION_SEARCH | DNS_OPTION_MISC + @return 0 if successful, or -1 if an error occurred + */ int evdns_set_option(const char *option, const char *val, int flags); -int evdns_resolv_conf_parse(int flags, const char *); + + +/** + Parse a resolv.conf file. + + The 'flags' parameter determines what information is parsed from the + resolv.conf file. See the man page for resolv.conf for the format of this + file. + + The following directives are not parsed from the file: sortlist, rotate, + no-check-names, inet6, debug. + + If this function encounters an error, the possible return values are: 1 = + failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of + memory, 5 = short read from file, 6 = no nameservers listed in the file + + @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC| + DNS_OPTIONS_ALL + @param filename the path to the resolv.conf file + @return 0 if successful, or various positive error codes if an error + occurred (see above) + @see resolv.conf(3), evdns_config_windows_nameservers() + */ +int evdns_resolv_conf_parse(int flags, const char *const filename); + + +/** + Obtain nameserver information using the Windows API. + + Attempt to configure a set of nameservers based on platform settings on + a win32 host. Preferentially tries to use GetNetworkParams; if that fails, + looks in the registry. + + @return 0 if successful, or -1 if an error occurred + @see evdns_resolv_conf_parse() + */ #ifdef MS_WINDOWS int evdns_config_windows_nameservers(void); #endif + + +/** + Clear the list of search domains. + */ void evdns_search_clear(void); + + +/** + Add a domain to the list of search domains + + @param domain the domain to be added to the search list + */ void evdns_search_add(const char *domain); + + +/** + Set the 'ndots' parameter for searches. + + Sets the number of dots which, when found in a name, causes + the first query to be without any search domain. + + @param ndots the new ndots parameter + */ void evdns_search_ndots_set(const int ndots); +/** + A callback that is invoked when a log message is generated + + @param is_warning indicates if the log message is a 'warning' + @param msg the content of the log message + */ typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg); + + +/** + Set the callback function to handle log messages. + + @param fn the callback to be invoked when a log message is generated + */ void evdns_set_log_fn(evdns_debug_log_fn_type fn); -#define DNS_NO_SEARCH 1 +/** + Set a callback that will be invoked to generate transaction IDs. By + default, we pick transaction IDs based on the current clock time. -#ifdef __cplusplus -} -#endif + @param fn the new callback, or NULL to use the default. + */ +void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void)); + +#define DNS_NO_SEARCH 1 /* * Structures and functions used to implement a DNS server. @@ -328,7 +477,15 @@ }; struct evdns_server_question { int type; +#ifdef __cplusplus + int dns_question_class; +#else + /* You should refer to this field as "dns_question_class". The + * name "class" works in C for backward compatibility, and will be + * removed in a future version. (1.5 or later). */ int class; +#define dns_question_class class +#endif char name[1]; }; typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *); @@ -353,7 +510,7 @@ struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data); void evdns_close_server_port(struct evdns_server_port *port); -int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data); +int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data); int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl); int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl); int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl); @@ -364,4 +521,8 @@ struct sockaddr; int evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len); +#ifdef __cplusplus +} +#endif + #endif /* !EVENTDNS_H */ Index: contrib/libevent/event-config.h =================================================================== RCS file: contrib/libevent/event-config.h diff -N contrib/libevent/event-config.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ contrib/libevent/event-config.h 25 Jun 2008 21:40:51 -0000 @@ -0,0 +1,262 @@ +/* event-config.h + * Generated by autoconf; post-processed by libevent. + * Do not edit this file. + * Do not rely on macros in this file existing in later versions. + */ +#ifndef _EVENT_CONFIG_H_ +#define _EVENT_CONFIG_H_ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define if clock_gettime is available in libc */ +/* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */ + +/* Define is no secure id variant is available */ +#define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1 + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef _EVENT_HAVE_CLOCK_GETTIME */ + +/* Define if /dev/poll is available */ +/* #undef _EVENT_HAVE_DEVPOLL */ + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_DLFCN_H 1 + +/* Define if your system supports the epoll system calls */ +/* #undef _EVENT_HAVE_EPOLL */ + +/* Define to 1 if you have the `epoll_ctl' function. */ +/* #undef _EVENT_HAVE_EPOLL_CTL */ + +/* Define if your system supports event ports */ +/* #undef _EVENT_HAVE_EVENT_PORTS */ + +/* Define to 1 if you have the `fcntl' function. */ +#define _EVENT_HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getaddrinfo' function. */ +#define _EVENT_HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getnameinfo' function. */ +#define _EVENT_HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define _EVENT_HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `inet_ntop' function. */ +#define _EVENT_HAVE_INET_NTOP 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `kqueue' function. */ +#define _EVENT_HAVE_KQUEUE 1 + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef _EVENT_HAVE_LIBNSL */ + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#define _EVENT_HAVE_LIBRESOLV 1 + +/* Define to 1 if you have the `rt' library (-lrt). */ +/* #undef _EVENT_HAVE_LIBRT */ + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef _EVENT_HAVE_LIBSOCKET */ + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef _EVENT_HAVE_NETINET_IN6_H */ + +/* Define to 1 if you have the `poll' function. */ +#define _EVENT_HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_POLL_H 1 + +/* Define to 1 if you have the `port_create' function. */ +/* #undef _EVENT_HAVE_PORT_CREATE */ + +/* Define to 1 if you have the header file. */ +/* #undef _EVENT_HAVE_PORT_H */ + +/* Define to 1 if you have the `select' function. */ +#define _EVENT_HAVE_SELECT 1 + +/* Define if F_SETFD is defined in */ +#define _EVENT_HAVE_SETFD 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define _EVENT_HAVE_SIGACTION 1 + +/* Define to 1 if you have the `signal' function. */ +#define _EVENT_HAVE_SIGNAL 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#define _EVENT_HAVE_STRLCPY 1 + +/* Define to 1 if you have the `strsep' function. */ +#define _EVENT_HAVE_STRSEP 1 + +/* Define to 1 if you have the `strtok_r' function. */ +#define _EVENT_HAVE_STRTOK_R 1 + +/* Define to 1 if you have the `strtoll' function. */ +#define _EVENT_HAVE_STRTOLL 1 + +/* Define to 1 if the system has the type `struct in6_addr'. */ +#define _EVENT_HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if you have the header file. */ +/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef _EVENT_HAVE_SYS_EPOLL_H */ + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_EVENT_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_QUEUE_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_TYPES_H 1 + +/* Define if TAILQ_FOREACH is defined in */ +#define _EVENT_HAVE_TAILQFOREACH 1 + +/* Define if timeradd is defined in */ +#define _EVENT_HAVE_TIMERADD 1 + +/* Define if timerclear is defined in */ +#define _EVENT_HAVE_TIMERCLEAR 1 + +/* Define if timercmp is defined in */ +#define _EVENT_HAVE_TIMERCMP 1 + +/* Define if timerisset is defined in */ +#define _EVENT_HAVE_TIMERISSET 1 + +/* Define to 1 if the system has the type `uint16_t'. */ +#define _EVENT_HAVE_UINT16_T 1 + +/* Define to 1 if the system has the type `uint32_t'. */ +#define _EVENT_HAVE_UINT32_T 1 + +/* Define to 1 if the system has the type `uint64_t'. */ +#define _EVENT_HAVE_UINT64_T 1 + +/* Define to 1 if the system has the type `uint8_t'. */ +#define _EVENT_HAVE_UINT8_T 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `vasprintf' function. */ +#define _EVENT_HAVE_VASPRINTF 1 + +/* Define if kqueue works correctly with pipes */ +#define _EVENT_HAVE_WORKING_KQUEUE 1 + +/* Name of package */ +#define _EVENT_PACKAGE "libevent" + +/* Define to the address where bug reports for this package should be sent. */ +#define _EVENT_PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define _EVENT_PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define _EVENT_PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define _EVENT_PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define _EVENT_PACKAGE_VERSION "" + +/* The size of `int', as computed by sizeof. */ +#define _EVENT_SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define _EVENT_SIZEOF_LONG 4 + +/* The size of `long long', as computed by sizeof. */ +#define _EVENT_SIZEOF_LONG_LONG 8 + +/* The size of `short', as computed by sizeof. */ +#define _EVENT_SIZEOF_SHORT 2 + +/* Define to 1 if you have the ANSI C header files. */ +#define _EVENT_STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define _EVENT_TIME_WITH_SYS_TIME 1 + +/* Version number of package */ +#define _EVENT_VERSION "1.4.5-stable" + +/* Define to appropriate substitue if compiler doesnt have __func__ */ +/* #undef _EVENT___func__ */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef _EVENT_const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef _EVENT___cplusplus +/* #undef _EVENT_inline */ +#endif + +/* Define to `int' if does not define. */ +/* #undef _EVENT_pid_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef _EVENT_size_t */ + +/* Define to unsigned int if you dont have it */ +/* #undef _EVENT_socklen_t */ +#endif Index: contrib/libevent/event-internal.h =================================================================== RCS file: /home/dcvs/src/contrib/libevent/event-internal.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 event-internal.h --- contrib/libevent/event-internal.h 30 Jan 2008 12:35:18 -0000 1.1.1.1 +++ contrib/libevent/event-internal.h 4 May 2008 00:48:34 -0000 @@ -31,8 +31,21 @@ extern "C" { #endif +#include "config.h" +#include "min_heap.h" #include "evsignal.h" +struct eventop { + const char *name; + void *(*init)(struct event_base *); + int (*add)(void *, struct event *); + int (*del)(void *, struct event *); + int (*dispatch)(struct event_base *, void *, struct timeval *); + void (*dealloc)(struct event_base *, void *); + /* set if we need to reinitialize the event base */ + int need_reinit; +}; + struct event_base { const struct eventop *evsel; void *evbase; @@ -40,6 +53,7 @@ int event_count_active; /* counts number of active events */ int event_gotterm; /* Set to terminate loop */ + int event_break; /* Set to terminate loop immediately */ /* active event management */ struct event_list **activequeues; @@ -51,9 +65,32 @@ struct event_list eventqueue; struct timeval event_tv; - RB_HEAD(event_tree, event) timetree; + struct min_heap timeheap; + + struct timeval tv_cache; }; +/* Internal use only: Functions that might be missing from */ +#ifndef HAVE_TAILQFOREACH +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) +#endif /* TAILQ_FOREACH */ + +int _evsignal_set_handler(struct event_base *base, int evsignal, + void (*fn)(int)); +int _evsignal_restore_handler(struct event_base *base, int evsignal); + #ifdef __cplusplus } #endif Index: contrib/libevent/event.3 =================================================================== RCS file: /home/dcvs/src/contrib/libevent/event.3,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 event.3 --- contrib/libevent/event.3 30 Jan 2008 12:35:18 -0000 1.1.1.1 +++ contrib/libevent/event.3 14 Dec 2007 19:08:14 -0000 @@ -34,10 +34,12 @@ .Nm event_dispatch , .Nm event_loop , .Nm event_loopexit , +.Nm event_loopbreak , .Nm event_set , .Nm event_base_dispatch , .Nm event_base_loop , .Nm event_base_loopexit , +.Nm event_base_loopbreak , .Nm event_base_set , .Nm event_base_free , .Nm event_add , @@ -78,7 +80,8 @@ .Nm evbuffer_read , .Nm evbuffer_find , .Nm evbuffer_readline , -.Nm evhttp_start , +.Nm evhttp_new , +.Nm evhttp_bind_socket , .Nm evhttp_free .Nd execute a function when a specific event occurs .Sh SYNOPSIS @@ -92,6 +95,8 @@ .Fn "event_loop" "int flags" .Ft int .Fn "event_loopexit" "struct timeval *tv" +.Ft int +.Fn "event_loopbreak" "void" .Ft void .Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" .Ft int @@ -101,6 +106,8 @@ .Ft int .Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv" .Ft int +.Fn "event_base_loopbreak" "struct event_base *base" +.Ft int .Fn "event_base_set" "struct event_base *base" "struct event *" .Ft void .Fn "event_base_free" "struct event_base *base" @@ -181,9 +188,11 @@ .Ft "char *" .Fn "evbuffer_readline" "struct evbuffer *buf" .Ft "struct evhttp *" -.Fn "evhttp_start" "const char *address" "u_short port" +.Fn "evhttp_new" "struct event_base *base" +.Ft int +.Fn "evhttp_bind_socket" "struct evhttp *http" "const char *address" "u_short port" .Ft "void" -.Fn "evhttp_free" "struct evhttp* http" +.Fn "evhttp_free" "struct evhttp *http" .Ft int .Fa (*event_sigcb)(void) ; .Ft volatile sig_atomic_t @@ -205,51 +214,6 @@ This function only returns on error, and should replace the event core of the application program. .Pp -In order to avoid races in signal handlers, the -.Nm event -API provides two variables: -.Va event_sigcb -and -.Va event_gotsig . -A signal handler -sets -.Va event_gotsig -to indicate that a signal has been received. -The application sets -.Va event_sigcb -to a callback function. -After the signal handler sets -.Va event_gotsig , -.Nm event_dispatch -will execute the callback function to process received signals. -The callback returns 1 when no events are registered any more. -It can return \-1 to indicate an error to the -.Nm event -library, causing -.Fn event_dispatch -to terminate with -.Va errno -set to -.Er EINTR . -.Pp -The -.Nm event_loop -function provides an interface for single pass execution of pending -events. -The flags -.Va EVLOOP_ONCE -and -.Va EVLOOP_NONBLOCK -are recognized. -The -.Nm event_loopexit -function allows the loop to be terminated after some amount of time -has passed. -The parameter indicates the time after which the loop should terminate. -.Pp -It is the responsibility of the caller to provide these functions with -pre-allocated event structures. -.Pp The function .Fn event_set prepares the event structure @@ -288,6 +252,11 @@ .Va EV_READ , or .Va EV_WRITE . +Additionally, an event which has registered interest in more than one of the +preceeding events, via bitwise-OR to +.Fn event_set , +can provide its callback function with a bitwise-OR of more than one triggered +event. The additional flag .Va EV_PERSIST makes an @@ -353,6 +322,59 @@ If the event has already executed or has never been added the call will have no effect. .Pp +The functions +.Fn evtimer_set , +.Fn evtimer_add , +.Fn evtimer_del , +.Fn evtimer_initialized , +and +.Fn evtimer_pending +are abbreviations for common situations where only a timeout is required. +The file descriptor passed will be \-1, and the event type will be +.Va EV_TIMEOUT . +.Pp +The functions +.Fn signal_set , +.Fn signal_add , +.Fn signal_del , +.Fn signal_initialized , +and +.Fn signal_pending +are abbreviations. +The event type will be a persistent +.Va EV_SIGNAL . +That means +.Fn signal_set +adds +.Va EV_PERSIST . +.Pp +In order to avoid races in signal handlers, the +.Nm event +API provides two variables: +.Va event_sigcb +and +.Va event_gotsig . +A signal handler +sets +.Va event_gotsig +to indicate that a signal has been received. +The application sets +.Va event_sigcb +to a callback function. +After the signal handler sets +.Va event_gotsig , +.Nm event_dispatch +will execute the callback function to process received signals. +The callback returns 1 when no events are registered any more. +It can return \-1 to indicate an error to the +.Nm event +library, causing +.Fn event_dispatch +to terminate with +.Va errno +set to +.Er EINTR . +.Pp The function .Fn event_once is similar to @@ -385,45 +407,38 @@ .Fn event_initialized macro can be used to check if an event has been initialized. .Pp -The functions -.Fn evtimer_set , -.Fn evtimer_add , -.Fn evtimer_del , -.Fn evtimer_initialized , +The +.Nm event_loop +function provides an interface for single pass execution of pending +events. +The flags +.Va EVLOOP_ONCE and -.Fn evtimer_pending -are abbreviations for common situations where only a timeout is required. -The file descriptor passed will be \-1, and the event type will be -.Va EV_TIMEOUT . +.Va EVLOOP_NONBLOCK +are recognized. +The +.Nm event_loopexit +function exits from the event loop. The next +.Fn event_loop +iteration after the +given timer expires will complete normally (handling all queued events) then +exit without blocking for events again. Subsequent invocations of +.Fn event_loop +will proceed normally. +The +.Nm event_loopbreak +function exits from the event loop immediately. +.Fn event_loop +will abort after the next event is completed; +.Fn event_loopbreak +is typically invoked from this event's callback. This behavior is analogous +to the "break;" statement. Subsequent invocations of +.Fn event_loop +will proceed normally. .Pp -The functions -.Fn signal_set , -.Fn signal_add , -.Fn signal_del , -.Fn signal_initialized , -and -.Fn signal_pending -are abbreviations. -The event type will be a persistent -.Va EV_SIGNAL . -That means -.Fn signal_set -adds -.Va EV_PERSIST . +It is the responsibility of the caller to provide these functions with +pre-allocated event structures. .Pp -It is possible to disable support for -.Va epoll , kqueue , devpoll , poll -or -.Va select -by setting the environment variable -.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL -or -.Va EVENT_NOSELECT , -respectively. -By setting the environment variable -.Va EVENT_SHOW_METHOD , -.Nm libevent -displays the kernel notification method that it uses. .Sh EVENT PRIORITIES By default .Nm libevent @@ -539,7 +554,10 @@ provides a very thin HTTP layer that can be used both to host an HTTP server and also to make HTTP requests. An HTTP server can be created by calling -.Fn evhttp_start . +.Fn evhttp_new . +It can be bound to any port and address with the +.Fn evhttp_bind_socket +function. When the HTTP server is no longer used, it can be freed via .Fn evhttp_free . .Pp @@ -556,6 +574,20 @@ check .Va event.h for the public interfaces. +.Sh ADDITIONAL NOTES +It is possible to disable support for +.Va epoll , kqueue , devpoll , poll +or +.Va select +by setting the environment variable +.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL +or +.Va EVENT_NOSELECT , +respectively. +By setting the environment variable +.Va EVENT_SHOW_METHOD , +.Nm libevent +displays the kernel notification method that it uses. .Sh RETURN VALUES Upon successful completion .Fn event_add Index: contrib/libevent/event.c =================================================================== RCS file: /home/dcvs/src/contrib/libevent/event.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 event.c --- contrib/libevent/event.c 30 Jan 2008 12:35:18 -0000 1.1.1.1 +++ contrib/libevent/event.c 29 May 2008 06:43:46 -0000 @@ -32,10 +32,8 @@ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN -#include "misc.h" #endif #include -#include #ifdef HAVE_SYS_TIME_H #include #else @@ -55,6 +53,7 @@ #include "event.h" #include "event-internal.h" +#include "evutil.h" #include "log.h" #ifdef HAVE_EVENT_PORTS @@ -66,9 +65,6 @@ #ifdef HAVE_POLL extern const struct eventop pollops; #endif -#ifdef HAVE_RTSIG -extern const struct eventop rtsigops; -#endif #ifdef HAVE_EPOLL extern const struct eventop epollops; #endif @@ -96,9 +92,6 @@ #ifdef HAVE_DEVPOLL &devpollops, #endif -#ifdef HAVE_RTSIG - &rtsigops, -#endif #ifdef HAVE_POLL &pollops, #endif @@ -131,20 +124,6 @@ static void timeout_process(struct event_base *); static void timeout_correct(struct event_base *, struct timeval *); -static int -compare(struct event *a, struct event *b) -{ - if (timercmp(&a->ev_timeout, &b->ev_timeout, <)) - return (-1); - else if (timercmp(&a->ev_timeout, &b->ev_timeout, >)) - return (1); - if (a < b) - return (-1); - else if (a > b) - return (1); - return (0); -} - static void detect_monotonic(void) { @@ -157,12 +136,17 @@ } static int -gettime(struct timeval *tp) +gettime(struct event_base *base, struct timeval *tp) { -#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) - struct timespec ts; + if (base->tv_cache.tv_sec) { + *tp = base->tv_cache; + return (0); + } +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) if (use_monotonic) { + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) return (-1); @@ -172,30 +156,36 @@ } #endif - return (gettimeofday(tp, NULL)); + return (evutil_gettimeofday(tp, NULL)); } -RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare); +struct event_base * +event_init(void) +{ + struct event_base *base = event_base_new(); -RB_GENERATE(event_tree, event, ev_timeout_node, compare); + if (base != NULL) + current_base = base; + return (base); +} -void * -event_init(void) +struct event_base * +event_base_new(void) { int i; struct event_base *base; if ((base = calloc(1, sizeof(struct event_base))) == NULL) - event_err(1, "%s: calloc"); + event_err(1, "%s: calloc", __func__); event_sigcb = NULL; event_gotsig = 0; detect_monotonic(); - gettime(&base->event_tv); + gettime(base, &base->event_tv); - RB_INIT(&base->timetree); + min_heap_ctor(&base->timeheap); TAILQ_INIT(&base->eventqueue); TAILQ_INIT(&base->sig.signalqueue); base->sig.ev_signal_pair[0] = -1; @@ -218,27 +208,48 @@ /* allocate a single active event queue */ event_base_priority_init(base, 1); - current_base = base; return (base); } void event_base_free(struct event_base *base) { - int i; + int i, n_deleted=0; + struct event *ev; if (base == NULL && current_base) base = current_base; - if (base == current_base) + if (base == current_base) current_base = NULL; + /* XXX(niels) - check for internal events first */ assert(base); + /* Delete all non-internal events. */ + for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) { + struct event *next = TAILQ_NEXT(ev, ev_next); + if (!(ev->ev_flags & EVLIST_INTERNAL)) { + event_del(ev); + ++n_deleted; + } + ev = next; + } + while ((ev = min_heap_top(&base->timeheap)) != NULL) { + event_del(ev); + ++n_deleted; + } + + if (n_deleted) + event_debug(("%s: %d events were still set in base", + __func__, n_deleted)); + if (base->evsel->dealloc != NULL) base->evsel->dealloc(base, base->evbase); - for (i=0; i < base->nactivequeues; ++i) + + for (i = 0; i < base->nactivequeues; ++i) assert(TAILQ_EMPTY(base->activequeues[i])); - assert(RB_EMPTY(&base->timetree)); + assert(min_heap_empty(&base->timeheap)); + min_heap_dtor(&base->timeheap); for (i = 0; i < base->nactivequeues; ++i) free(base->activequeues[i]); @@ -249,6 +260,34 @@ free(base); } +/* reinitialized the event base after a fork */ +int +event_reinit(struct event_base *base) +{ + const struct eventop *evsel = base->evsel; + void *evbase = base->evbase; + int res = 0; + struct event *ev; + + /* check if this event mechanism requires reinit */ + if (!evsel->need_reinit) + return (0); + + if (base->evsel->dealloc != NULL) + base->evsel->dealloc(base, base->evbase); + evbase = base->evbase = evsel->init(base); + if (base->evbase == NULL) + event_errx(1, "%s: could not reinitialize event mechanism", + __func__); + + TAILQ_FOREACH(ev, &base->eventqueue, ev_next) { + if (evsel->add(evbase, ev) == -1) + res = -1; + } + + return (res); +} + int event_priority_init(int npriorities) { @@ -307,9 +346,6 @@ int i; short ncalls; - if (!base->event_count_active) - return; - for (i = 0; i < base->nactivequeues; ++i) { if (TAILQ_FIRST(base->activequeues[i]) != NULL) { activeq = base->activequeues[i]; @@ -320,7 +356,10 @@ assert(activeq != NULL); for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) { - event_queue_remove(base, ev, EVLIST_ACTIVE); + if (ev->ev_events & EV_PERSIST) + event_queue_remove(base, ev, EVLIST_ACTIVE); + else + event_del(ev); /* Allows deletes to work */ ncalls = ev->ev_ncalls; @@ -329,7 +368,7 @@ ncalls--; ev->ev_ncalls = ncalls; (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg); - if (event_gotsig) + if (event_gotsig || base->event_break) return; } } @@ -351,6 +390,13 @@ return (event_base_loop(event_base, 0)); } +const char * +event_base_get_method(struct event_base *base) +{ + assert(base); + return (base->evsel->name); +} + static void event_loopexit_cb(int fd, short what, void *arg) { @@ -360,20 +406,39 @@ /* not thread safe */ int -event_loopexit(struct timeval *tv) +event_loopexit(const struct timeval *tv) { return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, current_base, tv)); } int -event_base_loopexit(struct event_base *event_base, struct timeval *tv) +event_base_loopexit(struct event_base *event_base, const struct timeval *tv) { return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb, event_base, tv)); } /* not thread safe */ +int +event_loopbreak(void) +{ + return (event_base_loopbreak(current_base)); +} + +int +event_base_loopbreak(struct event_base *event_base) +{ + if (event_base == NULL) + return (-1); + + event_base->event_break = 1; + return (0); +} + + + +/* not thread safe */ int event_loop(int flags) @@ -390,22 +455,21 @@ struct timeval *tv_p; int res, done; -#ifndef WIN32 if(!TAILQ_EMPTY(&base->sig.signalqueue)) evsignal_base = base; -#endif done = 0; while (!done) { - /* Calculate the initial events that we are waiting for */ - if (evsel->recalc(base, evbase, 0) == -1) - return (-1); - /* Terminate the loop if we have been asked to */ if (base->event_gotterm) { base->event_gotterm = 0; break; } + if (base->event_break) { + base->event_break = 0; + break; + } + /* You cannot use this interface for multi-threaded apps */ while (event_gotsig) { event_gotsig = 0; @@ -428,7 +492,7 @@ * if we have active events, we just poll new events * without waiting. */ - timerclear(&tv); + evutil_timerclear(&tv); } /* If we have no events, we just exit */ @@ -437,11 +501,17 @@ return (1); } - res = evsel->dispatch(base, evbase, tv_p); + /* update last old time */ + gettime(base, &base->event_tv); + + /* clear time cache */ + base->tv_cache.tv_sec = 0; + res = evsel->dispatch(base, evbase, tv_p); if (res == -1) return (-1); + gettime(base, &base->tv_cache); timeout_process(base); @@ -480,7 +550,7 @@ /* not threadsafe, event scheduled once. */ int event_once(int fd, short events, - void (*callback)(int, short, void *), void *arg, struct timeval *tv) + void (*callback)(int, short, void *), void *arg, const struct timeval *tv) { return event_base_once(current_base, fd, events, callback, arg, tv); } @@ -488,7 +558,7 @@ /* Schedules an event once */ int event_base_once(struct event_base *base, int fd, short events, - void (*callback)(int, short, void *), void *arg, struct timeval *tv) + void (*callback)(int, short, void *), void *arg, const struct timeval *tv) { struct event_once *eonce; struct timeval etv; @@ -506,7 +576,7 @@ if (events == EV_TIMEOUT) { if (tv == NULL) { - timerclear(&etv); + evutil_timerclear(&etv); tv = &etv; } @@ -548,6 +618,8 @@ ev->ev_ncalls = 0; ev->ev_pncalls = NULL; + min_heap_elem_init(ev); + /* by default, we put new events into the middle priority */ if(current_base) ev->ev_pri = current_base->nactivequeues/2; @@ -607,18 +679,18 @@ /* See if there is a timeout that we should report */ if (tv != NULL && (flags & event & EV_TIMEOUT)) { - gettime(&now); - timersub(&ev->ev_timeout, &now, &res); + gettime(ev->ev_base, &now); + evutil_timersub(&ev->ev_timeout, &now, &res); /* correctly remap to real time */ - gettimeofday(&now, NULL); - timeradd(&now, &res, tv); + evutil_gettimeofday(&now, NULL); + evutil_timeradd(&now, &res, tv); } return (flags & event); } int -event_add(struct event *ev, struct timeval *tv) +event_add(struct event *ev, const struct timeval *tv) { struct event_base *base = ev->ev_base; const struct eventop *evsel = base->evsel; @@ -639,6 +711,9 @@ if (ev->ev_flags & EVLIST_TIMEOUT) event_queue_remove(base, ev, EVLIST_TIMEOUT); + else if (min_heap_reserve(&base->timeheap, + 1 + min_heap_size(&base->timeheap)) == -1) + return (-1); /* ENOMEM == errno */ /* Check if it is active due to a timeout. Rescheduling * this timeout before the callback can be executed @@ -656,8 +731,8 @@ event_queue_remove(base, ev, EVLIST_ACTIVE); } - gettime(&now); - timeradd(&now, tv, &ev->ev_timeout); + gettime(base, &now); + evutil_timeradd(&now, tv, &ev->ev_timeout); event_debug(( "event_add: timeout in %d seconds, call %p", @@ -668,14 +743,18 @@ if ((ev->ev_events & (EV_READ|EV_WRITE)) && !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) { - event_queue_insert(base, ev, EVLIST_INSERTED); + int res = evsel->add(evbase, ev); + if (res != -1) + event_queue_insert(base, ev, EVLIST_INSERTED); - return (evsel->add(evbase, ev)); + return (res); } else if ((ev->ev_events & EV_SIGNAL) && !(ev->ev_flags & EVLIST_SIGNAL)) { - event_queue_insert(base, ev, EVLIST_SIGNAL); + int res = evsel->add(evbase, ev); + if (res != -1) + event_queue_insert(base, ev, EVLIST_SIGNAL); - return (evsel->add(evbase, ev)); + return (res); } return (0); @@ -746,21 +825,21 @@ struct event *ev; struct timeval *tv = *tv_p; - if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) { + if ((ev = min_heap_top(&base->timeheap)) == NULL) { /* if no time-based events are active wait for I/O */ *tv_p = NULL; return (0); } - if (gettime(&now) == -1) + if (gettime(base, &now) == -1) return (-1); - if (timercmp(&ev->ev_timeout, &now, <=)) { - timerclear(tv); + if (evutil_timercmp(&ev->ev_timeout, &now, <=)) { + evutil_timerclear(tv); return (0); } - timersub(&ev->ev_timeout, &now, tv); + evutil_timersub(&ev->ev_timeout, &now, tv); assert(tv->tv_sec >= 0); assert(tv->tv_usec >= 0); @@ -778,45 +857,50 @@ static void timeout_correct(struct event_base *base, struct timeval *tv) { - struct event *ev; + struct event **pev; + unsigned int size; struct timeval off; if (use_monotonic) return; /* Check if time is running backwards */ - gettime(tv); - if (timercmp(tv, &base->event_tv, >=)) { + gettime(base, tv); + if (evutil_timercmp(tv, &base->event_tv, >=)) { base->event_tv = *tv; return; } event_debug(("%s: time is running backwards, corrected", __func__)); - timersub(&base->event_tv, tv, &off); + evutil_timersub(&base->event_tv, tv, &off); /* * We can modify the key element of the node without destroying * the key, beause we apply it to all in the right order. */ - RB_FOREACH(ev, event_tree, &base->timetree) - timersub(&ev->ev_timeout, &off, &ev->ev_timeout); + pev = base->timeheap.p; + size = base->timeheap.n; + for (; size-- > 0; ++pev) { + struct timeval *ev_tv = &(**pev).ev_timeout; + evutil_timersub(ev_tv, &off, ev_tv); + } } void timeout_process(struct event_base *base) { struct timeval now; - struct event *ev, *next; + struct event *ev; - gettime(&now); + if (min_heap_empty(&base->timeheap)) + return; - for (ev = RB_MIN(event_tree, &base->timetree); ev; ev = next) { - if (timercmp(&ev->ev_timeout, &now, >)) - break; - next = RB_NEXT(event_tree, &base->timetree, ev); + gettime(base, &now); - event_queue_remove(base, ev, EVLIST_TIMEOUT); + while ((ev = min_heap_top(&base->timeheap))) { + if (evutil_timercmp(&ev->ev_timeout, &now, >)) + break; /* delete this event from the I/O queues */ event_del(ev); @@ -830,34 +914,28 @@ void event_queue_remove(struct event_base *base, struct event *ev, int queue) { - int docount = 1; - if (!(ev->ev_flags & queue)) event_errx(1, "%s: %p(fd %d) not on queue %x", __func__, ev, ev->ev_fd, queue); - if (ev->ev_flags & EVLIST_INTERNAL) - docount = 0; - - if (docount) + if (~ev->ev_flags & EVLIST_INTERNAL) base->event_count--; ev->ev_flags &= ~queue; switch (queue) { + case EVLIST_INSERTED: + TAILQ_REMOVE(&base->eventqueue, ev, ev_next); + break; case EVLIST_ACTIVE: - if (docount) - base->event_count_active--; + base->event_count_active--; TAILQ_REMOVE(base->activequeues[ev->ev_pri], ev, ev_active_next); break; - case EVLIST_SIGNAL: - TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next); - break; case EVLIST_TIMEOUT: - RB_REMOVE(event_tree, &base->timetree, ev); + min_heap_erase(&base->timeheap, ev); break; - case EVLIST_INSERTED: - TAILQ_REMOVE(&base->eventqueue, ev, ev_next); + case EVLIST_SIGNAL: + TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next); break; default: event_errx(1, "%s: unknown queue %x", __func__, queue); @@ -867,8 +945,6 @@ void event_queue_insert(struct event_base *base, struct event *ev, int queue) { - int docount = 1; - if (ev->ev_flags & queue) { /* Double insertion is possible for active events */ if (queue & EVLIST_ACTIVE) @@ -878,30 +954,25 @@ ev, ev->ev_fd, queue); } - if (ev->ev_flags & EVLIST_INTERNAL) - docount = 0; - - if (docount) + if (~ev->ev_flags & EVLIST_INTERNAL) base->event_count++; ev->ev_flags |= queue; switch (queue) { + case EVLIST_INSERTED: + TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); + break; case EVLIST_ACTIVE: - if (docount) - base->event_count_active++; + base->event_count_active++; TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], ev,ev_active_next); break; - case EVLIST_SIGNAL: - TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next); - break; case EVLIST_TIMEOUT: { - struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev); - assert(tmp == NULL); + min_heap_push(&base->timeheap, ev); break; } - case EVLIST_INSERTED: - TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); + case EVLIST_SIGNAL: + TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next); break; default: event_errx(1, "%s: unknown queue %x", __func__, queue); Index: contrib/libevent/event.h =================================================================== RCS file: /home/dcvs/src/contrib/libevent/event.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 event.h --- contrib/libevent/event.h 30 Jan 2008 12:35:18 -0000 1.1.1.1 +++ contrib/libevent/event.h 29 May 2008 06:43:46 -0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 Niels Provos + * Copyright (c) 2000-2007 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,14 +27,153 @@ #ifndef _EVENT_H_ #define _EVENT_H_ +/** @mainpage + + @section intro Introduction + + libevent is an event notification library for developing scalable network + servers. The libevent API provides a mechanism to execute a callback + function when a specific event occurs on a file descriptor or after a + timeout has been reached. Furthermore, libevent also support callbacks due + to signals or regular timeouts. + + libevent is meant to replace the event loop found in event driven network + servers. An application just needs to call event_dispatch() and then add or + remove events dynamically without having to change the event loop. + + Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and + epoll(4). It also has experimental support for real-time signals. The + internal event mechanism is completely independent of the exposed event API, + and a simple update of libevent can provide new functionality without having + to redesign the applications. As a result, Libevent allows for portable + application development and provides the most scalable event notification + mechanism available on an operating system. Libevent can also be used for + multi-threaded aplications; see Steven Grimm's explanation. Libevent should + compile on Linux, *BSD, Mac OS X, Solaris and Windows. + + @section usage Standard usage + + Every program that uses libevent must include the header, and pass + the -levent flag to the linker. Before using any of the functions in the + library, you must call event_init() or event_base_new() to perform one-time + initialization of the libevent library. + + @section event Event notification + + For each file descriptor that you wish to monitor, you must declare an event + structure and call event_set() to initialize the members of the structure. + To enable notification, you add the structure to the list of monitored + events by calling event_add(). The event structure must remain allocated as + long as it is active, so it should be allocated on the heap. Finally, you + call event_dispatch() to loop and dispatch events. + + @section bufferevent I/O Buffers + + libevent provides an abstraction on top of the regular event callbacks. This + abstraction is called a buffered event. A buffered event provides input and + output buffers that get filled and drained automatically. The user of a + buffered event no longer deals directly with the I/O, but instead is reading + from input and writing to output buffers. + + Once initialized via bufferevent_new(), the bufferevent structure can be + used repeatedly with bufferevent_enable() and bufferevent_disable(). + Instead of reading and writing directly to a socket, you would call + bufferevent_read() and bufferevent_write(). + + When read enabled the bufferevent will try to read from the file descriptor + and call the read callback. The write callback is executed whenever the + output buffer is drained below the write low watermark, which is 0 by + default. + + @section timers Timers + + libevent can also be used to create timers that invoke a callback after a + certain amount of time has expired. The evtimer_set() function prepares an + event struct to be used as a timer. To activate the timer, call + evtimer_add(). Timers can be deactivated by calling evtimer_del(). + + @section timeouts Timeouts + + In addition to simple timers, libevent can assign timeout events to file + descriptors that are triggered whenever a certain amount of time has passed + with no activity on a file descriptor. The timeout_set() function + initializes an event struct for use as a timeout. Once initialized, the + event must be activated by using timeout_add(). To cancel the timeout, call + timeout_del(). + + @section evdns Asynchronous DNS resolution + + libevent provides an asynchronous DNS resolver that should be used instead + of the standard DNS resolver functions. These functions can be imported by + including the header in your program. Before using any of the + resolver functions, you must call evdns_init() to initialize the library. To + convert a hostname to an IP address, you call the evdns_resolve_ipv4() + function. To perform a reverse lookup, you would call the + evdns_resolve_reverse() function. All of these functions use callbacks to + avoid blocking while the lookup is performed. + + @section evhttp Event-driven HTTP servers + + libevent provides a very simple event-driven HTTP server that can be + embedded in your program and used to service HTTP requests. + + To use this capability, you need to include the header in your + program. You create the server by calling evhttp_new(). Add addresses and + ports to listen on with evhttp_bind_socket(). You then register one or more + callbacks to handle incoming requests. Each URI can be assigned a callback + via the evhttp_set_cb() function. A generic callback function can also be + registered via evhttp_set_gencb(); this callback will be invoked if no other + callbacks have been registered for a given URI. + + @section evrpc A framework for RPC servers and clients + + libevents provides a framework for creating RPC servers and clients. It + takes care of marshaling and unmarshaling all data structures. + + @section api API Reference + + To browse the complete documentation of the libevent API, click on any of + the following links. + + event.h + The primary libevent header + + evdns.h + Asynchronous DNS resolution + + evhttp.h + An embedded libevent-based HTTP server + + evrpc.h + A framework for creating RPC servers and clients + + */ + +/** @file event.h + + A library for writing event-driven network servers + + */ + #ifdef __cplusplus extern "C" { #endif +#include +#ifdef _EVENT_HAVE_SYS_TYPES_H +#include +#endif +#ifdef _EVENT_HAVE_SYS_TIME_H #include +#endif +#ifdef _EVENT_HAVE_STDINT_H #include +#endif #include +/* For int types. */ +#include + #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include @@ -68,25 +207,16 @@ struct type **tqe_prev; /* address of previous next element */ \ } #endif /* !TAILQ_ENTRY */ -#ifndef RB_ENTRY -#define _EVENT_DEFINED_RBENTRY -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} -#endif /* !RB_ENTRY */ struct event_base; struct event { TAILQ_ENTRY (event) ev_next; TAILQ_ENTRY (event) ev_active_next; TAILQ_ENTRY (event) ev_signal_next; - RB_ENTRY (event) ev_timeout_node; + unsigned int min_heap_idx; /* for managing timeouts */ struct event_base *ev_base; + int ev_fd; short ev_events; short ev_ncalls; @@ -126,52 +256,253 @@ TAILQ_HEAD (event_list, event); TAILQ_HEAD (evkeyvalq, evkeyval); #endif /* _EVENT_DEFINED_TQENTRY */ -#ifdef _EVENT_DEFINED_RBENTRY -#undef RB_ENTRY -#undef _EVENT_DEFINED_RBENTRY -#endif /* _EVENT_DEFINED_RBENTRY */ - -struct eventop { - char *name; - void *(*init)(struct event_base *); - int (*add)(void *, struct event *); - int (*del)(void *, struct event *); - int (*recalc)(struct event_base *, void *, int); - int (*dispatch)(struct event_base *, void *, struct timeval *); - void (*dealloc)(struct event_base *, void *); -}; -void *event_init(void); +/** + Initialize the event API. + + Use event_base_new() to initialize a new event base, but does not set + the current_base global. If using only event_base_new(), each event + added must have an event base set with event_base_set() + + @see event_base_set(), event_base_free(), event_init() + */ +struct event_base *event_base_new(void); + +/** + Initialize the event API. + + The event API needs to be initialized with event_init() before it can be + used. Sets the current_base global representing the default base for + events that have no base associated with them. + + @see event_base_set(), event_base_new() + */ +struct event_base *event_init(void); + +/** + Reinitialized the event base after a fork + + Some event mechanisms do not survive across fork. The event base needs + to be reinitialized with the event_reinit() function. + + @param base the event base that needs to be re-initialized + @return 0 if successful, or -1 if some events could not be re-added. + @see event_base_new(), event_init() +*/ +int event_reinit(struct event_base *base); + +/** + Loop to process events. + + In order to process events, an application needs to call + event_dispatch(). This function only returns on error, and should + replace the event core of the application program. + + @see event_base_dispatch() + */ int event_dispatch(void); + + +/** + Threadsafe event dispatching loop. + + @param eb the event_base structure returned by event_init() + @see event_init(), event_dispatch() + */ int event_base_dispatch(struct event_base *); + + +/** + Get the kernel event notification mechanism used by libevent. + + @param eb the event_base structure returned by event_base_new() + @return a string identifying the kernel event mechanism (kqueue, epoll, etc.) + */ +const char *event_base_get_method(struct event_base *); + + +/** + Deallocate all memory associated with an event_base, and free the base. + + Note that this function will not close any fds or free any memory passed + to event_set as the argument to callback. + + @param eb an event_base to be freed + */ void event_base_free(struct event_base *); + #define _EVENT_LOG_DEBUG 0 #define _EVENT_LOG_MSG 1 #define _EVENT_LOG_WARN 2 #define _EVENT_LOG_ERR 3 typedef void (*event_log_cb)(int severity, const char *msg); +/** + Redirect libevent's log messages. + + @param cb a function taking two arguments: an integer severity between + _EVENT_LOG_DEBUG and _EVENT_LOG_ERR, and a string. If cb is NULL, + then the default log is used. + */ void event_set_log_callback(event_log_cb cb); -/* Associate a different event base with an event */ +/** + Associate a different event base with an event. + + @param eb the event base + @param ev the event + */ int event_base_set(struct event_base *, struct event *); -#define EVLOOP_ONCE 0x01 -#define EVLOOP_NONBLOCK 0x02 +/** + event_loop() flags + */ +/*@{*/ +#define EVLOOP_ONCE 0x01 /**< Block at most once. */ +#define EVLOOP_NONBLOCK 0x02 /**< Do not block. */ +/*@}*/ + +/** + Handle events. + + This is a more flexible version of event_dispatch(). + + @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK + @return 0 if successful, -1 if an error occurred, or 1 if no events were + registered. + @see event_loopexit(), event_base_loop() +*/ int event_loop(int); + +/** + Handle events (threadsafe version). + + This is a more flexible version of event_base_dispatch(). + + @param eb the event_base structure returned by event_init() + @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK + @return 0 if successful, -1 if an error occurred, or 1 if no events were + registered. + @see event_loopexit(), event_base_loop() + */ int event_base_loop(struct event_base *, int); -int event_loopexit(struct timeval *); /* Causes the loop to exit */ -int event_base_loopexit(struct event_base *, struct timeval *); +/** + Exit the event loop after the specified time. + + The next event_loop() iteration after the given timer expires will + complete normally (handling all queued events) then exit without + blocking for events again. + + Subsequent invocations of event_loop() will proceed normally. + + @param tv the amount of time after which the loop should terminate. + @return 0 if successful, or -1 if an error occurred + @see event_loop(), event_base_loop(), event_base_loopexit() + */ +int event_loopexit(const struct timeval *); + + +/** + Exit the event loop after the specified time (threadsafe variant). + + The next event_base_loop() iteration after the given timer expires will + complete normally (handling all queued events) then exit without + blocking for events again. + + Subsequent invocations of event_base_loop() will proceed normally. + + @param eb the event_base structure returned by event_init() + @param tv the amount of time after which the loop should terminate. + @return 0 if successful, or -1 if an error occurred + @see event_loopexit() + */ +int event_base_loopexit(struct event_base *, const struct timeval *); + +/** + Abort the active event_loop() immediately. + + event_loop() will abort the loop after the next event is completed; + event_loopbreak() is typically invoked from this event's callback. + This behavior is analogous to the "break;" statement. + + Subsequent invocations of event_loop() will proceed normally. + + @return 0 if successful, or -1 if an error occurred + @see event_base_loopbreak(), event_loopexit() + */ +int event_loopbreak(void); + +/** + Abort the active event_base_loop() immediately. + + event_base_loop() will abort the loop after the next event is completed; + event_base_loopbreak() is typically invoked from this event's callback. + This behavior is analogous to the "break;" statement. + + Subsequent invocations of event_loop() will proceed normally. + + @param eb the event_base structure returned by event_init() + @return 0 if successful, or -1 if an error occurred + @see event_base_loopexit + */ +int event_base_loopbreak(struct event_base *); + + +/** + Add a timer event. + + @param ev the event struct + @param tv timeval struct + */ #define evtimer_add(ev, tv) event_add(ev, tv) + + +/** + Define a timer event. + + @param ev event struct to be modified + @param cb callback function + @param arg argument that will be passed to the callback function + */ #define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) + + +/** + * Delete a timer event. + * + * @param ev the event struct to be disabled + */ #define evtimer_del(ev) event_del(ev) #define evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) #define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) +/** + * Add a timeout event. + * + * @param ev the event struct to be disabled + * @param tv the timeout value, in seconds + */ #define timeout_add(ev, tv) event_add(ev, tv) + + +/** + * Define a timeout event. + * + * @param ev the event struct to be defined + * @param cb the callback to be invoked when the timeout expires + * @param arg the argument to be passed to the callback + */ #define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) + + +/** + * Disable a timeout event. + * + * @param ev the timeout event to be disabled + */ #define timeout_del(ev) event_del(ev) + #define timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) #define timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) @@ -182,32 +513,210 @@ #define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv) #define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) +/** + Prepare an event structure to be added. + + The function event_set() prepares the event structure ev to be used in + future calls to event_add() and event_del(). The event will be prepared to + call the function specified by the fn argument with an int argument + indicating the file descriptor, a short argument indicating the type of + event, and a void * argument given in the arg argument. The fd indicates + the file descriptor that should be monitored for events. The events can be + either EV_READ, EV_WRITE, or both. Indicating that an application can read + or write from the file descriptor respectively without blocking. + + The function fn will be called with the file descriptor that triggered the + event and the type of event which will be either EV_TIMEOUT, EV_SIGNAL, + EV_READ, or EV_WRITE. The additional flag EV_PERSIST makes an event_add() + persistent until event_del() has been called. + + @param ev an event struct to be modified + @param fd the file descriptor to be monitored + @param event desired events to monitor; can be EV_READ and/or EV_WRITE + @param fn callback function to be invoked when the event occurs + @param arg an argument to be passed to the callback function + + @see event_add(), event_del(), event_once() + + */ void event_set(struct event *, int, short, void (*)(int, short, void *), void *); -int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *); -int event_base_once(struct event_base *, int, short, void (*)(int, short, void *), void *, struct timeval *); -int event_add(struct event *, struct timeval *); +/** + Schedule a one-time event to occur. + + The function event_once() is similar to event_set(). However, it schedules + a callback to be called exactly once and does not require the caller to + prepare an event structure. + + @param fd a file descriptor to monitor + @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ | + EV_WRITE + @param callback callback function to be invoked when the event occurs + @param arg an argument to be passed to the callback function + @param timeout the maximum amount of time to wait for the event, or NULL + to wait forever + @return 0 if successful, or -1 if an error occurred + @see event_set() + + */ +int event_once(int, short, void (*)(int, short, void *), void *, + const struct timeval *); + + +/** + Schedule a one-time event (threadsafe variant) + + The function event_base_once() is similar to event_set(). However, it + schedules a callback to be called exactly once and does not require the + caller to prepare an event structure. + + @param base an event_base returned by event_init() + @param fd a file descriptor to monitor + @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ | + EV_WRITE + @param callback callback function to be invoked when the event occurs + @param arg an argument to be passed to the callback function + @param timeout the maximum amount of time to wait for the event, or NULL + to wait forever + @return 0 if successful, or -1 if an error occurred + @see event_once() + */ +int event_base_once(struct event_base *base, int fd, short events, + void (*callback)(int, short, void *), void *arg, + const struct timeval *timeout); + + +/** + Add an event to the set of monitored events. + + The function event_add() schedules the execution of the ev event when the + event specified in event_set() occurs or in at least the time specified in + the tv. If tv is NULL, no timeout occurs and the function will only be + called if a matching event occurs on the file descriptor. The event in the + ev argument must be already initialized by event_set() and may not be used + in calls to event_set() until it has timed out or been removed with + event_del(). If the event in the ev argument already has a scheduled + timeout, the old timeout will be replaced by the new one. + + @param ev an event struct initialized via event_set() + @param timeout the maximum amount of time to wait for the event, or NULL + to wait forever + @return 0 if successful, or -1 if an error occurred + @see event_del(), event_set() + */ +int event_add(struct event *ev, const struct timeval *timeout); + + +/** + Remove an event from the set of monitored events. + + The function event_del() will cancel the event in the argument ev. If the + event has already executed or has never been added the call will have no + effect. + + @param ev an event struct to be removed from the working set + @return 0 if successful, or -1 if an error occurred + @see event_add() + */ int event_del(struct event *); + void event_active(struct event *, int, short); -int event_pending(struct event *, short, struct timeval *); +/** + Checks if a specific event is pending or scheduled. + + @param ev an event struct previously passed to event_add() + @param event the requested event type; any of EV_TIMEOUT|EV_READ| + EV_WRITE|EV_SIGNAL + @param tv an alternate timeout (FIXME - is this true?) + + @return 1 if the event is pending, or 0 if the event has not occurred + + */ +int event_pending(struct event *ev, short event, struct timeval *tv); + + +/** + Test if an event structure has been initialized. + + The event_initialized() macro can be used to check if an event has been + initialized. + + @param ev an event structure to be tested + @return 1 if the structure has been initialized, or 0 if it has not been + initialized + */ #ifdef WIN32 #define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE) #else #define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) #endif -/* Some simple debugging functions */ + +/** + Get the libevent version number. + + @return a string containing the version number of libevent + */ const char *event_get_version(void); + + +/** + Get the kernel event notification mechanism used by libevent. + + @return a string identifying the kernel event mechanism (kqueue, epoll, etc.) + */ const char *event_get_method(void); -/* These functions deal with event priorities */ +/** + Set the number of different event priorities. + + By default libevent schedules all active events with the same priority. + However, some time it is desirable to process some events with a higher + priority than others. For that reason, libevent supports strict priority + queues. Active events with a lower priority are always processed before + events with a higher priority. + + The number of different priorities can be set initially with the + event_priority_init() function. This function should be called before the + first call to event_dispatch(). The event_priority_set() function can be + used to assign a priority to an event. By default, libevent assigns the + middle priority to all events unless their priority is explicitly set. + + @param npriorities the maximum number of priorities + @return 0 if successful, or -1 if an error occurred + @see event_base_priority_init(), event_priority_set() + + */ int event_priority_init(int); + + +/** + Set the number of different event priorities (threadsafe variant). + + See the description of event_priority_init() for more information. + + @param eb the event_base structure returned by event_init() + @param npriorities the maximum number of priorities + @return 0 if successful, or -1 if an error occurred + @see event_priority_init(), event_priority_set() + */ int event_base_priority_init(struct event_base *, int); + + +/** + Assign a priority to an event. + + @param ev an event struct + @param priority the new priority to be assigned + @return 0 if successful, or -1 if an error occurred + @see event_priority_init() + */ int event_priority_set(struct event *, int); + /* These functions deal with buffering input and output */ struct evbuffer { @@ -239,6 +748,8 @@ }; struct bufferevent { + struct event_base *ev_base; + struct event ev_read; struct event ev_write; @@ -259,40 +770,355 @@ short enabled; /* events that are currently enabled */ }; + +/** + Create a new bufferevent. + + libevent provides an abstraction on top of the regular event callbacks. + This abstraction is called a buffered event. A buffered event provides + input and output buffers that get filled and drained automatically. The + user of a buffered event no longer deals directly with the I/O, but + instead is reading from input and writing to output buffers. + + Once initialized, the bufferevent structure can be used repeatedly with + bufferevent_enable() and bufferevent_disable(). + + When read enabled the bufferevent will try to read from the file descriptor + and call the read callback. The write callback is executed whenever the + output buffer is drained below the write low watermark, which is 0 by + default. + + If multiple bases are in use, bufferevent_base_set() must be called before + enabling the bufferevent for the first time. + + @param fd the file descriptor from which data is read and written to. + This file descriptor is not allowed to be a pipe(2). + @param readcb callback to invoke when there is data to be read, or NULL if + no callback is desired + @param writecb callback to invoke when the file descriptor is ready for + writing, or NULL if no callback is desired + @param errorcb callback to invoke when there is an error on the file + descriptor + @param cbarg an argument that will be supplied to each of the callbacks + (readcb, writecb, and errorcb) + @return a pointer to a newly allocated bufferevent struct, or NULL if an + error occurred + @see bufferevent_base_set(), bufferevent_free() + */ struct bufferevent *bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); + + +/** + Assign a bufferevent to a specific event_base. + + @param base an event_base returned by event_init() + @param bufev a bufferevent struct returned by bufferevent_new() + @return 0 if successful, or -1 if an error occurred + @see bufferevent_new() + */ int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev); + + +/** + Assign a priority to a bufferevent. + + @param bufev a bufferevent struct + @param pri the priority to be assigned + @return 0 if successful, or -1 if an error occurred + */ int bufferevent_priority_set(struct bufferevent *bufev, int pri); + + +/** + Deallocate the storage associated with a bufferevent structure. + + @param bufev the bufferevent structure to be freed. + */ void bufferevent_free(struct bufferevent *bufev); -int bufferevent_write(struct bufferevent *bufev, void *data, size_t size); + + +/** + Changes the callbacks for a bufferevent. + + @param bufev the bufferevent object for which to change callbacks + @param readcb callback to invoke when there is data to be read, or NULL if + no callback is desired + @param writecb callback to invoke when the file descriptor is ready for + writing, or NULL if no callback is desired + @param errorcb callback to invoke when there is an error on the file + descriptor + @param cbarg an argument that will be supplied to each of the callbacks + (readcb, writecb, and errorcb) + @see bufferevent_new() + */ +void bufferevent_setcb(struct bufferevent *bufev, + evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); + +/** + Changes the file descriptor on which the bufferevent operates. + + @param bufev the bufferevent object for which to change the file descriptor + @param fd the file descriptor to operate on +*/ +void bufferevent_setfd(struct bufferevent *bufev, int fd); + +/** + Write data to a bufferevent buffer. + + The bufferevent_write() function can be used to write data to the file + descriptor. The data is appended to the output buffer and written to the + descriptor automatically as it becomes available for writing. + + @param bufev the bufferevent to be written to + @param data a pointer to the data to be written + @param size the length of the data, in bytes + @return 0 if successful, or -1 if an error occurred + @see bufferevent_write_buffer() + */ +int bufferevent_write(struct bufferevent *bufev, + const void *data, size_t size); + + +/** + Write data from an evbuffer to a bufferevent buffer. The evbuffer is + being drained as a result. + + @param bufev the bufferevent to be written to + @param buf the evbuffer to be written + @return 0 if successful, or -1 if an error occurred + @see bufferevent_write() + */ int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf); + + +/** + Read data from a bufferevent buffer. + + The bufferevent_read() function is used to read data from the input buffer. + + @param bufev the bufferevent to be read from + @param data pointer to a buffer that will store the data + @param size the size of the data buffer, in bytes + @return the amount of data read, in bytes. + */ size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); + +/** + Enable a bufferevent. + + @param bufev the bufferevent to be enabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_disable() + */ int bufferevent_enable(struct bufferevent *bufev, short event); + + +/** + Disable a bufferevent. + + @param bufev the bufferevent to be disabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_enable() + */ int bufferevent_disable(struct bufferevent *bufev, short event); + + +/** + Set the read and write timeout for a buffered event. + + @param bufev the bufferevent to be modified + @param timeout_read the read timeout + @param timeout_write the write timeout + */ void bufferevent_settimeout(struct bufferevent *bufev, int timeout_read, int timeout_write); + +/** + Sets the watermarks for read and write events. + + On input, a bufferevent does not invoke the user read callback unless + there is at least low watermark data in the buffer. If the read buffer + is beyond the high watermark, the buffevent stops reading from the network. + + On output, the user write callback is invoked whenever the buffered data + falls below the low watermark. + + @param bufev the bufferevent to be modified + @param events EV_READ, EV_WRITE or both + @param lowmark the lower watermark to set + @param highmark the high watermark to set +*/ + +void bufferevent_setwatermark(struct bufferevent *bufev, short events, + size_t lowmark, size_t highmark); + #define EVBUFFER_LENGTH(x) (x)->off #define EVBUFFER_DATA(x) (x)->buffer #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); + + +/** + * Read a single line from an event buffer. + * + * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'. + * The returned buffer needs to be freed by the caller. + * + * @param buffer the evbuffer to read from + * @return pointer to a single line, or NULL if an error occurred + */ 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 *); -int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...); + + +/** + 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 The number of bytes added 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 The number of bytes added 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 *, int); + + +/** + 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 *, int, 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 * known ones - and we can just ignore the end of an event buffer. @@ -300,37 +1126,47 @@ void evtag_init(void); -void evtag_marshal(struct evbuffer *evbuf, uint8_t tag, const void *data, - uint32_t len); +void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data, + ev_uint32_t len); -void encode_int(struct evbuffer *evbuf, uint32_t number); +/** + Encode an integer and store it in an evbuffer. -void evtag_marshal_int(struct evbuffer *evbuf, uint8_t tag, uint32_t integer); + We encode integer's by nibbles; the first nibble contains the number + of significant nibbles - 1; this allows us to encode up to 64-bit + integers. This function is byte-order independent. -void evtag_marshal_string(struct evbuffer *buf, uint8_t tag, + @param evbuf evbuffer to store the encoded number + @param number a 32-bit integer + */ +void encode_int(struct evbuffer *evbuf, ev_uint32_t number); + +void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, + ev_uint32_t integer); + +void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string); -void evtag_marshal_timeval(struct evbuffer *evbuf, uint8_t tag, +void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv); -void evtag_test(void); - -int evtag_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst); -int evtag_peek(struct evbuffer *evbuf, uint8_t *ptag); -int evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength); -int evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength); +int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, + struct evbuffer *dst); +int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag); +int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength); +int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength); int evtag_consume(struct evbuffer *evbuf); -int evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag, - uint32_t *pinteger); +int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, + ev_uint32_t *pinteger); -int evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data, - size_t len); +int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, + void *data, size_t len); -int evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag, +int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, char **pstring); -int evtag_unmarshal_timeval(struct evbuffer *evbuf, uint8_t need_tag, +int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, struct timeval *ptv); #ifdef __cplusplus Index: contrib/libevent/event_tagging.c =================================================================== RCS file: /home/dcvs/src/contrib/libevent/event_tagging.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 event_tagging.c --- contrib/libevent/event_tagging.c 30 Jan 2008 12:35:18 -0000 1.1.1.1 +++ contrib/libevent/event_tagging.c 24 Apr 2008 18:28:48 -0000 @@ -25,22 +25,26 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include - #ifdef HAVE_CONFIG_H #include "config.h" #endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif + #ifdef WIN32 #define WIN32_LEAN_AND_MEAN +#include #include #undef WIN32_LEAN_AND_MEAN #else #include #endif -#include #include #ifdef HAVE_SYS_TIME_H #include @@ -53,17 +57,22 @@ #ifndef WIN32 #include #endif +#ifdef HAVE_UNISTD_H #include +#endif #include "event.h" +#include "evutil.h" #include "log.h" -int decode_int(uint32_t *pnumber, struct evbuffer *evbuf); +int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf); +int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag); +int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf); static struct evbuffer *_buf; /* not thread safe */ void -evtag_init() +evtag_init(void) { if (_buf != NULL) return; @@ -79,12 +88,12 @@ */ void -encode_int(struct evbuffer *evbuf, uint32_t number) +encode_int(struct evbuffer *evbuf, ev_uint32_t number) { int off = 1, nibbles = 0; - uint8_t data[5]; + ev_uint8_t data[5]; - memset(data, 0, sizeof(data)); + memset(data, 0, sizeof(ev_uint32_t)+1); while (number) { if (off & 0x1) data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f); @@ -105,40 +114,105 @@ } /* + * Support variable length encoding of tags; we use the high bit in each + * octet as a continuation signal. + */ + +int +evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag) +{ + int bytes = 0; + ev_uint8_t data[5]; + + memset(data, 0, sizeof(data)); + do { + ev_uint8_t lower = tag & 0x7f; + tag >>= 7; + + if (tag) + lower |= 0x80; + + data[bytes++] = lower; + } while (tag); + + if (evbuf != NULL) + evbuffer_add(evbuf, data, bytes); + + return (bytes); +} + +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); + int count = 0, shift = 0, done = 0; + + while (count++ < len) { + ev_uint8_t lower = *data++; + number |= (lower & 0x7f) << shift; + shift += 7; + + if (!(lower & 0x80)) { + done = 1; + break; + } + } + + if (!done) + return (-1); + + if (dodrain) + evbuffer_drain(evbuf, count); + + if (ptag != NULL) + *ptag = number; + + return (count); +} + +int +evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf) +{ + return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */)); +} + +/* * Marshal a data type, the general format is as follows: * * tag number: one byte; length: var bytes; payload: var bytes */ void -evtag_marshal(struct evbuffer *evbuf, uint8_t tag, - const void *data, uint32_t len) +evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, + const void *data, ev_uint32_t len) { - evbuffer_add(evbuf, &tag, sizeof(tag)); + evtag_encode_tag(evbuf, tag); encode_int(evbuf, len); evbuffer_add(evbuf, (void *)data, len); } /* Marshaling for integers */ void -evtag_marshal_int(struct evbuffer *evbuf, uint8_t tag, uint32_t integer) +evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer) { evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); encode_int(_buf, integer); - evbuffer_add(evbuf, &tag, sizeof(tag)); + evtag_encode_tag(evbuf, tag); encode_int(evbuf, EVBUFFER_LENGTH(_buf)); evbuffer_add_buffer(evbuf, _buf); } void -evtag_marshal_string(struct evbuffer *buf, uint8_t tag, const char *string) +evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string) { evtag_marshal(buf, tag, string, strlen(string)); } void -evtag_marshal_timeval(struct evbuffer *evbuf, uint8_t tag, struct timeval *tv) +evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv) { evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); @@ -150,31 +224,30 @@ } static int -decode_int_internal(uint32_t *pnumber, struct evbuffer *evbuf, int dodrain) +decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain) { - uint32_t number = 0; - uint8_t *data = EVBUFFER_DATA(evbuf); + ev_uint32_t number = 0; + ev_uint8_t *data = EVBUFFER_DATA(evbuf); int len = EVBUFFER_LENGTH(evbuf); - int nibbles = 0, off; + int nibbles = 0; if (!len) return (-1); nibbles = ((data[0] & 0xf0) >> 4) + 1; - if (nibbles > 8 || (nibbles >> 1) > len - 1) + if (nibbles > 8 || (nibbles >> 1) + 1 > len) return (-1); + len = (nibbles >> 1) + 1; - off = nibbles; - while (off > 0) { + while (nibbles > 0) { number <<= 4; - if (off & 0x1) - number |= data[off >> 1] & 0x0f; + if (nibbles & 0x1) + number |= data[nibbles >> 1] & 0x0f; else - number |= (data[off >> 1] & 0xf0) >> 4; - off--; + number |= (data[nibbles >> 1] & 0xf0) >> 4; + nibbles--; } - len = (nibbles >> 1) + 1; if (dodrain) evbuffer_drain(evbuf, len); @@ -184,55 +257,53 @@ } int -decode_int(uint32_t *pnumber, struct evbuffer *evbuf) +evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf) { return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0); } int -evtag_peek(struct evbuffer *evbuf, uint8_t *ptag) +evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag) { - if (EVBUFFER_LENGTH(evbuf) < 2) - return (-1); - *ptag = EVBUFFER_DATA(evbuf)[0]; - - return (0); + return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */)); } int -evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength) +evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength) { struct evbuffer tmp; - int res; + int res, len; - if (EVBUFFER_LENGTH(evbuf) < 2) + len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */); + if (len == -1) return (-1); tmp = *evbuf; - tmp.buffer += 1; - tmp.off -= 1; + tmp.buffer += len; + tmp.off -= len; res = decode_int_internal(plength, &tmp, 0); if (res == -1) return (-1); - *plength += res + 1; + *plength += res + len; return (0); } int -evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength) +evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength) { struct evbuffer tmp; - int res; + int res, len; - if (EVBUFFER_LENGTH(evbuf) < 2) + len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */); + if (len == -1) return (-1); tmp = *evbuf; - tmp.buffer += 1; - tmp.off -= 1; + tmp.buffer += len; + tmp.off -= len; res = decode_int_internal(plength, &tmp, 0); if (res == -1) @@ -244,9 +315,10 @@ int evtag_consume(struct evbuffer *evbuf) { - uint32_t len; - evbuffer_drain(evbuf, 1); - if (decode_int(&len, evbuf) == -1) + ev_uint32_t len; + if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1) + return (-1); + if (evtag_decode_int(&len, evbuf) == -1) return (-1); evbuffer_drain(evbuf, len); @@ -256,15 +328,14 @@ /* Reads the data type from an event buffer */ int -evtag_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst) +evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst) { - uint8_t tag; - uint32_t len; - uint32_t integer; + ev_uint32_t len; + ev_uint32_t integer; - if (evbuffer_remove(src, &tag, sizeof(tag)) != sizeof(tag)) + if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1) return (-1); - if (decode_int(&integer, src) == -1) + if (evtag_decode_int(&integer, src) == -1) return (-1); len = integer; @@ -276,24 +347,24 @@ evbuffer_drain(src, len); - *ptag = tag; return (len); } /* Marshaling for integers */ int -evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag, - uint32_t *pinteger) +evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, + ev_uint32_t *pinteger) { - uint8_t tag; - uint32_t len; - uint32_t integer; + ev_uint32_t tag; + ev_uint32_t len; + ev_uint32_t integer; - if (evbuffer_remove(evbuf, &tag, sizeof(tag)) != sizeof(tag) || - tag != need_tag) + if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1) + return (-1); + if (need_tag != tag) return (-1); - if (decode_int(&integer, evbuf) == -1) + if (evtag_decode_int(&integer, evbuf) == -1) return (-1); len = integer; @@ -306,16 +377,16 @@ evbuffer_drain(evbuf, len); - return (decode_int(pinteger, _buf)); + return (evtag_decode_int(pinteger, _buf)); } /* Unmarshal a fixed length tag */ int -evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data, +evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data, size_t len) { - uint8_t tag; + ev_uint32_t tag; /* Initialize this event buffer so that we can read into it */ evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); @@ -332,10 +403,10 @@ } int -evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag, +evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, char **pstring) { - uint8_t tag; + ev_uint32_t tag; evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); @@ -351,20 +422,20 @@ } int -evtag_unmarshal_timeval(struct evbuffer *evbuf, uint8_t need_tag, +evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, struct timeval *ptv) { - uint8_t tag; - uint32_t integer; + ev_uint32_t tag; + ev_uint32_t integer; evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag) return (-1); - if (decode_int(&integer, _buf) == -1) + if (evtag_decode_int(&integer, _buf) == -1) return (-1); ptv->tv_sec = integer; - if (decode_int(&integer, _buf) == -1) + if (evtag_decode_int(&integer, _buf) == -1) return (-1); ptv->tv_usec = integer; Index: contrib/libevent/evhttp.h =================================================================== RCS file: contrib/libevent/evhttp.h diff -N contrib/libevent/evhttp.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ contrib/libevent/evhttp.h 14 May 2008 04:07:41 -0000 @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2000-2004 Niels Provos + * 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 _EVHTTP_H_ +#define _EVHTTP_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#undef WIN32_LEAN_AND_MEAN +#endif + +/** @file evhttp.h + * + * Basic support for HTTP serving. + * + * As libevent is a library for dealing with event notification and most + * interesting applications are networked today, I have often found the + * need to write HTTP code. The following prototypes and definitions provide + * an application with a minimal interface for making HTTP requests and for + * creating a very simple HTTP server. + */ + +/* Response codes */ +#define HTTP_OK 200 +#define HTTP_NOCONTENT 204 +#define HTTP_MOVEPERM 301 +#define HTTP_MOVETEMP 302 +#define HTTP_NOTMODIFIED 304 +#define HTTP_BADREQUEST 400 +#define HTTP_NOTFOUND 404 +#define HTTP_SERVUNAVAIL 503 + +struct evhttp; +struct evhttp_request; +struct evkeyvalq; + +/** Create a new HTTP server + * + * @param base (optional) the event base to receive the HTTP events + * @return a pointer to a newly initialized evhttp server structure + */ +struct evhttp *evhttp_new(struct event_base *base); + +/** + * Binds an HTTP server on the specified address and port. + * + * Can be called multiple times to bind the same http server + * to multiple different ports. + * + * @param http a pointer to an evhttp object + * @param address a string containing the IP address to listen(2) on + * @param port the port number to listen on + * @return a newly allocated evhttp struct + * @see evhttp_free() + */ +int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port); + +/** + * Makes an HTTP server accept connections on the specified socket + * + * This may be useful to create a socket and then fork multiple instances + * of an http server, or when a socket has been communicated via file + * descriptor passing in situations where an http servers does not have + * permissions to bind to a low-numbered port. + * + * Can be called multiple times to have the http server listen to + * multiple different sockets. + * + * @param http a pointer to an evhttp object + * @param fd a socket fd that is ready for accepting connections + * @return 0 on success, -1 on failure. + * @see evhttp_free(), evhttp_bind_socket() + */ +int evhttp_accept_socket(struct evhttp *http, int fd); + +/** + * Free the previously created HTTP server. + * + * Works only if no requests are currently being served. + * + * @param http the evhttp server object to be freed + * @see evhttp_start() + */ +void evhttp_free(struct evhttp* http); + +/** Set a callback for a specified URI */ +void evhttp_set_cb(struct evhttp *, const char *, + void (*)(struct evhttp_request *, void *), void *); + +/** Removes the callback for a specified URI */ +int evhttp_del_cb(struct evhttp *, const char *); + +/** Set a callback for all requests that are not caught by specific callbacks + */ +void evhttp_set_gencb(struct evhttp *, + void (*)(struct evhttp_request *, void *), void *); + +/** + * Set the timeout for an HTTP request. + * + * @param http an evhttp object + * @param timeout_in_secs the timeout, in seconds + */ +void evhttp_set_timeout(struct evhttp *, int timeout_in_secs); + +/* Request/Response functionality */ + +/** + * Send an HTML error message to the client. + * + * @param req a request object + * @param error the HTTP error code + * @param reason a brief explanation of the error + */ +void evhttp_send_error(struct evhttp_request *req, int error, + const char *reason); + +/** + * Send an HTML reply to the client. + * + * @param req a request object + * @param code the HTTP response code to send + * @param reason a brief message to send with the response code + * @param databuf the body of the response + */ +void evhttp_send_reply(struct evhttp_request *req, int code, + const char *reason, struct evbuffer *databuf); + +/* Low-level response interface, for streaming/chunked replies */ +void evhttp_send_reply_start(struct evhttp_request *, int, const char *); +void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *); +void evhttp_send_reply_end(struct evhttp_request *); + +/** + * Start an HTTP server on the specified address and port + * + * DEPRECATED: it does not allow an event base to be specified + * + * @param address the address to which the HTTP server should be bound + * @param port the port number on which the HTTP server should listen + * @return an struct evhttp object + */ +struct evhttp *evhttp_start(const char *address, u_short port); + +/* + * Interfaces for making requests + */ +enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD }; + +enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE }; + +/** + * the request structure that a server receives. + * WARNING: expect this structure to change. I will try to provide + * reasonable accessors. + */ +struct evhttp_requ