]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
+ - created log_assert, that throws assertions to the logfile.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 25 Jan 2007 16:08:52 +0000 (16:08 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 25 Jan 2007 16:08:52 +0000 (16:08 +0000)
+       - listen_dnsport service. Binds ports.

git-svn-id: file:///svn/unbound/trunk@35 be551aaa-1e26-0410-a405-d3ace91eadb9

configure.ac
daemon/unbound.c
doc/Changelog
services/listen_dnsport.c
services/listen_dnsport.h
util/log.h
util/netevent.c
util/netevent.h

index 8f8d6a0b50b77ee90bec4de59c5cc7fb25d697ba..7117bebb2936d7364f364c33e80ae91cca8a0f6c 100644 (file)
@@ -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)
index cc708e4a578efa3025da4ddae77340e3684e0967..b6491392b0528dc68e9a91a85ff8cb8f5be5a18c 100644 (file)
 #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;
 }
index a792750d44ea84823d3de15c76b96297ee1d6943..ffcfb1e0e6783bcb0b5e737236cd26b19fb87514 100644 (file)
@@ -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.
index d8025046360a47d6ff145776269cbf2ad951fdaf..dfb48da067bc0455c7c9ddfcbdb2319a68e4c1dc 100644 (file)
  */
 
 #include "services/listen_dnsport.h"
+#include "util/netevent.h"
+#include "util/log.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+#include <netdb.h>
+#include <errno.h>
+#include <fcntl.h>
+
+/** 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; i<num_ifs; i++) {
+               if(!listen_create_if(ifs[i], front, base, port, 
+                       do_udp, do_tcp, &hints, bufsize)) {
+                       listen_delete(front);
+                       return NULL;
+               }
+       }
+
+       return front;
+}
+
+void 
+listen_delete(struct listen_dnsport* front)
+{
+       struct listen_list *p, *pn;
+       if(!front) 
+               return;
+       p = front->cps;
+       while(p) {
+               pn = p->next;
+               comm_point_delete(p->com);
+               free(p);
+               p = pn;
+       }
+       ldns_buffer_free(front->udp_buff);
+       free(front);
+}
 
index 940180c74e68a7cdd033c03dd1cdd203f37d5ea4..9c1511017709e15bd01c44107158d1df00ffcdb4 100644 (file)
@@ -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
index 1c3c5405b5359fb578a31607e92d3374775f2f28..643c682977deef3fb143e08ac800444c44453cfb 100644 (file)
@@ -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 */
index b96d345509082b902018be032faa2996a526c671..246198dbe104776a892e62ef1862b1440cc264fa 100644 (file)
@@ -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;
+}
index e9774fa9cd0603bd6505cf71e8bc0848ab8ff987..3360b870200cd9a4b4a3d87a7326f73a1bee1c13 100644 (file)
@@ -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 */