From ec2c1db47e2931fc4be55f9653b3b4182d674cc7 Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Sun, 22 Feb 2004 21:17:23 +0000 Subject: [PATCH] new event_once interface; start of buffering interface for buffered events svn:r93 --- Makefile.am | 2 +- buffer.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++ configure.in | 4 +- event.3 | 17 ++++++ event.c | 59 ++++++++++++++++++ event.h | 25 +++++++- 6 files changed, 267 insertions(+), 5 deletions(-) create mode 100644 buffer.c diff --git a/Makefile.am b/Makefile.am index f7696e0e..009244b2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,7 @@ EXTRA_DIST = acconfig.h err.c event.h evsignal.h event.3 kqueue.c \ lib_LIBRARIES = libevent.a -libevent_a_SOURCES = event.c +libevent_a_SOURCES = event.c buffer.c libevent_a_LIBADD = @LIBOBJS@ include_HEADERS = event.h diff --git a/buffer.c b/buffer.c new file mode 100644 index 00000000..8272cf39 --- /dev/null +++ b/buffer.c @@ -0,0 +1,165 @@ +/* + * Copyright 2002, 2003 Niels Provos + * All rights reserved. + * + */ + +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include +#include +#include +#include +#include +#ifdef HAVE_STDARG_H +#include +#endif +#include + +#undef timeout_pending +#undef timeout_initialized + +#include + +#include "event.h" + +extern int debug; + +struct evbuffer * +evbuffer_new(void) +{ + struct evbuffer *buffer; + + if ((buffer = calloc(1, sizeof(struct evbuffer))) == NULL) + err(1, "%s: calloc", __func__); + + return (buffer); +} + +void +evbuffer_free(struct evbuffer *buffer) +{ + if (buffer->buffer != NULL) + free(buffer->buffer); + free(buffer); +} + +void +evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) +{ + evbuffer_add(outbuf, inbuf->buffer, inbuf->off); + evbuffer_drain(inbuf, inbuf->off); +} + +int +evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...) +{ + int res = -1; + char *msg; + va_list ap; + + va_start(ap, fmt); + + if (vasprintf(&msg, fmt, ap) == -1) + goto end; + + res = strlen(msg); + evbuffer_add(buf, msg, res); + free(msg); + + + end: + va_end(ap); + + return (res); +} + +void +evbuffer_add(struct evbuffer *buf, u_char *data, size_t datlen) +{ + size_t need = buf->off + datlen; + + if (buf->totallen < need) { + if ((buf->buffer = realloc(buf->buffer, need)) == NULL) + err(1, "%s: realloc", __func__); + buf->totallen = need; + } + + memcpy(buf->buffer + buf->off, data, datlen); + buf->off += datlen; +} + +void +evbuffer_drain(struct evbuffer *buf, size_t len) +{ + if (len >= buf->off) { + buf->off = 0; + return; + } + + memmove(buf->buffer, buf->buffer + len, buf->off - len); + buf->off -= len; +} + +int +evbuffer_read(struct evbuffer *buffer, int fd, int howmuch) +{ + u_char inbuf[4096]; + int n; + + if (howmuch < 0 || howmuch > sizeof(inbuf)) + howmuch = sizeof(inbuf); + + n = read(fd, inbuf, howmuch); + if (n == -1) + return (-1); + if (n == 0) + return (0); + + evbuffer_add(buffer, inbuf, n); + + return (n); +} + +int +evbuffer_write(struct evbuffer *buffer, int fd) +{ + int n; + + n = write(fd, buffer->buffer, buffer->off); + if (n == -1) + return (-1); + if (n == 0) + return (0); + + evbuffer_drain(buffer, n); + + return (n); +} + +u_char * +evbuffer_find(struct evbuffer *buffer, u_char *what, size_t len) +{ + size_t remain = buffer->off; + u_char *search = buffer->buffer; + u_char *p; + + while ((p = memchr(search, *what, remain)) != NULL && remain >= len) { + if (memcmp(p, what, len) == 0) + return (p); + + search = p + 1; + remain = buffer->off - (size_t)(search - buffer->buffer); + } + + return (NULL); +} diff --git a/configure.in b/configure.in index 92a08ff9..278f7629 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ dnl configure.in for libevent dnl Dug Song AC_INIT(event.c) -AM_INIT_AUTOMAKE(libevent,0.7b) +AM_INIT_AUTOMAKE(libevent,0.7c) AM_CONFIG_HEADER(config.h) AM_MAINTAINER_MODE @@ -27,7 +27,7 @@ AC_CHECK_LIB(socket, socket) dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h) +AC_CHECK_HEADERS(stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h) if test "x$ac_cv_header_sys_queue_h" = "xyes"; then AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) AC_EGREP_CPP(yes, diff --git a/event.3 b/event.3 index 924ecdea..0a355cef 100644 --- a/event.3 +++ b/event.3 @@ -36,6 +36,7 @@ .Nm event_set , .Nm event_add , .Nm event_del , +.Nm event_once , .Nm event_pending , .Nm event_initialized , .Nm evtimer_set , @@ -65,6 +66,8 @@ .Ft int .Fn "event_del" "struct event *ev" .Ft int +.Fn "event_once" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv" +.Ft int .Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv" .Ft int .Fn "event_initialized" "struct event *ev" @@ -234,6 +237,20 @@ will cancel the event in the argument If the event has already executed or has never been added the call will have no effect. .Pp +The function +.Fn event_once +is similiar to +.Fn event_set . +However, it schedules a callback to be called exactly once and does not +require the caller to prepare an +.Fa event +structure. +This function supports +.Fa EV_TIMEOUT , +.Fa EV_READ +and +.Fa EV_WRITE . +.Pp The .Fn event_pending function can be used to check if the event specified by diff --git a/event.c b/event.c index 1dda1a7d..ec08e142 100644 --- a/event.c +++ b/event.c @@ -273,6 +273,62 @@ event_loop(int flags) return (0); } +/* Sets up an event for processing once */ + +struct event_once { + struct event ev; + + void (*cb)(int, short, void *); + void *arg; +}; + +/* One-time callback, it deletes itself */ + +static void +event_once_cb(int fd, short events, void *arg) +{ + struct event_once *eonce = arg; + + (*eonce->cb)(fd, events, eonce->arg); + free(eonce); +} + +/* Schedules an event once */ + +int +event_once(int fd, short events, + void (*callback)(int, short, void *), void *arg, struct timeval *tv) +{ + struct event_once *eonce; + struct timeval etv; + + if ((eonce = calloc(1, sizeof(struct event_once))) == NULL) + return (-1); + + if (events == EV_TIMEOUT) { + if (tv == NULL) { + timerclear(&etv); + tv = &etv; + } + + eonce->cb = callback; + eonce->arg = arg; + + evtimer_set(&eonce->ev, event_once_cb, &eonce); + } else if (events & (EV_READ|EV_WRITE)) { + events &= EV_READ|EV_WRITE; + + event_set(&eonce->ev, fd, events, event_once_cb, &eonce); + } else { + /* Bad event combination */ + return (-1); + } + + event_add(&eonce->ev, tv); + + return (0); +} + void event_set(struct event *ev, int fd, short events, void (*callback)(int, short, void *), void *arg) @@ -445,6 +501,9 @@ timeout_next(struct timeval *tv) timersub(&ev->ev_timeout, &now, tv); + assert(tv->tv_sec >= 0); + assert(tv->tv_usec >= 0); + LOG_DBG((LOG_MISC, 60, "timeout_next: in %d seconds", tv->tv_sec)); return (0); } diff --git a/event.h b/event.h index bfac3f2a..ed09afc6 100644 --- a/event.h +++ b/event.h @@ -1,5 +1,3 @@ -/* $OpenBSD: event.h,v 1.4 2002/07/12 18:50:48 provos Exp $ */ - /* * Copyright 2000-2002 Niels Provos * All rights reserved. @@ -153,6 +151,8 @@ void timeout_process(void); #define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) 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_add(struct event *, struct timeval *); int event_del(struct event *); void event_active(struct event *, int, short); @@ -165,6 +165,27 @@ int event_pending(struct event *, short, struct timeval *); #define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) #endif +/* These functions deal with buffering input and output */ + +struct evbuffer { + u_char *buffer; + + size_t totallen; + size_t off; +}; + +#define EVBUFFER_LENGTH(x) (x)->off + +struct evbuffer *evbuffer_new(void); +void evbuffer_free(struct evbuffer *); +void evbuffer_add(struct evbuffer *, u_char *, size_t); +void evbuffer_add_buffer(struct evbuffer *, struct evbuffer *); +int evbuffer_add_printf(struct evbuffer *, char *fmt, ...); +void evbuffer_drain(struct evbuffer *, size_t); +int evbuffer_write(struct evbuffer *, int); +int evbuffer_read(struct evbuffer *, int, int); +u_char *evbuffer_find(struct evbuffer *, u_char *, size_t); + #ifdef __cplusplus } #endif