From: Wouter Wijngaards Date: Thu, 25 Jan 2007 16:08:52 +0000 (+0000) Subject: + - created log_assert, that throws assertions to the logfile. X-Git-Tag: release-0.0~90 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3284b2f6f66eb2c29a1bcaf6001b279d70809794;p=thirdparty%2Funbound.git + - created log_assert, that throws assertions to the logfile. + - listen_dnsport service. Binds ports. git-svn-id: file:///svn/unbound/trunk@35 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/configure.ac b/configure.ac index 8f8d6a0b5..7117bebb2 100644 --- a/configure.ac +++ b/configure.ac @@ -111,7 +111,7 @@ AC_PROG_LIBTOOL # Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([getopt.h stdarg.h stdbool.h netinet/in.h time.h sys/param.h sys/socket.h],,, [AC_INCLUDES_DEFAULT]) +AC_CHECK_HEADERS([getopt.h stdarg.h stdbool.h netinet/in.h time.h sys/param.h sys/socket.h arpa/inet.h],,, [AC_INCLUDES_DEFAULT]) # check for types AC_CHECK_TYPE(int8_t, char) diff --git a/daemon/unbound.c b/daemon/unbound.c index cc708e4a5..b6491392b 100644 --- a/daemon/unbound.c +++ b/daemon/unbound.c @@ -43,14 +43,21 @@ #include "config.h" #include "util/log.h" #include "util/netevent.h" +#include "services/listen_dnsport.h" + +/** default port to listen for queries, passed to getaddrinfo */ +#define UNBOUND_DNS_PORT "53" +/** buffer size for network connections */ +#define BUFSZ 65552 /** print usage. */ static void usage() { printf("usage: unbound [options]\n"); printf("\tstart unbound daemon DNS resolver.\n"); - printf("\t-h\tthis help\n"); - printf("\t-v\tverbose (multiple times increase verbosity)\n"); + printf("-h this help\n"); + printf("-p port the port to listen on\n"); + printf("-v verbose (multiple times increase verbosity)\n"); printf("Version %s\n", PACKAGE_VERSION); printf("BSD licensed, see LICENSE file in source package.\n"); printf("Report bugs to %s.\n", PACKAGE_BUGREPORT); @@ -70,12 +77,21 @@ int main(int argc, char* argv[]) { struct comm_base *base = 0; + struct listen_dnsport* front = 0; + int do_ip4=1, do_ip6=1, do_udp=1, do_tcp=1; + const char* port = UNBOUND_DNS_PORT; int c; log_init(); /* parse the options */ - while( (c=getopt(argc, argv, "hv")) != -1) { + while( (c=getopt(argc, argv, "hvp:")) != -1) { switch(c) { + case 'p': + if(!atoi(optarg)) + fatal_exit("invalid port '%s'", optarg); + port = optarg; + verbose(VERB_ALGO, "using port: %s", port); + break; case 'v': verbosity ++; break; @@ -94,12 +110,20 @@ main(int argc, char* argv[]) return 1; } - log_info("Start of %s.", PACKAGE_STRING); - + /* setup */ base = comm_base_create(); if(!base) - fatal_exit("could not create commbase"); + fatal_exit("could not create event handling base"); + front = listen_create(base, 0, NULL, port, do_ip4, do_ip6, + do_udp, do_tcp, BUFSZ); + if(!front) + fatal_exit("could not create listening sockets"); + + log_info("Start of %s.", PACKAGE_STRING); + /* cleanup */ + verbose(VERB_ALGO, "Exit cleanup."); + listen_delete(front); comm_base_delete(base); return 0; } diff --git a/doc/Changelog b/doc/Changelog index a792750d4..ffcfb1e0e 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -5,6 +5,8 @@ - fixed libevent configure flag. - detects event_base_free() in new libevent 1.2 version. - getopt in daemon. fatal_exit() and verbose() logging funcs. + - created log_assert, that throws assertions to the logfile. + - listen_dnsport service. Binds ports. 24 January 2007: Wouter - cleaned up configure.ac. diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index d80250463..dfb48da06 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -40,4 +40,296 @@ */ #include "services/listen_dnsport.h" +#include "util/netevent.h" +#include "util/log.h" + +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +#include +#include + +/** number of queued TCP connections for listen() */ +#define TCP_BACKLOG 5 +/** number of simultaneous open TCP connections */ +#define TCP_COUNT 10 + +/** callback of comm_point_callback_t for events. */ +static int listen_udp_callback(struct comm_point* cp, void* arg, int error) +{ + return 0; +} + +/** callback of comm_point_callback_t for events. */ +static int listen_tcp_callback(struct comm_point* cp, void* arg, int error) +{ + return 0; +} + +/** + * Debug print of the getaddrinfo returned address. + * @param addr: the address returned. + */ +static void +verbose_print_addr(struct addrinfo *addr) +{ + if(verbosity >= VERB_ALGO) { + char buf[100]; + if(inet_ntop(addr->ai_family, + &((struct sockaddr_in*)addr->ai_addr)->sin_addr, buf, + sizeof(buf)) == 0) { + strncpy(buf, "(null)", sizeof(buf)); + } + verbose(VERB_ALGO, "creating %s %s socket %s %d", + addr->ai_family==AF_INET?"inet": + addr->ai_family==AF_INET6?"inet6":"otherfamily", + addr->ai_socktype==SOCK_DGRAM?"udp": + addr->ai_socktype==SOCK_STREAM?"tcp":"otherprotocol", + buf, + ntohs(((struct sockaddr_in*)addr->ai_addr)->sin_port)); + } +} + +/** + * Create and bind UDP socket + * @param addr: address info ready to make socket. + * @return: the socket. -1 on error. + */ +static int +create_udp_sock(struct addrinfo *addr) +{ + int s, flag; + verbose_print_addr(addr); + if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { + log_err("can't create socket: %s", strerror(errno)); + return -1; + } + if(bind(s, (struct sockaddr*)addr->ai_addr, addr->ai_addrlen) != 0) { + log_err("can't bind socket: %s", strerror(errno)); + return -1; + } + if((flag = fcntl(s, F_GETFL)) == -1) { + log_err("can't fcntl F_GETFL: %s", strerror(errno)); + flag = 0; + } + flag |= O_NONBLOCK; + if(fcntl(s, F_SETFL, flag) == -1) { + log_err("can't fcntl F_SETFL: %s", strerror(errno)); + return -1; + } + return s; +} + +/** + * Create and bind TCP listening socket + * @param addr: address info ready to make socket. + * @return: the socket. -1 on error. + */ +static int +create_tcp_accept_sock(struct addrinfo *addr) +{ + int s, flag; +#ifdef SO_REUSEADDR + int on = 1; +#endif /* SO_REUSEADDR */ + verbose_print_addr(addr); + if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { + log_err("can't create socket: %s", strerror(errno)); + return -1; + } +#ifdef SO_REUSEADDR + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { + log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", + strerror(errno)); + return -1; + } +#endif /* SO_REUSEADDR */ + if(bind(s, (struct sockaddr*)addr->ai_addr, addr->ai_addrlen) != 0) { + log_err("can't bind socket: %s", strerror(errno)); + return -1; + } + if((flag = fcntl(s, F_GETFL)) == -1) { + log_err("can't fcntl F_GETFL: %s", strerror(errno)); + flag = 0; + } + flag |= O_NONBLOCK; + if(fcntl(s, F_SETFL, flag) == -1) { + log_err("can't fcntl F_SETFL: %s", strerror(errno)); + return -1; + } + if(listen(s, TCP_BACKLOG) == -1) { + log_err("can't listen: %s", strerror(errno)); + return -1; + } + return s; +} + +/** + * Create socket from getaddrinfo results + */ +static int +make_sock(int stype, const char* ifname, const char* port, + struct addrinfo *hints) +{ + struct addrinfo *res = NULL; + int r, s; + hints->ai_socktype = stype; + if((r=getaddrinfo(ifname, port, hints, &res)) != 0 || !res) { + log_err("node %s:%s getaddrinfo: %s %s", + ifname?ifname:"default", port, gai_strerror(r), + r==EAI_SYSTEM?strerror(errno):""); + return -1; + } + if(stype == SOCK_DGRAM) + s = create_udp_sock(res); + else s = create_tcp_accept_sock(res); + freeaddrinfo(res); + return s; +} + +/** + * Helper for listen_create. Creates one interface (or NULL for default). + * @param ifname: The interface ip address. + * @param front: The the listening info. + * @param base: Event base. + * @param port: Port number to use (as string). + * @param do_udp: if udp should be used. + * @param do_tcp: if udp should be used. + * @param hints: for getaddrinfo. family and flags have to be set by caller. + * @param bufsize: TCP buffer size. + * @return: returns false on error. + */ +static int +listen_create_if(const char* ifname, struct listen_dnsport* front, + struct comm_base* base, const char* port, int do_udp, int do_tcp, + struct addrinfo *hints, size_t bufsize) +{ + struct comm_point *cp_udp = NULL, *cp_tcp = NULL; + struct listen_list *el_udp, *el_tcp; + int s; + if(!do_udp && !do_tcp) + return 0; + if(do_udp) { + if((s = make_sock(SOCK_DGRAM, ifname, port, hints)) == -1) + return 0; + cp_udp = comm_point_create_udp(base, s, front->udp_buff, + listen_udp_callback, front); + if(!cp_udp) { + log_err("can't create commpoint"); + close(s); + return 0; + } + } + if(do_tcp) { + if((s = make_sock(SOCK_STREAM, ifname, port, hints)) == -1) { + comm_point_delete(cp_udp); + return 0; + } + cp_tcp = comm_point_create_tcp(base, s, TCP_COUNT, bufsize, + listen_tcp_callback, front); + if(!cp_tcp) { + log_err("can't create commpoint"); + comm_point_delete(cp_udp); + return 0; + } + } + /* add commpoints to the listen structure */ + el_udp = (struct listen_list*)malloc(sizeof(struct listen_list)); + if(!el_udp) { + log_err("out of memory"); + comm_point_delete(cp_udp); + comm_point_delete(cp_tcp); + return 0; + } + el_tcp = (struct listen_list*)malloc(sizeof(struct listen_list)); + if(!el_tcp) { + log_err("out of memory"); + free(el_udp); + comm_point_delete(cp_udp); + comm_point_delete(cp_tcp); + return 0; + } + el_udp->com = cp_udp; + el_udp->next = front->cps; + front->cps = el_udp; + comm_point_set_cb_arg(el_udp->com, el_udp); + el_tcp->com = cp_tcp; + el_tcp->next = front->cps; + front->cps = el_tcp; + comm_point_set_cb_arg(el_tcp->com, el_tcp); + return 1; +} + +struct listen_dnsport* +listen_create(struct comm_base* base, int num_ifs, const char* ifs[], + const char* port, int do_ip4, int do_ip6, int do_udp, int do_tcp, + size_t bufsize) +{ + struct addrinfo hints; + int i; + struct listen_dnsport* front = (struct listen_dnsport*) + malloc(sizeof(struct listen_dnsport)); + if(!front) + return NULL; + front->cps = NULL; + front->udp_buff = ldns_buffer_new(bufsize); + if(!front->udp_buff) { + free(front); + return NULL; + } + + /* getaddrinfo */ + memset(&hints, 0, sizeof(hints)); + + hints.ai_flags = AI_PASSIVE; + /* no name lookups on our listening ports */ + if(num_ifs > 0) + hints.ai_flags |= AI_NUMERICHOST; + + hints.ai_family = AF_UNSPEC; + if(!do_ip4 && !do_ip6) { + listen_delete(front); + return NULL; + } else if(do_ip4 && do_ip6) + hints.ai_family = AF_UNSPEC; + else if(do_ip4) + hints.ai_family = AF_INET; + else if(do_ip6) { + hints.ai_family = AF_INET6; + } + + if(num_ifs == 0) { + if(!listen_create_if(NULL, front, base, port, + do_udp, do_tcp, &hints, bufsize)) { + listen_delete(front); + return NULL; + } + } else for(i = 0; icps; + while(p) { + pn = p->next; + comm_point_delete(p->com); + free(p); + p = pn; + } + ldns_buffer_free(front->udp_buff); + free(front); +} diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index 940180c74..9c1511017 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -44,6 +44,7 @@ #include "config.h" struct comm_base; +struct listen_list; /** * Listening for queries structure. @@ -52,6 +53,23 @@ struct comm_base; struct listen_dnsport { /** Base for select calls */ struct comm_base* base; + + /** buffer shared by UDP connections, since there is only one + datagram at any time. */ + ldns_buffer* udp_buff; + + /** list of comm points used to get incoming events */ + struct listen_list *cps; +}; + +/** + * Single linked list to store event points. + */ +struct listen_list { + /** next in list */ + struct listen_list *next; + /** event info */ + struct comm_point *com; }; /** @@ -67,11 +85,13 @@ struct listen_dnsport { * @param do_ip6: listen to ip6 queries. * @param do_udp: listen to udp queries. * @param do_tcp: listen to tcp queries. - * @return: the malloced listening structure, ready for use. + * @param bufsize: size of datagram buffer. + * @return: the malloced listening structure, ready for use. NULL on error. */ struct listen_dnsport* listen_create(struct comm_base* base, - int num_ifs, const char* ifs[], int port, - int do_ip4, int do_ip6, int do_udp, int do_tcp); + int num_ifs, const char* ifs[], const char* port, + int do_ip4, int do_ip6, int do_udp, int do_tcp, + size_t bufsize); /** * delete the listening structure diff --git a/util/log.h b/util/log.h index 1c3c5405b..643c68297 100644 --- a/util/log.h +++ b/util/log.h @@ -108,4 +108,19 @@ void fatal_exit(const char* format, ...) ATTR_FORMAT(printf, 1, 2); */ void log_vmsg(const char* type, const char *format, va_list args); +/** always assert for now. */ +#define UNBOUND_ASSERT 1 +/** + * an assertion that is thrown to the logfile. + */ +#ifdef UNBOUND_ASSERT +# define log_assert(x) \ + do { if(!(x)) \ + fatal_exit("%s:%d: %s: assertion %s failed", \ + __FILE__, __LINE__, __func__, #x); \ + } while(0); +#else +# define log_assert(x) /*nothing*/ +#endif + #endif /* UTIL_LOG_H */ diff --git a/util/netevent.c b/util/netevent.c index b96d34550..246198dbe 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -325,12 +325,13 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, 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"); } + /* close fd after removing from event lists, or epoll/etc messes up */ + if(c->fd != -1) + close(c->fd); + c->fd = -1; } void @@ -345,7 +346,15 @@ comm_point_delete(struct comm_point* c) comm_point_delete(c->tcp_handlers[i]); free(c->tcp_handlers); } + if(c->type == comm_tcp) + ldns_buffer_free(c->buffer); free(c->ev); free(c); } +void +comm_point_set_cb_arg(struct comm_point* c, void *arg) +{ + log_assert(c); + c->cb_arg = arg; +} diff --git a/util/netevent.h b/util/netevent.h index e9774fa9c..3360b8702 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -225,4 +225,11 @@ void comm_point_close(struct comm_point* c); */ void comm_point_delete(struct comm_point* c); +/** + * Reset the callback argument for a comm point. + * @param c: the comm point to change. + * @param arg: the new callback user argument. + */ +void comm_point_set_cb_arg(struct comm_point* c, void *arg); + #endif /* NET_EVENT_H */