X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=server.c;h=a344b77440751a6e7017d9d7e641390a36eb157f;hp=13c8c85f98339023b90415125e9df275a28c98f3;hb=53af5c6efb309565990203fd8504a812ec9166c9;hpb=7f08e8b0eb9570f1eb787dbb4e10d56585b36bbf diff --git a/server.c b/server.c index 13c8c85f..a344b774 100644 --- a/server.c +++ b/server.c @@ -45,6 +45,7 @@ #include "afh.h" #include "string.h" #include "afs.h" +#include "net.h" #include "server.h" #include "list.h" #include "send.h" @@ -52,7 +53,6 @@ #include "vss.h" #include "config.h" #include "close_on_fork.h" -#include "net.h" #include "daemon.h" #include "ipc.h" #include "fd.h" @@ -100,6 +100,9 @@ uint32_t afs_socket_cookie; /** The mutex protecting the shared memory area containing the mmd struct. */ int mmd_mutex; +/* Serializes log output. */ +static int log_mutex; + static struct sched sched; static struct signal_task *signal_task; @@ -126,8 +129,9 @@ bool process_is_command_handler(void) /** The task responsible for server command handling. */ struct server_command_task { - /** TCP port on which para_server listens for connections. */ - int listen_fd; + unsigned num_listen_fds; /* only one by default */ + /** TCP socket(s) on which para_server listens for connections. */ + int *listen_fds; /* File descriptor for the accepted socket. */ int child_fd; /** Copied from para_server's main function. */ @@ -151,9 +155,17 @@ char *server_get_tasks(void) return get_task_list(&sched); } -/* - * setup shared memory area and get mutex for locking - */ +static void pre_log_hook(void) +{ + mutex_lock(log_mutex); +} + +static void post_log_hook(void) +{ + mutex_unlock(log_mutex); +} + +/* Setup shared memory area and init mutexes */ static void init_ipc_or_die(void) { void *shm; @@ -172,6 +184,10 @@ static void init_ipc_or_die(void) if (ret < 0) goto err_out; mmd_mutex = ret; + ret = mutex_new(); + if (ret < 0) + goto destroy_mmd_mutex; + log_mutex = ret; mmd->num_played = 0; mmd->num_commands = 0; @@ -181,6 +197,8 @@ static void init_ipc_or_die(void) mmd->vss_status_flags = VSS_NEXT; mmd->new_vss_status_flags = VSS_NEXT; return; +destroy_mmd_mutex: + mutex_destroy(mmd_mutex); err_out: PARA_EMERG_LOG("%s\n", para_strerror(-ret)); exit(EXIT_FAILURE); @@ -266,7 +284,7 @@ success: daemon_set_flag(DF_LOG_TIMING); daemon_set_priority(OPT_UINT32_VAL(PRIORITY)); if (user_list_file) - init_user_list(user_list_file); + user_list_init(user_list_file); ret = 1; free_cf: free(cf); @@ -365,22 +383,22 @@ static void init_signal_task(void) static void command_pre_select(struct sched *s, void *context) { + unsigned n; struct server_command_task *sct = context; - para_fd_set(sct->listen_fd, &s->rfds, &s->max_fileno); + + for (n = 0; n < sct->num_listen_fds; n++) + para_fd_set(sct->listen_fds[n], &s->rfds, &s->max_fileno); } -static int command_post_select(struct sched *s, void *context) +static int command_task_accept(unsigned listen_idx, struct sched *s, + struct server_command_task *sct) { - struct server_command_task *sct = context; int new_fd, ret, i; char *peer_name; pid_t child_pid; uint32_t *chunk_table; - ret = task_get_notification(sct->task); - if (ret < 0) - return ret; - ret = para_accept(sct->listen_fd, &s->rfds, NULL, 0, &new_fd); + ret = para_accept(sct->listen_fds[listen_idx], &s->rfds, NULL, 0, &new_fd); if (ret <= 0) goto out; mmd->num_connects++; @@ -442,23 +460,63 @@ out: return 0; } +static int command_post_select(struct sched *s, void *context) +{ + struct server_command_task *sct = context; + unsigned n; + int ret; + + ret = task_get_notification(sct->task); + if (ret < 0) + return ret; + for (n = 0; n < sct->num_listen_fds; n++) { + ret = command_task_accept(n, s, sct); + if (ret < 0) { + free(sct->listen_fds); + return ret; + } + } + return 0; +} + static void init_server_command_task(struct server_command_task *sct, int argc, char **argv) { int ret; + unsigned n; + uint32_t port = OPT_UINT32_VAL(PORT); PARA_NOTICE_LOG("initializing tcp command socket\n"); sct->child_fd = -1; sct->argc = argc; sct->argv = argv; - ret = para_listen_simple(IPPROTO_TCP, OPT_UINT32_VAL(PORT)); - if (ret < 0) - goto err; - sct->listen_fd = ret; - ret = mark_fd_nonblocking(sct->listen_fd); - if (ret < 0) - goto err; - add_close_on_fork_list(sct->listen_fd); /* child doesn't need the listener */ + if (!OPT_GIVEN(LISTEN_ADDRESS)) { + sct->num_listen_fds = 1; + sct->listen_fds = para_malloc(sizeof(int)); + ret = para_listen_simple(IPPROTO_TCP, port); + if (ret < 0) + goto err; + sct->listen_fds[0] = ret; + } else { + sct->num_listen_fds = OPT_GIVEN(LISTEN_ADDRESS); + sct->listen_fds = para_malloc(sct->num_listen_fds * sizeof(int)); + for (n = 0; n < OPT_GIVEN(LISTEN_ADDRESS); n++) { + const char *arg; + arg = lls_string_val(n, OPT_RESULT(LISTEN_ADDRESS)); + ret = para_listen(IPPROTO_TCP, arg, port); + if (ret < 0) + goto err; + sct->listen_fds[n] = ret; + } + } + for (n = 0; n < sct->num_listen_fds; n++) { + ret = mark_fd_nonblocking(sct->listen_fds[n]); + if (ret < 0) + goto err; + /* child doesn't need the listener */ + add_close_on_fork_list(sct->listen_fds[n]); + } + sct->task = task_register(&(struct task_info) { .name = "server command", .pre_select = command_pre_select, @@ -488,6 +546,8 @@ static int init_afs(int argc, char **argv) int i; afs_pid = getpid(); + crypt_shutdown(); + user_list_deplete(); for (i = argc - 1; i >= 0; i--) memset(argv[i], 0, strlen(argv[i])); i = argc - lls_num_inputs(cmdline_lpr) - 1; @@ -546,10 +606,11 @@ static void server_init(int argc, char **argv, struct server_command_task *sct) if (OPT_GIVEN(DAEMON)) daemon_pipe = daemonize(true /* parent waits for SIGTERM */); server_pid = getpid(); - init_random_seed_or_die(); + crypt_init(); daemon_log_welcome("server"); - init_ipc_or_die(); /* init mmd struct and mmd->lock */ + init_ipc_or_die(); /* init mmd struct, mmd and log mutex */ daemon_set_start_time(); + daemon_set_hooks(pre_log_hook, post_log_hook); PARA_NOTICE_LOG("initializing audio format handlers\n"); afh_init(); @@ -624,6 +685,21 @@ static int server_select(int max_fileno, fd_set *readfds, fd_set *writefds, return ret; } +/** + * Deallocate all lopsub parse results. + * + * The server allocates a parse result for command line options and optionally + * a second parse result for the effective configuration, defined by merging + * the command line options with the options stored in the configuration file. + * This function frees both structures. + */ +void free_lpr(void) +{ + lls_free_parse_result(server_lpr, CMD_PTR); + if (server_lpr != cmdline_lpr) + lls_free_parse_result(cmdline_lpr, CMD_PTR); +} + /** * The main function of para_server. * @@ -650,10 +726,13 @@ int main(int argc, char *argv[]) */ mutex_unlock(mmd_mutex); sched_shutdown(&sched); + crypt_shutdown(); signal_shutdown(signal_task); if (!process_is_command_handler()) { /* parent (server) */ mutex_destroy(mmd_mutex); - shm_detach(mmd); + daemon_set_hooks(NULL, NULL); /* only one process remaining */ + mutex_destroy(log_mutex); + deplete_close_on_fork_list(); if (ret < 0) PARA_EMERG_LOG("%s\n", para_strerror(-ret)); } else { @@ -663,8 +742,7 @@ int main(int argc, char *argv[]) } vss_shutdown(); shm_detach(mmd); - lls_free_parse_result(server_lpr, CMD_PTR); - if (server_lpr != cmdline_lpr) - lls_free_parse_result(cmdline_lpr, CMD_PTR); + user_list_deplete(); + free_lpr(); exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS); }