unbound: $(COMMON_OBJ) $(DAEMON_OBJ)
$(INFO) Link $@
- $Q$(LINK) -o $@ $^
+ $Q$(LINK) -o $@ $^ $(LIBS)
unittest: $(COMMON_OBJ) $(UNITTEST_OBJ)
$(INFO) Link $@
- $Q$(LINK) -o $@ $^
+ $Q$(LINK) -o $@ $^ $(LIBS)
clean:
rm -f *.o *.d *.lo *~ tags
# check to see if libraries are needed for these functions.
AC_CHECK_LIB(socket, socket)
AC_CHECK_LIB(nsl, inet_pton)
+AC_CHECK_LIB(event, event_set)
AC_FUNC_MALLOC
+23 January 2007: Wouter
+ - added libevent to configure to link with.
+ - util/netevent setup work.
+
22 January 2007: Wouter
- Designed header file for network communication.
0.8 Library use - resolver validator lib (and test apps)
0.9 Corner cases - be able to resolve in the wild. Run fuzzers.
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.
For boxes 0.5-1.0 the planning is to be revised, at the 0.5 stage external
}
void
-log_vmsg(const char *format, va_list args)
+log_vmsg(const char* type, const char *format, va_list args)
{
char message[MAXSYSLOGMSGLEN];
const char* ident="unbound";
vsnprintf(message, sizeof(message), format, args);
- fprintf(stderr, "[%d] %s[%d]: %s\n",
- (int)time(NULL), ident, (int)getpid(), message);
+ fprintf(stderr, "[%d] %s[%d] %s: %s\n",
+ (int)time(NULL), ident, (int)getpid(), type, message);
}
/**
{
va_list args;
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);
}
void log_init();
/**
+ * Log informational message.
* Pass printf formatted arguments. No trailing newline is needed.
* @param format: printf-style format string. Arguments follow.
*/
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.
+ * @param type: string to designate type of message (info, error).
* @param format: the printf style format to print. no newline.
* @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 */
--- /dev/null
+/*
+ * 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);
+}
+
#include "config.h"
struct buffer;
-/** internal event notification data storage structure. */
+/* internal event notification data storage structure. */
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 {
/** behind the scenes structure, with say libevent info. alloced. */
struct internal_event* ev;
/** The current read/write count for TCP */
size_t tcp_byte_count;
/** parent communication point (for TCP sockets) */
- struct comm_point tcp_parent;
+ struct comm_point *tcp_parent;
/* -------- TCP Accept -------- */
/** current number of TCP connections on this socket */
int max_tcp_count;
/** malloced array of tcp handlers for a tcp-accept,
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.
For tcp_accept the first entry, for tcp_handlers the next one. */
struct comm_point *tcp_free;
comm_tcp
} 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.
- After that the buffer will be sent back to client.
- tcp_accept does not get called back, is NULL then.
+ /** if set, read/write completes:
+ 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;
- 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.
+ /** callback when done.
+ tcp_accept does not get called back, is NULL then.
+ If a timeout happens, callback with timeout=1 is called.
+ If an error happens, callback is called with error set
+ nonzero. If nonzero, it is an errno value.
+ If the connection is closed (by remote end) then the
+ callback is called with error set to -1.
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.
- For TCP handlers after the answer is sent back the fd is closed.
- If a timeout happens, TCP handler is closed, and callback with
- timeout=1 is called.
+ if the routine returns 0, nothing is done.
+ Notzero, the buffer will be sent back to client.
+ For UDP this is done without changing the commpoint.
+ In TCP it sets write state.
*/
- int (*)(struct comm_point*, void*) callback;
+ comm_point_callback_t* callback;
/** argument to pass to callback. */
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 */