daemon code.

git-svn-id: file:///svn/unbound/trunk@136 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-02-22 16:22:54 +00:00
parent 618ef6acbb
commit d5de0d10d5
12 changed files with 382 additions and 34 deletions

View file

@ -57,7 +57,7 @@ UNITTEST_SRC=testcode/unitmain.c $(COMMON_SRC)
UNITTEST_OBJ=$(addprefix $(BUILD),$(UNITTEST_SRC:.c=.o)) $(COMPAT_OBJ)
DAEMON_SRC=$(wildcard daemon/*.c) $(COMMON_SRC)
DAEMON_OBJ=$(addprefix $(BUILD),$(DAEMON_SRC:.c=.o)) $(COMPAT_OBJ)
TESTBOUND_SRC=testcode/testbound.c testcode/ldns-testpkts.c daemon/worker.c testcode/replay.c testcode/fake_event.c $(filter-out util/netevent.c services/listen_dnsport.c services/outside_network.c, $(COMMON_SRC))
TESTBOUND_SRC=testcode/testbound.c testcode/ldns-testpkts.c daemon/worker.c daemon/daemon.c testcode/replay.c testcode/fake_event.c $(filter-out util/netevent.c services/listen_dnsport.c services/outside_network.c, $(COMMON_SRC))
TESTBOUND_OBJ=$(addprefix $(BUILD),$(TESTBOUND_SRC:.c=.o)) $(COMPAT_OBJ)
ALL_SRC=$(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) $(TESTBOUND_SRC)
ALL_OBJ=$(addprefix $(BUILD),$(ALL_SRC:.c=.o) $(addprefix compat/,$(LIBOBJS))) $(COMPAT_OBJ)

117
daemon/daemon.c Normal file
View file

@ -0,0 +1,117 @@
/*
* daemon/daemon.c - collection of workers that handles requests.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* The daemon consists of global settings and a number of workers.
*/
/** buffer size for network connections */
#define BUFSZ 65552
#include "config.h"
#include "daemon/daemon.h"
#include "daemon/worker.h"
#include "util/log.h"
#include "util/config_file.h"
#include "services/listen_dnsport.h"
struct daemon*
daemon_init()
{
struct daemon* daemon = (struct daemon*)calloc(1,
sizeof(struct daemon));
if(!daemon)
return NULL;
lock_basic_init(&daemon->lock);
daemon->need_to_exit = 0;
return daemon;
}
int
daemon_open_shared_ports(struct daemon* daemon, struct config_file* cfg)
{
log_assert(daemon);
daemon->cfg = cfg;
if(daemon->cfg->port == daemon->listening_port)
return 1;
listening_ports_free(daemon->ports);
if(!(daemon->ports=listening_ports_open(daemon->cfg)))
return 0;
daemon->listening_port = daemon->cfg->port;
return 1;
}
void
daemon_fork(struct daemon* daemon)
{
/* only one thread for now */
log_assert(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)))
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;
}
void
daemon_cleanup(struct daemon* daemon)
{
int i;
log_assert(daemon);
for(i=0; i<daemon->num; i++)
worker_delete(daemon->workers[i]);
free(daemon->workers);
daemon->workers = NULL;
daemon->num = 0;
daemon->cfg = NULL;
}
void
daemon_delete(struct daemon* daemon)
{
if(!daemon)
return;
listening_ports_free(daemon->ports);
lock_basic_destroy(&daemon->lock);
free(daemon);
}

104
daemon/daemon.h Normal file
View file

@ -0,0 +1,104 @@
/*
* daemon/daemon.h - collection of workers that handles requests.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* The daemon consists of global settings and a number of workers.
*/
#ifndef DAEMON_H
#define DAEMON_H
#include "util/locks.h"
struct config_file;
struct worker;
struct listen_port;
/**
* Structure holding worker list.
* Holds globally visible information.
*/
struct daemon {
/** mutex for exclusive access to this structure. */
lock_basic_t lock;
/** The config settings */
struct config_file* cfg;
/** port number that has ports opened. */
int listening_port;
/** listening ports, opened, to be shared by threads */
struct listen_port* ports;
/** num threads allocated */
int num;
/** the worker entries */
struct worker** workers;
/** do we need to exit unbound (or is it only a reload?) */
int need_to_exit;
};
/**
* Initialize daemon structure.
* @return: The daemon structure, or NULL on error.
*/
struct daemon* daemon_init();
/**
* Open shared listening ports (if needed).
* @param daemon: the daemon.
* @param cfg: the cfg settings. Applied to daemon.
* @return: false on error.
*/
int daemon_open_shared_ports(struct daemon* daemon, struct config_file* cfg);
/**
* Fork workers and start service.
* When the routine exits, it is no longer forked.
* @param daemon: the daemon.
*/
void daemon_fork(struct daemon* daemon);
/**
* Close off the worker thread information.
* Bring the daemon back into state ready for daemon_fork again.
* @param daemon: the daemon.
*/
void daemon_cleanup(struct daemon* daemon);
/**
* Delete worker.
*/
void daemon_delete(struct daemon* daemon);
#endif /* DAEMON_H */

