Netevent work

git-svn-id: file:///svn/unbound/trunk@27 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-01-23 13:46:18 +00:00
parent df792cc3af
commit 8982c72e5c
8 changed files with 392 additions and 26 deletions

View file

@ -67,11 +67,11 @@ all: $(COMMON_OBJ) unbound unittest
unbound: $(COMMON_OBJ) $(DAEMON_OBJ) unbound: $(COMMON_OBJ) $(DAEMON_OBJ)
$(INFO) Link $@ $(INFO) Link $@
$Q$(LINK) -o $@ $^ $Q$(LINK) -o $@ $^ $(LIBS)
unittest: $(COMMON_OBJ) $(UNITTEST_OBJ) unittest: $(COMMON_OBJ) $(UNITTEST_OBJ)
$(INFO) Link $@ $(INFO) Link $@
$Q$(LINK) -o $@ $^ $Q$(LINK) -o $@ $^ $(LIBS)
clean: clean:
rm -f *.o *.d *.lo *~ tags rm -f *.o *.d *.lo *~ tags

View file

@ -188,6 +188,7 @@ AC_CHECK_TYPE(in_port_t, [], [AC_DEFINE([in_port_t], [uint16_t], [in_port_t])],
# check to see if libraries are needed for these functions. # check to see if libraries are needed for these functions.
AC_CHECK_LIB(socket, socket) AC_CHECK_LIB(socket, socket)
AC_CHECK_LIB(nsl, inet_pton) AC_CHECK_LIB(nsl, inet_pton)
AC_CHECK_LIB(event, event_set)
AC_FUNC_MALLOC AC_FUNC_MALLOC

View file

@ -1,3 +1,7 @@
23 January 2007: Wouter
- added libevent to configure to link with.
- util/netevent setup work.
22 January 2007: Wouter 22 January 2007: Wouter
- Designed header file for network communication. - Designed header file for network communication.

View file

@ -35,7 +35,7 @@ Roughly the boxes are as follows:
0.8 Library use - resolver validator lib (and test apps) 0.8 Library use - resolver validator lib (and test apps)
0.9 Corner cases - be able to resolve in the wild. Run fuzzers. 0.9 Corner cases - be able to resolve in the wild. Run fuzzers.
Run as many tests as we can think of. Run as many tests as we can think of.
1.0 El product. Run shadow for a resolver in production for several 0.10 Beta release. Run shadow for a resolver in production for several
weeks. weeks.
For boxes 0.5-1.0 the planning is to be revised, at the 0.5 stage external For boxes 0.5-1.0 the planning is to be revised, at the 0.5 stage external

View file

@ -23,13 +23,13 @@ log_init()
} }
void void
log_vmsg(const char *format, va_list args) log_vmsg(const char* type, const char *format, va_list args)
{ {
char message[MAXSYSLOGMSGLEN]; char message[MAXSYSLOGMSGLEN];
const char* ident="unbound"; const char* ident="unbound";
vsnprintf(message, sizeof(message), format, args); vsnprintf(message, sizeof(message), format, args);
fprintf(stderr, "[%d] %s[%d]: %s\n", fprintf(stderr, "[%d] %s[%d] %s: %s\n",
(int)time(NULL), ident, (int)getpid(), message); (int)time(NULL), ident, (int)getpid(), type, message);
} }
/** /**
@ -41,6 +41,19 @@ log_info(const char *format, ...)
{ {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
log_vmsg(format, args); log_vmsg("info", format, args);
va_end(args);
}
/**
* implementation of log_err
* @param format: format string printf-style.
*/
void
log_err(const char *format, ...)
{
va_list args;
va_start(args, format);
log_vmsg("error", format, args);
va_end(args); va_end(args);
} }

View file

