]> granicus.if.org Git - libevent/commitdiff
provided buffered events
authorNiels Provos <provos@gmail.com>
Tue, 23 Mar 2004 03:43:53 +0000 (03:43 +0000)
committerNiels Provos <provos@gmail.com>
Tue, 23 Mar 2004 03:43:53 +0000 (03:43 +0000)
svn:r95

Makefile.am
buffer.c
compat/sys/tree.h
configure.in
evbuffer.c [new file with mode: 0644]
event.c
event.h

index 009244b29d8c99099fb07b273832990fcd437bca..c299567935127ef331898cf8542d91b17cc90ae5 100644 (file)
@@ -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 buffer.c
+libevent_a_SOURCES = event.c buffer.c evbuffer.c
 libevent_a_LIBADD = @LIBOBJS@
 
 include_HEADERS = event.h
index 8272cf39c2453c47064df30c1b3ba9dc8f6e2320..ad608b77a0dca44d0541e8fa3266e717e4292442 100644 (file)
--- a/buffer.c
+++ b/buffer.c
 #endif
 #include <unistd.h>
 
-#undef timeout_pending
-#undef timeout_initialized
-
-#include <event.h>
-
 #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__);
+       buffer = calloc(1, sizeof(struct evbuffer));
 
        return (buffer);
 }
@@ -53,11 +45,20 @@ evbuffer_free(struct evbuffer *buffer)
        free(buffer);
 }
 
-void
+/* 
+ * This is a destructive add.  The data from one buffer moves into
+ * the other buffer.
+ */
+
+int
 evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
 {
-       evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
-       evbuffer_drain(inbuf, inbuf->off);
+       int res;
+       res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
+       if (res == 0)
+               evbuffer_drain(inbuf, inbuf->off);
+
+       return (res);
 }
 
 int
@@ -73,29 +74,41 @@ evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...)
                goto end;
        
        res = strlen(msg);
-       evbuffer_add(buf, msg, res);
+       if (evbuffer_add(buf, msg, res) == -1)
+               res = -1;
        free(msg);
 
-
  end:
        va_end(ap);
 
        return (res);
 }
 
-void
+int
 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;
+               void *newbuf;
+               int length = buf->totallen;
+
+               if (length < 256)
+                       length = 256;
+               while (length < need)
+                       length <<= 1;
+
+               if ((newbuf = realloc(buf->buffer, length)) == NULL)
+                       return (-1);
+
+               buf->buffer = newbuf;
+               buf->totallen = length;
        }
 
        memcpy(buf->buffer + buf->off, data, datlen);
        buf->off += datlen;
+
+       return (0);
 }
 
 void
index 927ca04cd76b30e76948ad5ba21a760b5406dc32..6a3381caee41c45eacbf871dae27a777ebd43927 100644 (file)
@@ -379,7 +379,7 @@ void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
 struct type *name##_RB_REMOVE(struct name *, struct type *);           \
 struct type *name##_RB_INSERT(struct name *, struct type *);           \
 struct type *name##_RB_FIND(struct name *, struct type *);             \
-struct type *name##_RB_NEXT(struct name *, struct type *);             \
+struct type *name##_RB_NEXT(struct type *);                            \
 struct type *name##_RB_MINMAX(struct name *, int);                     \
                                                                        \
 
@@ -624,7 +624,7 @@ name##_RB_FIND(struct name *head, struct type *elm)                 \
 }                                                                      \
                                                                        \
 struct type *                                                          \
