From 93b9103f7383d400616d222606c294e07b16e1aa Mon Sep 17 00:00:00 2001 From: Lars Müller Date: Sat, 1 Mar 2008 18:30:38 +0000 Subject: Import dnbd* from the former openslx-contrib repo as of revision 92. openslx-contrib is currently read only and will get removed in some days. git-svn-id: http://svn.openslx.org/svn/openslx/contrib/dnbd2/trunk@1592 95ad53e4-c205-0410-b2fa-d234c58c8868 --- server/main.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 server/main.c (limited to 'server/main.c') diff --git a/server/main.c b/server/main.c new file mode 100644 index 0000000..5a923a9 --- /dev/null +++ b/server/main.c @@ -0,0 +1,227 @@ +/* + * server/main.c + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dnbd2.h" +#include "tree.h" +#include "file.h" +#include "config.h" +#include "query.h" + + +char *cfile = NULL; /* path to config file */ +void *tree = NULL; /* tree containing datasets */ +int server_fd; /* file descriptor for UPD communication */ +struct sockaddr_in server_addr; + + +/* + * Flags and signal handlers. + */ +int sig_exit, sig_config; +void exit_handler(int sig); +void config_handler(int sig); + + +/* + * Function to configure server. We call it with LOAD on + * initialization and with RELOAD when SIGHUP is caught. + */ +enum config_action { LOAD, RELOAD }; +int configure(enum config_action action); + + +void print_usage(void); +int daemon_init(void); + + +int main(int argc, char **argv) +{ + int ret; + ssize_t n; + socklen_t len; + dnbd2_data_reply_t reply; + dnbd2_data_request_t request; + struct sockaddr_in client_addr; + struct sigaction exit_act, config_act; + + if (argc != 2) { + print_usage(); + return -1; + } + + cfile = argv[1]; + openlog(argv[0], LOG_PID, LOG_LOCAL2); + syslog(LOG_NOTICE, "Starting DNBD2 Server."); + + /* Load datasets and bind to socket. */ + if (configure(LOAD) == -1) + goto out_no_start; + + /* Daemonize. */ + ret = daemon_init(); + if (ret == -1) { + syslog(LOG_ERR, "Could not fork and background."); + goto out_no_start; + } + + /* Setup signal handlers. */ + sigaction(SIGTERM, NULL, &exit_act); + exit_act.sa_flags &= ~SA_RESTART; + exit_act.sa_handler = exit_handler; + + sigaction(SIGHUP, NULL, &config_act); + config_act.sa_flags &= ~SA_RESTART; + config_act.sa_handler = config_handler; + + sigaction(SIGTERM, &exit_act, NULL); + sigaction(SIGINT, &exit_act, NULL); + sigaction(SIGHUP, &config_act, NULL); + + while (1) { + if (sig_exit) { + syslog(LOG_NOTICE, "Stopping Server."); + exit(0); + } + if (sig_config) { + syslog(LOG_NOTICE, "Reloading configuration."); + if (configure(RELOAD) == -1) + syslog(LOG_ERR, "Not using new configuration."); + sig_config = 0; + } + + /* Receive request. */ + len = sizeof(client_addr); + n = recvfrom(server_fd, &request, sizeof(request), 0, + &client_addr, &len); + + if (n == -1 || n != sizeof(request)) + continue; + + /* Process request. */ + ret = handle_query(&request, &reply, &tree); + if (ret == -1) + continue; + + /* Send reply. */ + sendto(server_fd, &reply, sizeof(reply), 0, &client_addr, len); + } + + return 0; + + out_no_start: + syslog(LOG_ERR, "Server not started."); + fprintf(stderr, "Server not started - " + "consult your syslog for errors.\n"); + return -1; +} + + +void config_handler(int sig) +{ + sig_config = 1; +} + + +void exit_handler(int sig) +{ + sig_exit = 1; +} + + +int cmp_addr(struct sockaddr_in addr1, struct sockaddr_in addr2) +{ + int diff = memcmp(&addr1.sin_addr.s_addr, + &addr2.sin_addr.s_addr, + sizeof(in_addr_t)); + + if (diff) + return diff; + + return memcmp(&addr1.sin_port, + &addr2.sin_port, + sizeof(in_port_t)); +} + + +int configure(enum config_action action) +{ + void *tmp_tree = NULL; + int datasets, ret, tmp_fd = server_fd; + struct sockaddr_in tmp_addr; + + datasets = parse_config_file(cfile, &tmp_addr, &tmp_tree); + if (datasets <= 0) + return -1; + + /* Create a socket and bind to it. */ + if (action == LOAD || cmp_addr(tmp_addr, server_addr)) { + tmp_fd = socket(PF_INET, SOCK_DGRAM, 0); + if (tmp_fd == -1) { + syslog(LOG_ERR, "Could not create socket."); + return -1; + } + + ret = bind(tmp_fd, (struct sockaddr *) &tmp_addr, + sizeof(tmp_addr)); + + if (ret == -1) { + close(tmp_fd); + syslog(LOG_ERR, "Could not assign name to socket."); + return -1; + } + } + + /* Make new socket available and close the old one if necesary. */ + if (action == RELOAD && cmp_addr(tmp_addr, server_addr)) { + if (close(server_fd) == -1 ) { + syslog(LOG_ERR, "Could not close socket."); + } + } + + server_fd = tmp_fd; + server_addr = tmp_addr; + + tree_destroy(tree); + tree = tmp_tree; + return 0; +} + + +void print_usage(void) +{ + printf("usage: dnbd2-dserver config-file\n"); +} + + +int daemon_init(void) +{ + pid_t pid = fork(); + + if (pid == -1) + return pid; + + if (pid != 0) { + /* We are the parent. */ + exit(0); + } + + /* We are the child. */ + setsid(); + chdir("/"); + umask(0); + + return 0; +} -- cgit v1.2.3-55-g7522