@ -27,16 +27,25 @@
void log_init(); void log_init();
/** /**
* Log informational message.
* Pass printf formatted arguments. No trailing newline is needed. * Pass printf formatted arguments. No trailing newline is needed.
* @param format: printf-style format string. Arguments follow. * @param format: printf-style format string. Arguments follow.
*/ */
void log_info(const char* format, ...) ATTR_FORMAT(printf, 1, 2); void log_info(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
/**
* Log error message.
* Pass printf formatted arguments. No trailing newline is needed.
* @param format: printf-style format string. Arguments follow.
*/
void log_err(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
/** /**
* va_list argument version of log_info. * va_list argument version of log_info.
* @param type: string to designate type of message (info, error).
* @param format: the printf style format to print. no newline. * @param format: the printf style format to print. no newline.
* @param args: arguments for format string. * @param args: arguments for format string.
*/ */
void log_vmsg(const char *format, va_list args); void log_vmsg(const char* type, const char *format, va_list args);
#endif /* UTIL_LOG_H */ #endif /* UTIL_LOG_H */

240
util/netevent.c Normal file
View file

@ -0,0 +1,240 @@
/*
* util/netevent.c - event notification
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* See LICENSE for the license.
*
*/
/**
* \file
*
* This file contains event notification functions.
*/
#include "util/netevent.h"
#include "util/log.h"
#include <errno.h>
/* we use libevent */
#include <event.h>
/**
* The internal event structure for keeping libevent info for the event.
* Possibly other structures (list, tree) this is part of.
*/
struct internal_event {
/** libevent event type, alloced here */
struct event ev;
};
/**
* Internal base structure, so that every thread has its own events.
*/
struct internal_base {
/** libevent event_base type. */
struct event_base* base;
};
struct comm_base* comm_base_create()
{
struct comm_base* b = (struct comm_base*)calloc(1,
sizeof(struct comm_base));
if(!b)
return NULL;
b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
if(!b->eb) {
free(b);
return NULL;
}
b->eb->base = event_init();
if(!b->eb->base) {
free(b->eb);
free(b);
return NULL;
}
return b;
}
void comm_base_delete(struct comm_base* b)
{
/* No way to delete event_base! leaks. */
b->eb->base = NULL;
free(b->eb);
free(b);
}
void comm_base_dispatch(struct comm_base* b)
{
int retval;
while(1) {
retval = event_base_dispatch(b->eb->base);
if(retval != 0) {
log_err("event_dispatch returned error %d, "
"errno is %s", retval, strerror(errno));
}
}
}
/**
* libevent callback routine for commpoint udp
* @param fd: file descriptor.
* @param event: event bits from libevent:
* EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
* @param arg: the comm_point structure.
*/
static void
comm_point_udp_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
void* arg)
{
struct comm_point* c = (struct comm_point*)arg;
log_info("callback udp for %x", (int)c);
}
/**
* libevent callback routine for commpoint tcp accept listeners.
* @param fd: file descriptor.
* @param event: event bits from libevent:
* EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
* @param arg: the comm_point structure.
*/
static void
comm_point_tcp_accept_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
void* arg)
{
struct comm_point* c = (struct comm_point*)arg;
log_info("callback tcpaccept for %x", (int)c);
}
struct comm_point* comm_point_create_udp(struct comm_base *base,
int fd, struct buffer* buffer,
comm_point_callback_t* callback, void* callback_arg)
{
struct comm_point* c = (struct comm_point*)calloc(1,
sizeof(struct comm_point));
short evbits;
if(!c)
return NULL;
c->ev = (struct internal_event*)calloc(1,
sizeof(struct internal_event));
if(!c->ev) {
free(c);
return NULL;
}
c->fd = fd;
c->buffer = buffer;
c->timeout = NULL;
c->tcp_is_reading = 0;
c->tcp_byte_count = 0;
c->tcp_parent = NULL;
c->cur_tcp_count = 0;
c->max_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->type = comm_udp;
c->tcp_do_close = 0;
c->tcp_do_toggle_rw = 0;
c->callback = callback;
c->cb_arg = callback_arg;
evbits = EV_READ | EV_PERSIST;
/* libevent stuff */
event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_callback, c);
if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
event_add(&c->ev->ev, c->timeout) != 0 ) {
log_err("could not add udp event");
comm_point_delete(c);
return NULL;
}
return c;
}
struct comm_point*
comm_point_create_tcp_handler(struct comm_base *base,
struct comm_point* parent, size_t bufsize,
comm_point_callback_t* callback, void* callback_arg)
{
return NULL;
}
struct comm_point*
comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize,
comm_point_callback_t* callback, void* callback_arg)
{
struct comm_point* c = (struct comm_point*)calloc(1,
sizeof(struct comm_point));
short evbits;
int i;
/* first allocate the TCP accept listener */
if(!c)
return NULL;
c->ev = (struct internal_event*)calloc(1,
sizeof(struct internal_event));
if(!c->ev) {
free(c);
return NULL;
}
c->fd = fd;
c->buffer = NULL;
c->timeout = NULL;
c->tcp_is_reading = 0;
c->tcp_byte_count = 0;
c->tcp_parent = NULL;
c->cur_tcp_count = 0;
c->max_tcp_count = num;
c->tcp_handlers = (struct comm_point**)calloc(num,
sizeof(struct comm_point*));
c->tcp_free = NULL;
c->type = comm_tcp_accept;
c->tcp_do_close = 0;
c->tcp_do_toggle_rw = 0;
c->callback = NULL;
c->cb_arg = NULL;
evbits = EV_READ | EV_PERSIST;
/* libevent stuff */
event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_accept_callback, c);
if( event_base_set(base->eb->base, &c->ev->ev) != 0 ||
event_add(&c->ev->ev, c->timeout) != 0 )
{
log_err("could not add tcpacc event");
if(!event_del(&c->ev->ev)) {
log_err("could not event_del tcpacc event");
}
free(c->tcp_handlers);
free(c->ev);
free(c);
return NULL;
}
/* now prealloc the tcp handlers */
for(i=0; i<num; i++) {
c->tcp_handlers[i] = comm_point_create_tcp_handler(base,
c, bufsize, callback, callback_arg);
}
return c;
}
void comm_point_close(struct comm_point* c)
{
if(c->fd != -1)
close(c->fd);
c->fd = -1;
if(event_del(&c->ev->ev) != 0) {
log_err("could not event_del on close");
}
}
void comm_point_delete(struct comm_point* c)
{
comm_point_close(c);
if(c->tcp_handlers) {
int i;
for(i=0; i<c->max_tcp_count; i++)
comm_point_delete(c->tcp_handlers[i]);
free(c->tcp_handlers);
}
free(c->ev);
free(c);
}