View file

@ -42,11 +42,10 @@
#include "config.h"
#include "util/log.h"
#include "daemon/worker.h"
#include "daemon/daemon.h"
#include "util/config_file.h"
/** buffer size for network connections */
#define BUFSZ 65552
#include <fcntl.h>
#include <pwd.h>
/** print usage. */
static void usage()
@ -61,6 +60,51 @@ static void usage()
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
}
/** daemonize, drop user priviliges and chroot if needed */
static void
do_chroot(struct config_file* cfg)
{
log_assert(cfg);
/* daemonize last to be able to print error to user */
if(cfg->chrootdir && cfg->chrootdir[0])
if(chroot(cfg->chrootdir))
fatal_exit("unable to chroot: %s", strerror(errno));
if(cfg->username && cfg->username[0]) {
struct passwd *pwd;
if((pwd = getpwnam(cfg->username)) == NULL)
fatal_exit("user '%s' does not exist.", cfg->username);
if(setgid(pwd->pw_gid) != 0)
fatal_exit("unable to set group id: %s", strerror(errno));
if(setuid(pwd->pw_uid) != 0)
fatal_exit("unable to set user id: %s", strerror(errno));
endpwent();
}
if(cfg->do_daemonize) {
int fd;
/* Take off... */
switch (fork()) {
case 0:
break;
case -1:
fatal_exit("fork failed: %s", strerror(errno));
default:
/* exit interactive session */
exit(0);
}
/* detach */
if(setsid() == -1)
fatal_exit("setsid() failed: %s", strerror(errno));
if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)close(fd);
}
}
}
/**
* Run the daemon.
* @param cfgfile: the config file name.
@ -69,35 +113,41 @@ static void usage()
*/
static void run_daemon(const char* cfgfile, int cmdline_verbose)
{
struct worker* worker = NULL;
struct config_file *cfg = NULL;
struct config_file* cfg = NULL;
struct daemon* daemon = NULL;
int done_chroot = 0;
if(!(cfg = config_create())) {
fprintf(stderr, "Could not init config defaults.");
exit(1);
}
if(cfgfile) {
if(!config_read(cfg, cfgfile)) {
config_delete(cfg);
exit(1);
}
if(!(daemon = daemon_init()))
fatal_exit("alloc failure");
while(!daemon->need_to_exit) {
if(done_chroot)
log_info("Restart of %s.", PACKAGE_STRING);
else log_info("Start of %s.", PACKAGE_STRING);
/* config stuff */
if(!(cfg = config_create()))
fatal_exit("Could not alloc config defaults");
if(!config_read(cfg, cfgfile))
fatal_exit("Could not read config file: %s", cfgfile);
verbosity = cmdline_verbose + cfg->verbosity;
}
log_info("Start of %s.", PACKAGE_STRING);
/* setup */
worker = worker_init(cfg, BUFSZ);
if(!worker) {
fatal_exit("could not initialize");
}
/* drop user priviliges and chroot if needed */
log_info("start of service (%s).", PACKAGE_STRING);
worker_work(worker);
/* prepare */
if(!daemon_open_shared_ports(daemon, cfg))
fatal_exit("could not open ports");
if(!done_chroot) {
do_chroot(cfg);
done_chroot = 1;
}
/* work */
daemon_fork(daemon);
/* cleanup */
/* clean up for restart */
verbose(VERB_ALGO, "cleanup.");
daemon_cleanup(daemon);
config_delete(cfg);
}
verbose(VERB_ALGO, "Exit cleanup.");
worker_delete(worker);
daemon_delete(daemon);
}
/** getopt global, in case header files fail to declare it. */

View file