-name##_RB_NEXT(struct name *head, struct type *elm)                    \
+name##_RB_NEXT(struct type *elm)                                       \
 {                                                                      \
        if (RB_RIGHT(elm, field)) {                                     \
                elm = RB_RIGHT(elm, field);                             \
@@ -665,13 +665,13 @@ name##_RB_MINMAX(struct name *head, int val)                              \
 #define RB_INSERT(name, x, y)  name##_RB_INSERT(x, y)
 #define RB_REMOVE(name, x, y)  name##_RB_REMOVE(x, y)
 #define RB_FIND(name, x, y)    name##_RB_FIND(x, y)
-#define RB_NEXT(name, x, y)    name##_RB_NEXT(x, y)
+#define RB_NEXT(name, x, y)    name##_RB_NEXT(y)
 #define RB_MIN(name, x)                name##_RB_MINMAX(x, RB_NEGINF)
 #define RB_MAX(name, x)                name##_RB_MINMAX(x, RB_INF)
 
 #define RB_FOREACH(x, name, head)                                      \
        for ((x) = RB_MIN(name, head);                                  \
             (x) != NULL;                                               \
-            (x) = name##_RB_NEXT(head, x))
+            (x) = name##_RB_NEXT(x))
 
 #endif /* _SYS_TREE_H_ */
index 278f7629080b2c71b4fe826789401a179dde0d62..61c12179d19a081a59748166b85d970949170dbc 100644 (file)
@@ -61,7 +61,7 @@ dnl Checks for typedefs, structures, and compiler characteristics.
 AC_HEADER_TIME
 
 dnl Checks for library functions.
-AC_CHECK_FUNCS(gettimeofday)
+AC_CHECK_FUNCS(gettimeofday vasprintf)
 
 needsignal=no
 haveselect=no
diff --git a/evbuffer.c b/evbuffer.c
new file mode 100644 (file)
index 0000000..80e7318
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#include <unistd.h>
+
+#include "event.h"
+
+static int
+bufferevent_add(struct event *ev, int timeout)
+{
+       struct timeval tv, *ptv = NULL;
+
+       if (timeout) {
+               timerclear(&tv);
+               tv.tv_sec = timeout;
+               ptv = &tv;
+       }
+
+       return (event_add(ev, ptv));
+}
+
+static void
+bufferevent_readcb(int fd, short event, void *arg)
+{
+       struct bufferevent *bufev = arg;
+       int res = 0;
+       short what = EVBUFFER_READ;
+
+       if (event == EV_TIMEOUT) {
+               what |= EVBUFFER_TIMEOUT;
+               goto error;
+       }
+
+       res = evbuffer_read(bufev->input, fd, -1);
+       if (res == -1) {
+               if (errno == EAGAIN || errno == EINTR)
+                       goto reschedule;
+               /* error case */
+               what |= EVBUFFER_ERROR;
+       } else if (res == 0) {
+               /* eof case */
+               what |= EVBUFFER_EOF;
+       }
+
+       if (res <= 0)
+               goto error;
+
+       bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+
+       /* Invoke the user callback - must always be called last */
+       (*bufev->readcb)(bufev, bufev->cbarg);
+       return;
+
+ reschedule:
+       bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+       return;
+
+ error:
+       (*bufev->errorcb)(bufev, what, bufev->cbarg);
+}
+
+static void
+bufferevent_writecb(int fd, short event, void *arg)
+{
+       struct bufferevent *bufev = arg;
+       int res;
+       short what = EVBUFFER_WRITE;
+
+       if (event == EV_TIMEOUT) {
+               what |= EVBUFFER_TIMEOUT;
+               goto error;
+       }
+
+       res = evbuffer_write(bufev->input, fd);
+       if (res == -1) {
+               if (errno == EAGAIN || errno == EINTR)
+                       goto reschedule;
+               /* error case */
+               what |= EVBUFFER_ERROR;
+       } else if (res == 0) {
+               /* eof case */
+               what |= EVBUFFER_EOF;
+       }
+
+       if (res <= 0)
+               goto error;
+
+       /* Invoke the user callback if our buffer is drained */
+       if (EVBUFFER_LENGTH(bufev->output) == 0)
+               (*bufev->writecb)(bufev, bufev->cbarg);
+
+ reschedule:
+       /* Do not call if we call user callback before, we may be deleted */
+       if (EVBUFFER_LENGTH(bufev->output) != 0) {
+               bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+       }
+       return;
+
+ error:
+       (*bufev->errorcb)(bufev, what, bufev->cbarg);
+}
+
+/*
+ * Create a new buffered event object.
+ *
+ * The read callback is invoked whenever we read new data.
+ * The write callback is invoked whenever the output buffer is drained.
+ * The error callback is invoked on a write/read error or on EOF.
+ */
+
+struct bufferevent *
+bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb,
+    everrorcb errorcb, void *cbarg)
+{
+       struct bufferevent *bufev;
+
+       if ((bufev = calloc(1, sizeof(struct bufferevent))) == NULL)
+               return (NULL);
+
+       if ((bufev->input = evbuffer_new()) == NULL) {
+               free(bufev);
+               return (NULL);
+       }
+
+       if ((bufev->output = evbuffer_new()) == NULL) {
+               evbuffer_free(bufev->input);
+               free(bufev);
+               return (NULL);
+       }
+
+       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;
+
+       bufev->enabled = EV_READ | EV_WRITE;
+
+       return (bufev);
+}
+
+void
+bufferevent_free(struct bufferevent *bufev)
+{
+       event_del(&bufev->ev_read);
+       event_del(&bufev->ev_write);
+
+       evbuffer_free(bufev->input);
+       evbuffer_free(bufev->output);
+
+       free(bufev);
+}
+
+/*
+ * Returns 0 on success;
+ *        -1 on failure.
+ */
+
+int
+bufferevent_write(struct bufferevent *bufev, void *data, size_t size)
+{
+       int res;
+
+       res = evbuffer_add(bufev->output, data, size);
+
+       if (res == -1)
+               return (res);
+
+       /* If everything is okay, we need to schedule a write */
+       if (size > 0 && (bufev->enabled & EV_WRITE))
+               bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+
+       return (res);
+}
+
+int
+bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
+{
+       int res;
+
+       res = bufferevent_write(bufev, buf->buffer, buf->off);
+       if (res != -1)
+               evbuffer_drain(buf, buf->off);
+
+       return (res);
+}
+
+size_t
+bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
+{
+       struct evbuffer *buf = bufev->input;
+
+       if (buf->off < size)
+               size = buf->off;
+
+       /* Copy the available data to the user buffer */
+       memcpy(data, buf->buffer, size);
+
+       if (size)
+               evbuffer_drain(buf, size);
+
+       return (size);
+}
+
+int
+bufferevent_enable(struct bufferevent *bufev, short event)
+{
+       if (event & EV_READ) {
+               if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1)
+                       return (-1);
+       }
+       if (event & EV_WRITE) {
+               if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1)
+                       return (-1);
+       }
+
+       bufev->enabled |= event;
+       return (0);
+}
+
+int
+bufferevent_disable(struct bufferevent *bufev, short event)
+{
+       if (event & EV_READ) {
+               if (event_del(&bufev->ev_read) == -1)
+                       return (-1);
+       }
+       if (event & EV_WRITE) {
+               if (event_del(&bufev->ev_write) == -1)
+                       return (-1);
+       }
+
+       bufev->enabled &= ~event;
+       return (0);
+}
+
+/*
+ * Sets the read and write timeout for a buffered event.
+ */
+
+void
+bufferevent_settimeout(struct bufferevent *bufev,
+    int timeout_read, int timeout_write) {
+       bufev->timeout_read = timeout_read;
+       bufev->timeout_write = timeout_write;
+}
diff --git a/event.c b/event.c
index 3cf61b452f0534dc20e39fcba2a79d934feec59a..ed8c36320b7b3904c5dd450ad75cc9f34e488432 100644 (file)
--- a/event.c
+++ b/event.c
@@ -238,7 +238,7 @@ event_loop(int flags)
                /* Terminate the loop if we have been asked to */
                if (event_gotterm) {
                        event_gotterm = 0;
-                       done = 1;
+                       break;
                }
 
                while (event_gotsig) {
diff --git a/event.h b/event.h
index c393c3882c390d3202488323aaed1257a64f5cb8..ebb716531fc684aec111f72099c38812a572e1fe 100644 (file)
--- a/event.h
+++ b/event.h
@@ -205,6 +205,7 @@ struct bufferevent {
 
 struct bufferevent *bufferevent_new(int fd,
     evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+void bufferevent_free(struct bufferevent *bufev);
 int bufferevent_write(struct bufferevent *bufev, void *data, size_t size);
 int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
 size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);