View file

@ -30,10 +30,31 @@
#include "config.h" #include "config.h"
struct buffer; struct buffer;
/** internal event notification data storage structure. */ /* internal event notification data storage structure. */
struct internal_event; struct internal_event;
struct internal_base;
struct comm_point;
/** Communication point to the network */ /** callback from communication point function type */
typedef int comm_point_callback_t(struct comm_point*, void*, int);
/**
* A communication point dispatcher. Thread specific.
*/
struct comm_base {
/** behind the scenes structure. with say libevent info. alloced */
struct internal_base* eb;
};
/**
* Communication point to the network
* These behaviours can be accomplished by setting the flags
* and passing return values from the callback.
* udp frontside: called after readdone. sendafter.
* tcp frontside: called readdone, sendafter. close.
* udp behind: called after readdone. No send after.
* tcp behind: write done, read done, then called. No send after.
*/
struct comm_point { struct comm_point {
/** behind the scenes structure, with say libevent info. alloced. */ /** behind the scenes structure, with say libevent info. alloced. */
struct internal_event* ev; struct internal_event* ev;
@ -53,7 +74,7 @@ struct comm_point {
/** The current read/write count for TCP */ /** The current read/write count for TCP */
size_t tcp_byte_count; size_t tcp_byte_count;
/** parent communication point (for TCP sockets) */ /** parent communication point (for TCP sockets) */
struct comm_point tcp_parent; struct comm_point *tcp_parent;
/* -------- TCP Accept -------- */ /* -------- TCP Accept -------- */
/** current number of TCP connections on this socket */ /** current number of TCP connections on this socket */
@ -62,7 +83,7 @@ struct comm_point {
int max_tcp_count; int max_tcp_count;
/** malloced array of tcp handlers for a tcp-accept, /** malloced array of tcp handlers for a tcp-accept,
of size max_tcp_count. */ of size max_tcp_count. */
struct comm_point *tcp_handlers; struct comm_point **tcp_handlers;
/** linked list of free tcp_handlers to use for new queries. /** linked list of free tcp_handlers to use for new queries.
For tcp_accept the first entry, for tcp_handlers the next one. */ For tcp_accept the first entry, for tcp_handlers the next one. */
struct comm_point *tcp_free; struct comm_point *tcp_free;
@ -77,28 +98,106 @@ struct comm_point {
comm_tcp comm_tcp
} type; } type;
/** what to do when read/write is done. /* ---------- Behaviour ----------- */
/** if set, the connection is closed on error, on timeout,
and after read/write completes. No callback is done. */
int tcp_do_close;
For a query this means it is read in and ready to be processed. /** if set, read/write completes:
After that the buffer will be sent back to client. read/write state of tcp is toggled.
buffer reset/bytecount reset.
this flag cleared.
So that when that is done the callback is called. */
int tcp_do_toggle_rw;
/** callback when done.
tcp_accept does not get called back, is NULL then. tcp_accept does not get called back, is NULL then.
If a timeout happens, callback with timeout=1 is called.
udp frontside: called after readdone. sendafter. If an error happens, callback is called with error set
tcp frontside: called readdone, sendafter. close. nonzero. If nonzero, it is an errno value.
udp behind: called after readdone. No send after. If the connection is closed (by remote end) then the
tcp behind: write done, read done, then called. No send after. callback is called with error set to -1.
declare as: declare as:
int my_callback(struct comm_point*, void* cb_arg, int timeout); int my_callback(struct comm_point* c, void* my_arg,
int timeout, int error);
if the routine returns 0, no answer is sent back. if the routine returns 0, nothing is done.
For TCP handlers after the answer is sent back the fd is closed. Notzero, the buffer will be sent back to client.
If a timeout happens, TCP handler is closed, and callback with For UDP this is done without changing the commpoint.
timeout=1 is called. In TCP it sets write state.
*/ */
int (*)(struct comm_point*, void*) callback; comm_point_callback_t* callback;
/** argument to pass to callback. */ /** argument to pass to callback. */
void *cb_arg; void *cb_arg;
}; };
/**
* Create a new comm base.
* @return: the new comm base. NULL on error.
*/
struct comm_base* comm_base_create();
/**
* Destroy a comm base.
* All comm points must have been deleted.
* @param b: the base to delete.
*/
void comm_base_delete(struct comm_base* b);
/**
* Dispatch the comm base events.
* @param b: the communication to perform.
*/
void comm_base_dispatch(struct comm_base* b);
/**
* Create an UDP comm point. Calls malloc.
* setups the structure with the parameters you provide.
* @param base: in which base to alloc the commpoint.
* @param fd : file descriptor of open UDP socket.
* @param buffer: shared buffer by UDP sockets from this thread.
* @param callback: callback function pointer.
* @param callback_arg: will be passed to your callback function.
* @return: returns the allocated communication point. NULL on error.
* Sets timeout to NULL. Turns off TCP options.
*/
struct comm_point* comm_point_create_udp(struct comm_base *base,
int fd, struct buffer* buffer,
comm_point_callback_t* callback, void* callback_arg);
/**
* Create a TCP listener comm point. Calls malloc.
* Setups the structure with the parameters you provide.
* Also Creates TCP Handlers, pre allocated for you.
* Uses the parameters you provide.
* @param base: in which base to alloc the commpoint.
* @param fd: file descriptor of open TCP socket set to listen nonblocking.
* @param num: becomes max_tcp_count, the routine allocates that
* many tcp handler commpoints.
* @param bufsize: size of buffer to create for handlers.
* @param callback: callback function pointer for TCP handlers.
* @param callback_arg: will be passed to your callback function.
* @return: returns the TCP listener commpoint. You can find the
* TCP handlers in the array inside the listener commpoint.
* returns NULL on error.
* Inits timeout to NULL. All handlers are on the free list.
*/
struct comm_point* comm_point_create_tcp(struct comm_base *base,
int fd, int num, size_t bufsize,
comm_point_callback_t* callback, void* callback_arg);
/**
* Close a comm point fd.
* @param c: comm point to close.
*/
void comm_point_close(struct comm_point* c);
/**
* Close and deallocate (free) the comm point. If the comm point is
* a tcp-accept point, also its tcp-handler points are deleted.
* @param c: comm point to delete.
*/
void comm_point_delete(struct comm_point* c);
#endif /* NET_EVENT_H */ #endif /* NET_EVENT_H */