]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - server.c
server: Implement --listen-address for control service.
[paraslash.git] / server.c
index 4bc85a345b6328041059da62443a0d544371e324..9c11b23cbb4801f15e08ae3c1a0a559322b38578 100644 (file)
--- a/server.c
+++ b/server.c
@@ -1,8 +1,4 @@
-/*
- * Copyright (C) 1997 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 1997 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
 
 /** \file server.c Paraslash's main server. */
 
@@ -49,6 +45,7 @@
 #include "afh.h"
 #include "string.h"
 #include "afs.h"
+#include "net.h"
 #include "server.h"
 #include "list.h"
 #include "send.h"
@@ -56,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"
@@ -90,7 +86,15 @@ struct lls_parse_result *server_lpr = NULL;
 /* Command line options (no config file options). Used in handle_sighup(). */
 static struct lls_parse_result *cmdline_lpr;
 
-/** A random value used in child context for authentication. */
+/**
+ * A random number used to "authenticate" the afs connection.
+ *
+ * para_server picks this number by random before it forks the afs process. The
+ * command handlers know this number as well and write it to the afs socket,
+ * together with the id of the shared memory area which contains the payload of
+ * the afs command. A local process has to know this number to abuse the afs
+ * service provided by the local socket.
+ */
 uint32_t afs_socket_cookie;
 
 /** The mutex protecting the shared memory area containing the mmd struct. */
@@ -99,10 +103,14 @@ int mmd_mutex;
 static struct sched sched;
 static struct signal_task *signal_task;
 
+/** The process id of the audio file selector process. */
+pid_t afs_pid = 0;
+
 /** 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;
        /** Copied from para_server's main function. */
        int argc;
        /** Argument vector passed to para_server's main function. */
@@ -178,12 +186,11 @@ void parse_config_or_die(bool reload)
        struct lls_parse_result *cf_lpr, *merged_lpr;
        char *home = para_homedir();
 
-       daemon_close_log();
        if (OPT_GIVEN(CONFIG_FILE))
                cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE));
        else
                cf = make_message("%s/.paraslash/server.conf", home);
-       if (!mmd || getpid() != mmd->afs_pid) {
+       if (!mmd || getpid() != afs_pid) {
                if (OPT_GIVEN(USER_LIST))
                        user_list_file = para_strdup(OPT_STRING_VAL(USER_LIST));
                else
@@ -196,7 +203,6 @@ void parse_config_or_die(bool reload)
                        goto free_cf;
                if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && OPT_GIVEN(CONFIG_FILE))
                        goto free_cf;
-               ret = 0;
                server_lpr = cmdline_lpr;
                goto success;
        }
@@ -212,7 +218,7 @@ void parse_config_or_die(bool reload)
        if (reload) /* config file overrides command line */
                ret = lls(lls_merge(cf_lpr, cmdline_lpr, CMD_PTR, &merged_lpr,
                        &errctx));
-       else /* command line options overrride config file options */
+       else /* command line options override config file options */
                ret = lls(lls_merge(cmdline_lpr, cf_lpr, CMD_PTR, &merged_lpr,
                        &errctx));
        lls_free_parse_result(cf_lpr, CMD_PTR);
@@ -263,8 +269,8 @@ static void handle_sighup(void)
 
        PARA_NOTICE_LOG("SIGHUP\n");
        parse_config_or_die(true);
-       if (mmd->afs_pid)
-               kill(mmd->afs_pid, SIGHUP);
+       if (afs_pid != 0)
+               kill(afs_pid, SIGHUP);
 }
 
 static int signal_post_select(struct sched *s, __a_unused void *context)
@@ -283,7 +289,7 @@ static int signal_post_select(struct sched *s, __a_unused void *context)
                        int ret = para_reap_child(&pid);
                        if (ret <= 0)
                                break;
-                       if (pid != mmd->afs_pid)
+                       if (pid != afs_pid)
                                continue;
                        PARA_EMERG_LOG("fatal: afs died\n");
                        kill(0, SIGTERM);
@@ -309,8 +315,8 @@ static int signal_post_select(struct sched *s, __a_unused void *context)
                 * processes get killed immediately by the above kill().
                 */
                PARA_INFO_LOG("waiting for afs (pid %d) to die\n",
-                       (int)mmd->afs_pid);
-               waitpid(mmd->afs_pid, NULL, 0);
+                       (int)afs_pid);
+               waitpid(afs_pid, NULL, 0);
 cleanup:
                free(mmd->afd.afhi.chunk_table);
                close_listed_fds();
@@ -341,24 +347,24 @@ 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, fd_set *rfds,
+               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 = para_accept(sct->listen_fd, &s->rfds, NULL, 0, &new_fd);
+       ret = para_accept(sct->listen_fds[listen_idx], rfds, NULL, 0, &new_fd);
        if (ret <= 0)
                goto out;
-       peer_name = remote_name(new_fd);
-       PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
        mmd->num_connects++;
        mmd->active_connections++;
        /*
@@ -384,6 +390,8 @@ static int command_post_select(struct sched *s, void *context)
                /* parent keeps accepting connections */
                return 0;
        }
+       peer_name = remote_name(new_fd);
+       PARA_INFO_LOG("accepted connection from %s\n", peer_name);
        /* mmd might already have changed at this point */
        free(chunk_table);
        alarm(ALARM_TIMEOUT);
@@ -397,7 +405,7 @@ static int command_post_select(struct sched *s, void *context)
                memset(sct->argv[i], 0, strlen(sct->argv[i]));
        i = sct->argc - 1 - lls_num_inputs(cmdline_lpr);
        sprintf(sct->argv[i], "para_server (serving %s)", peer_name);
-       handle_connect(new_fd, peer_name);
+       handle_connect(new_fd);
        /* never reached*/
 out:
        if (ret < 0)
@@ -405,23 +413,61 @@ out:
        return 0;
 }
 
+static int command_post_select(struct sched *s, void *context)
+{
+       struct server_command_task *sct = context;
+       unsigned n;
+       int ret;
+
+       for (n = 0; n < sct->num_listen_fds; n++) {
+               ret = command_task_accept(n, &s->rfds, sct);
+               if (ret < 0) {
+                       free(sct->listen_fds);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
 static void init_server_command_task(int argc, char **argv)
 {
        int ret;
        static struct server_command_task server_command_task_struct,
                *sct = &server_command_task_struct;
+       unsigned n;
+       uint32_t port = OPT_UINT32_VAL(PORT);
+
 
        PARA_NOTICE_LOG("initializing tcp command socket\n");
        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,
@@ -437,7 +483,6 @@ err:
 static int init_afs(int argc, char **argv)
 {
        int ret, afs_server_socket[2];
-       pid_t afs_pid;
        char c;
 
        ret = socketpair(PF_UNIX, SOCK_STREAM, 0, afs_server_socket);
@@ -451,14 +496,14 @@ static int init_afs(int argc, char **argv)
        if (afs_pid == 0) { /* child (afs) */
                int i;
 
+               afs_pid = getpid();
                for (i = argc - 1; i >= 0; i--)
                        memset(argv[i], 0, strlen(argv[i]));
                i = argc - lls_num_inputs(cmdline_lpr) - 1;
                sprintf(argv[i], "para_server (afs)");
                close(afs_server_socket[0]);
-               afs_init(afs_socket_cookie, afs_server_socket[1]);
+               afs_init(afs_server_socket[1]);
        }
-       mmd->afs_pid = afs_pid;
        close(afs_server_socket[1]);
        if (read(afs_server_socket[0], &c, 1) <= 0) {
                PARA_EMERG_LOG("early afs exit\n");