From: Wouter Wijngaards Date: Fri, 23 Feb 2007 10:04:50 +0000 (+0000) Subject: Ports are shared and you can kill -HUP to do a reload (of config file). X-Git-Tag: release-0.1~34 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=84053077eb00eb4279b6062a876ce0c370bb5175;p=thirdparty%2Funbound.git Ports are shared and you can kill -HUP to do a reload (of config file). git-svn-id: file:///svn/unbound/trunk@137 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/daemon.c b/daemon/daemon.c index a2bc58abd..39c3d1c82 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -83,14 +83,17 @@ daemon_fork(struct daemon* daemon) daemon->num = 1; daemon->workers = (struct worker**)calloc((size_t)daemon->num, sizeof(struct worker*)); - if(!(daemon->workers[0] = worker_init(daemon->cfg, BUFSZ))) + if(!(daemon->workers[0] = worker_init(daemon->cfg, daemon->ports, + BUFSZ))) fatal_exit("could not initialize thread # %d", 0); daemon->workers[0]->daemon = daemon; daemon->workers[0]->thread_num = 0; log_info("start of service (%s).", PACKAGE_STRING); worker_work(daemon->workers[0]); - daemon->need_to_exit = 1; + if(daemon->workers[0]->need_to_restart) + daemon->need_to_exit = 0; + else daemon->need_to_exit = 1; } void diff --git a/daemon/worker.c b/daemon/worker.c index b4d46e9ed..87b5a430a 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -191,6 +191,7 @@ worker_sighandler(int sig, void* arg) switch(sig) { case SIGHUP: log_info("caught signal SIGHUP"); + worker->need_to_restart = 1; comm_base_exit(worker->base); break; case SIGINT: @@ -208,12 +209,14 @@ worker_sighandler(int sig, void* arg) } struct worker* -worker_init(struct config_file *cfg, size_t buffer_size) +worker_init(struct config_file *cfg, struct listen_port* ports, + size_t buffer_size) { struct worker* worker = (struct worker*)calloc(1, sizeof(struct worker)); if(!worker) return NULL; + worker->need_to_restart = 0; worker->base = comm_base_create(); if(!worker->base) { log_err("could not create event handling base"); @@ -229,8 +232,7 @@ worker_init(struct config_file *cfg, size_t buffer_size) worker_delete(worker); return NULL; } - worker->front = listen_create(worker->base, 0, NULL, cfg->port, - cfg->do_ip4, cfg->do_ip6, cfg->do_udp, cfg->do_tcp, + worker->front = listen_create(worker->base, ports, buffer_size, worker_handle_request, worker); if(!worker->front) { log_err("could not create listening sockets"); diff --git a/daemon/worker.h b/daemon/worker.h index c0d167109..7458e0a2a 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -50,6 +50,7 @@ struct listen_dnsport; struct outside_network; struct config_file; struct daemon; +struct listen_port; /** size of table used for random numbers. large to be more secure. */ #define RND_STATE_SIZE 256 @@ -86,16 +87,20 @@ struct worker { /** random() table for this worker. */ char* rndstate; + /** do we need to restart (instead of exit) ? */ + int need_to_restart; }; /** * Initialize worker. * Allocates event base, listens to ports * @param cfg: configuration settings. + * @param ports: list of shared query ports. * @param buffer_size: size of datagram buffer. * @return: The worker, or NULL on error. */ -struct worker* worker_init(struct config_file *cfg, size_t buffer_size); +struct worker* worker_init(struct config_file *cfg, struct listen_port* ports, + size_t buffer_size); /** * Make worker work. diff --git a/doc/Changelog b/doc/Changelog index 43d0511a2..bc6128864 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,9 @@ +23 February 2007: Wouter + - Can do reloads on sigHUP. Everything is stopped, and freed, + except the listening ports. Then the config file is reread. + And everything is started again (and listening ports if needed). + - Ports for queries are shared. + 22 February 2007: Wouter - Have a config file. Removed commandline options, moved to config. - tests use config file. diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index ce00bbaa0..f44c49ea3 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -43,6 +43,7 @@ #include "services/outside_network.h" #include "util/netevent.h" #include "util/log.h" +#include "util/config_file.h" #include "util/net_help.h" #ifdef HAVE_SYS_TYPES_H @@ -218,93 +219,90 @@ make_sock(int stype, const char* ifname, const char* port, } /** - * Helper for listen_create. Creates one interface (or NULL for default). + * Add port to open ports list. + * @param list: list head. changed. + * @param s: fd. + * @param is_udp: if fd is UDP. + * @return false on failure. list in unchanged then. + */ +static int +port_insert(struct listen_port** list, int s, int is_udp) +{ + struct listen_port* item = (struct listen_port*)malloc( + sizeof(struct listen_port)); + if(!item) + return 0; + item->next = *list; + item->fd = s; + item->is_udp = is_udp; + *list = item; + return 1; +} + +/** + * Helper for ports_open. 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. - * @param cb: callback function - * @param cb_arg: user parameter for callback function. + * @param port: Port number to use (as string). + * @param list: list of open ports, appended to, changed to point to list head. * @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, comm_point_callback_t* cb, - void *cb_arg) +ports_create_if(const char* ifname, int do_udp, int do_tcp, + struct addrinfo *hints, const char* port, struct listen_port** list) { - 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, - cb, cb_arg); - if(!cp_udp) { - log_err("can't create commpoint"); + if(!port_insert(list, s, 1)) { 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, - cb, cb_arg); - if(!cp_tcp) { - log_err("can't create commpoint"); - comm_point_delete(cp_udp); + if(!port_insert(list, s, 0)) { close(s); 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 1; +} + +/** + * Add items to commpoint list in front. + * @param c: commpoint to add. + * @param front: listen struct. + * @return: false on failure. + */ +static int +listen_cp_insert(struct comm_point* c, struct listen_dnsport* front) +{ + struct listen_list* item = (struct listen_list*)malloc( + sizeof(struct listen_list)); + if(!item) return 0; - } - el_udp->com = cp_udp; - el_udp->next = front->cps; - front->cps = el_udp; - el_tcp->com = cp_tcp; - el_tcp->next = front->cps; - front->cps = el_tcp; + item->com = c; + item->next = front->cps; + front->cps = item; return 1; } 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, +listen_create(struct comm_base* base, struct listen_port* ports, size_t bufsize, comm_point_callback_t* cb, void *cb_arg) { - struct addrinfo hints; - int i; - char portbuf[10]; struct listen_dnsport* front = (struct listen_dnsport*) malloc(sizeof(struct listen_dnsport)); if(!front) return NULL; - snprintf(portbuf, sizeof(portbuf), "%d", port); front->cps = NULL; front->udp_buff = ldns_buffer_new(bufsize); if(!front->udp_buff) { @@ -312,93 +310,128 @@ listen_create(struct comm_base* base, int num_ifs, const char* ifs[], return NULL; } + /* create comm points as needed */ + while(ports) { + struct comm_point* cp = NULL; + if(ports->is_udp) + cp = comm_point_create_udp(base, ports->fd, + front->udp_buff, cb, cb_arg); + else cp = comm_point_create_tcp(base, ports->fd, + TCP_COUNT, bufsize, cb, cb_arg); + if(!cp) { + log_err("can't create commpoint"); + listen_delete(front); + return NULL; + } + cp->do_not_close = 1; + if(!listen_cp_insert(cp, front)) { + log_err("malloc failed"); + comm_point_delete(cp); + listen_delete(front); + return NULL; + } + ports = ports->next; + } + if(!front->cps) { + log_err("Could not open sockets to accept queries."); + 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); +} + +struct listen_port* +listening_ports_open(struct config_file* cfg) +{ + struct listen_port* list = NULL; + struct addrinfo hints; + int i, do_ip4, do_ip6; + char portbuf[32]; + snprintf(portbuf, sizeof(portbuf), "%d", cfg->port); + do_ip4 = cfg->do_ip4; + do_ip6 = cfg->do_ip6; + /* getaddrinfo */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; /* no name lookups on our listening ports */ - if(num_ifs > 0) + if(cfg->num_ifs > 0) hints.ai_flags |= AI_NUMERICHOST; hints.ai_family = AF_UNSPEC; #ifndef INET6 do_ip6 = 0; #endif if(!do_ip4 && !do_ip6) { - listen_delete(front); return NULL; } - /* create ip4 and ip6 ports so that return addresses are nice. */ - if(num_ifs == 0) { + if(cfg->num_ifs == 0) { if(do_ip6) { hints.ai_family = AF_INET6; - if(!listen_create_if(NULL, front, base, portbuf, - do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) { - listen_delete(front); + if(!ports_create_if(NULL, cfg->do_udp, cfg->do_tcp, + &hints, portbuf, &list)) { + listening_ports_free(list); return NULL; } } if(do_ip4) { hints.ai_family = AF_INET; - if(!listen_create_if(NULL, front, base, portbuf, - do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) { - listen_delete(front); + if(!ports_create_if(NULL, cfg->do_udp, cfg->do_tcp, + &hints, portbuf, &list)) { + listening_ports_free(list); return NULL; } } - } else for(i = 0; inum_ifs; i++) { + if(str_is_ip6(cfg->ifs[i])) { if(!do_ip6) continue; hints.ai_family = AF_INET6; - if(!listen_create_if(ifs[i], front, base, portbuf, - do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) { - listen_delete(front); + if(!ports_create_if(cfg->ifs[i], cfg->do_udp, + cfg->do_tcp, &hints, portbuf, &list)) { + listening_ports_free(list); return NULL; } } else { if(!do_ip4) continue; hints.ai_family = AF_INET; - if(!listen_create_if(ifs[i], front, base, portbuf, - do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) { - listen_delete(front); + if(!ports_create_if(cfg->ifs[i], cfg->do_udp, + cfg->do_tcp, &hints, portbuf, &list)) { + listening_ports_free(list); return NULL; } } } - if(!front->cps) { - log_err("Could not open sockets to accept queries."); - 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); -} - -struct listen_port* -listening_ports_open(struct config_file* cfg) -{ - return calloc(1,1); + return list; } void listening_ports_free(struct listen_port* list) { - free(list); + struct listen_port* nx; + while(list) { + nx = list->next; + if(list->fd != -1) + close(list->fd); + free(list); + list = nx; + } } diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index 3b644fe43..ce774697a 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -89,6 +89,9 @@ struct listen_port { /** * Create shared listening ports + * Getaddrinfo, create socket, bind and listen to zero or more + * interfaces for IP4 and/or IP6, for UDP and/or TCP. + * On the given port number. It creates the sockets. * @param cfg: settings on what ports to open. * @return: linked list of ports or NULL on error. */ @@ -100,18 +103,10 @@ struct listen_port* listening_ports_open(struct config_file* cfg); void listening_ports_free(struct listen_port* list); /** - * Getaddrinfo, create socket, bind and listen to zero or more - * interfaces for IP4 and/or IP6, for UDP and/or TCP. - * On the given port number. It creates the listening sockets. + * Create commpoints with for this thread for the shared ports. * @param base: the comm_base that provides event functionality. - * @param num_ifs: number of interfaces to listen on. Can be 0, * for default all ifs. - * @param ifs: array of strings with interface specs, IP addresses. - * @param port: the port number to bind to. - * @param do_ip4: listen to ip4 queries. - * @param do_ip6: listen to ip6 queries. - * @param do_udp: listen to udp queries. - * @param do_tcp: listen to tcp queries. + * @param ports: the list of shared ports. * @param bufsize: size of datagram buffer. * @param cb: callback function when a request arrives. It is passed * the packet and user argument. Return true to send a reply. @@ -119,9 +114,8 @@ void listening_ports_free(struct listen_port* list); * @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, - size_t bufsize, comm_point_callback_t* cb, void* cb_arg); + struct listen_port* ports, size_t bufsize, + comm_point_callback_t* cb, void* cb_arg); /** * delete the listening structure diff --git a/services/outside_network.c b/services/outside_network.c index 7a75ef4df..1c24a9bd7 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -164,7 +164,7 @@ open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint) { struct addrinfo *res = NULL; int r, s; - char portstr[20]; + char portstr[32]; if(porthint != -1) snprintf(portstr, sizeof(portstr), "%d", porthint); diff --git a/testcode/fake_event.c b/testcode/fake_event.c index d6132d421..839646bf7 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -479,10 +479,7 @@ run_scenario(struct replay_runtime* runtime) /*********** Dummy routines ***********/ struct listen_dnsport* -listen_create(struct comm_base* base, int ATTR_UNUSED(num_ifs), - const char* ATTR_UNUSED(ifs[]), int ATTR_UNUSED(port), - int ATTR_UNUSED(do_ip4), int ATTR_UNUSED(do_ip6), - int ATTR_UNUSED(do_udp), int ATTR_UNUSED(do_tcp), +listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports), size_t bufsize, comm_point_callback_t* cb, void* cb_arg) { struct replay_runtime* runtime = (struct replay_runtime*)base; diff --git a/util/config_file.c b/util/config_file.c index 0c2660476..0db8d067b 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -91,6 +91,8 @@ config_create() } cfg->fwd_port = UNBOUND_DNS_PORT; cfg->do_daemonize = 0; + cfg->num_ifs = 0; + cfg->ifs = NULL; return cfg; } @@ -104,6 +106,7 @@ create_cfg_parser(struct config_file* cfg, char* filename) cfg_parser->line = 1; cfg_parser->errors = 0; cfg_parser->cfg = cfg; + cfg_parser->server_settings_seen = 0; } int diff --git a/util/config_file.h b/util/config_file.h index 42e2d7ebf..546486638 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -74,6 +74,11 @@ struct config_file { /** forwarder port */ int fwd_port; + /** number of interfaces to open. If 0 default all interfaces. */ + int num_ifs; + /** interface description strings (IP addresses) */ + char **ifs; + /** chrootdir, if not "" or chroot will be done */ char* chrootdir; /** username to change to, if not "". */ @@ -115,6 +120,8 @@ struct config_parser_state { int errors; /** the result of parsing is stored here. */ struct config_file* cfg; + /** has server: already been seen. */ + int server_settings_seen; }; /** global config parser object used during config parsing */ diff --git a/util/configparser.y b/util/configparser.y index 3632062b8..7dd8bbdde 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -52,7 +52,6 @@ void ub_c_error(const char *message); /* these need to be global, otherwise they cannot be used inside yacc */ extern struct config_parser_state* cfg_parser; -static int server_settings_seen = 0; #if 0 #define OUTYY(s) printf s /* used ONLY when debugging */ @@ -80,10 +79,10 @@ toplevelvar: serverstart contents_server ; /* server: declaration */ serverstart: VAR_SERVER { OUTYY(("\nP(server:)\n")); - if(server_settings_seen) { + if(cfg_parser->server_settings_seen) { yyerror("duplicate server: element."); } - server_settings_seen = 1; + cfg_parser->server_settings_seen = 1; } ; contents_server: contents_server content_server | ; diff --git a/util/netevent.c b/util/netevent.c index 36789131f..f0a895835 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -516,6 +516,7 @@ comm_point_create_udp(struct comm_base *base, int fd, ldns_buffer* buffer, c->tcp_free = NULL; c->type = comm_udp; c->tcp_do_close = 0; + c->do_not_close = 0; c->tcp_do_toggle_rw = 0; c->callback = callback; c->cb_arg = callback_arg; @@ -569,6 +570,7 @@ comm_point_create_tcp_handler(struct comm_base *base, c->tcp_free = NULL; c->type = comm_tcp; c->tcp_do_close = 0; + c->do_not_close = 0; c->tcp_do_toggle_rw = 0; c->callback = callback; c->cb_arg = callback_arg; @@ -623,6 +625,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, c->tcp_free = NULL; c->type = comm_tcp_accept; c->tcp_do_close = 0; + c->do_not_close = 0; c->tcp_do_toggle_rw = 0; c->callback = NULL; c->cb_arg = NULL; @@ -659,7 +662,7 @@ comm_point_close(struct comm_point* c) log_err("could not event_del on close"); } /* close fd after removing from event lists, or epoll.. is messed up */ - if(c->fd != -1) + if(c->fd != -1 && !c->do_not_close) close(c->fd); c->fd = -1; } diff --git a/util/netevent.h b/util/netevent.h index 9822936ea..9b3098b6f 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -139,6 +139,9 @@ struct comm_point { } type; /* ---------- Behaviour ----------- */ + /** if set the connection is NOT closed on delete. */ + int do_not_close; + /** if set, the connection is closed on error, on timeout, and after read/write completes. No callback is done. */ int tcp_do_close;