@ -281,6 +281,7 @@ worker_delete(struct worker* worker)
outside_network_delete(worker->back);
comm_signal_delete(worker->comsig);
comm_base_delete(worker->base);
free(worker->rndstate);
free(worker);
}

View file

@ -45,9 +45,11 @@
#include "config.h"
#include "util/netevent.h"
#include "util/locks.h"
struct listen_dnsport;
struct outside_network;
struct config_file;
struct daemon;
/** size of table used for random numbers. large to be more secure. */
#define RND_STATE_SIZE 256
@ -57,6 +59,10 @@ struct config_file;
* Holds globally visible information.
*/
struct worker {
/** global shared daemon structure */
struct daemon* daemon;
/** the thread number (in daemon array). */
int thread_num;
/** the event base this worker works with */
struct comm_base* base;
/** the frontside listening interface where request events come in */

View file

@ -391,3 +391,14 @@ listen_delete(struct listen_dnsport* front)
ldns_buffer_free(front->udp_buff);
free(front);
}
struct listen_port*
listening_ports_open(struct config_file* cfg)
{
return calloc(1,1);
}
void listening_ports_free(struct listen_port* list)
{
free(list);
}

View file

@ -46,6 +46,7 @@
#include "util/netevent.h"
struct listen_list;
struct addrinfo;
struct config_file;
/**
* Listening for queries structure.
@ -73,6 +74,31 @@ struct listen_list {
struct comm_point* com;
};
/**
* Single linked list to store shared ports that have been
* opened for use by all threads.
*/
struct listen_port {
/** next in list */
struct listen_port* next;
/** file descriptor, open and ready for use */
int fd;
/** type of file descriptor, udp or tcp */
int is_udp;
};
/**
* Create shared listening ports
* @param cfg: settings on what ports to open.
* @return: linked list of ports or NULL on error.
*/
struct listen_port* listening_ports_open(struct config_file* cfg);
/**
* Close and delete the (list of) listening ports.
*/
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.

View file

@ -690,4 +690,15 @@ pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
runtime->pending_list = pend;
}
struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg))
{
return calloc(1, 1);
}
void listening_ports_free(struct listen_port* list)
{
free(list);
}
/*********** End of Dummy routines ***********/

View file

@ -77,12 +77,20 @@ config_create()
cfg->do_tcp = 1;
cfg->outgoing_base_port = cfg->port + 1000;
cfg->outgoing_num_ports = 16;
cfg->fwd_address = strdup("");
if(!cfg->fwd_address) {
free(cfg);
if(!(cfg->fwd_address = strdup(""))) {
config_delete(cfg);
return NULL;
}
if(!(cfg->username = strdup(""))) {
config_delete(cfg);
return NULL;
}
if(!(cfg->chrootdir = strdup(""))) {
config_delete(cfg);
return NULL;
}
cfg->fwd_port = UNBOUND_DNS_PORT;
cfg->do_daemonize = 0;
return cfg;
}
@ -101,7 +109,10 @@ create_cfg_parser(struct config_file* cfg, char* filename)
int
config_read(struct config_file* cfg, const char* filename)
{
FILE *in = fopen(filename, "r");
FILE *in;
if(!filename)
return 1;
in = fopen(filename, "r");
if(!in) {
log_err("Could not open %s: %s", filename, strerror(errno));
return 0;
@ -124,6 +135,8 @@ config_delete(struct config_file* cfg)
{
if(!cfg) return;
free(cfg->fwd_address);
free(cfg->username);
free(cfg->chrootdir);
free(cfg);
}

View file

@ -73,6 +73,14 @@ struct config_file {
char* fwd_address;
/** forwarder port */
int fwd_port;
/** chrootdir, if not "" or chroot will be done */
char* chrootdir;
/** username to change to, if not "". */
char* username;
/** daemonize, i.e. fork into the background. */
int do_daemonize;
};
/**
@ -84,7 +92,7 @@ struct config_file* config_create();
/**
* Read the config file from the specified filename.
* @param config: where options are stored into, must be freshly created.
* @param filename: name of configfile.
* @param filename: name of configfile. If NULL nothing is done.
* @return: false on error.
*/
int config_read(struct config_file* config, const char* filename);

View file

@ -676,6 +676,7 @@ comm_point_delete(struct comm_point* c)
comm_point_delete(c->tcp_handlers[i]);
free(c->tcp_handlers);
}
free(c->timeout);
if(c->type == comm_tcp)
ldns_buffer_free(c->buffer);
free(c->ev);