/** \file server.c Paraslash's main server. */
-/**
- * \mainpage Main data structures and selected APIs:
- *
- * - Senders: \ref sender,
- * - Audio file selector: \ref afs_info, \ref afs_table,
- * - Audio format handler: \ref audio_format_handler, \ref afh_info
- * - Receivers/filters/writers: \ref receiver, \ref receiver_node,
- * \ref filter, \ref filter_node, \ref writer_node, \ref writer.
- * - Scheduling: \ref sched.h,
- * - Buffer trees: \ref buffer_tree.h,
- * - Sideband API: \ref sideband.h,
- * - Crypto: \ref crypt.h, \ref crypt_backend.h,
- * - Error subsystem: \ref error.h,
- * - Inter process communication: \ref ipc.h,
- * - Forward error correction: \ref fec.h,
- * - Daemons: \ref daemon.h,
- * - Mixer API: \ref mix.h,
- * - Interactive sessions: \ref interactive.h,
- * - File descriptors: \ref fd.h,
- * - Signals: \ref signal.h,
- * - Networking: \ref net.h,
- * - Time: \ref time.c,
- * - Doubly linked lists: \ref list.h.
- */
-
#include <netinet/in.h>
#include <sys/socket.h>
#include <signal.h>
#include "net.h"
#include "server.h"
#include "list.h"
-#include "send.h"
#include "sched.h"
+#include "send.h"
#include "vss.h"
#include "config.h"
#include "close_on_fork.h"
/** The process id of the audio file selector process. */
pid_t afs_pid = 0;
-/* The the main server process (parent of afs and the command handlers). */
+/* The main server process (parent of afs and the command handlers). */
static pid_t server_pid;
/**
mmd->active_connections = 0;
mmd->vss_status_flags = VSS_NEXT;
mmd->new_vss_status_flags = VSS_NEXT;
+ mmd->loglevel = OPT_UINT32_VAL(LOGLEVEL);
return;
destroy_mmd_mutex:
mutex_destroy(mmd_mutex);
exit(EXIT_FAILURE);
}
+/** Get a reference to the supercommand of para_server. */
+#define CMD_PTR (lls_cmd(0, server_suite))
+
/**
* (Re-)read the server configuration files.
*
para_strerror(-ret));
exit(EXIT_FAILURE);
}
- daemon_set_loglevel(ENUM_STRING_VAL(LOGLEVEL));
+ daemon_set_loglevel(OPT_UINT32_VAL(LOGLEVEL));
if (OPT_GIVEN(LOGFILE)) {
daemon_set_logfile(OPT_STRING_VAL(LOGFILE));
daemon_open_log_or_die();
kill(afs_pid, SIGHUP);
}
-static int signal_post_select(struct sched *s, __a_unused void *context)
+static int signal_post_monitor(struct sched *s, __a_unused void *context)
{
int ret, signum;
ret = task_get_notification(signal_task->task);
if (ret < 0)
return ret;
- signum = para_next_signal(&s->rfds);
+ signum = para_next_signal();
switch (signum) {
case 0:
return 0;
if (pid != afs_pid)
continue;
PARA_EMERG_LOG("fatal: afs died\n");
- kill(0, SIGTERM);
- goto cleanup;
+ goto genocide;
}
break;
/* die on sigint/sigterm. Kill all children too. */
case SIGINT:
case SIGTERM:
PARA_EMERG_LOG("terminating on signal %d\n", signum);
+genocide:
kill(0, SIGTERM);
/*
* We must wait for all of our children to die. For the afs
while (wait(NULL) != -1 || errno != ECHILD)
; /* still at least one child alive */
mutex_lock(mmd_mutex);
-cleanup:
free(mmd->afd.afhi.chunk_table);
task_notify_all(s, E_DEADLY_SIGNAL);
return -E_DEADLY_SIGNAL;
add_close_on_fork_list(signal_task->fd);
signal_task->task = task_register(&(struct task_info) {
.name = "signal",
- .pre_select = signal_pre_select,
- .post_select = signal_post_select,
+ .pre_monitor = signal_pre_monitor,
+ .post_monitor = signal_post_monitor,
.context = signal_task,
}, &sched);
}
-static void command_pre_select(struct sched *s, void *context)
+static void command_pre_monitor(struct sched *s, void *context)
{
unsigned n;
struct server_command_task *sct = context;
for (n = 0; n < sct->num_listen_fds; n++)
- para_fd_set(sct->listen_fds[n], &s->rfds, &s->max_fileno);
+ sched_monitor_readfd(sct->listen_fds[n], s);
}
static int command_task_accept(unsigned listen_idx, struct sched *s,
pid_t child_pid;
uint32_t *chunk_table;
- ret = para_accept(sct->listen_fds[listen_idx], &s->rfds, NULL, 0, &new_fd);
+ ret = para_accept(sct->listen_fds[listen_idx], NULL, 0, &new_fd);
if (ret <= 0)
goto out;
mmd->num_connects++;
/*
* After we return, the scheduler calls server_select() with a minimal
* timeout value, because the remaining tasks have a notification
- * pending. Next it calls the ->post_select method of these tasks,
+ * pending. Next it calls the ->post_monitor method of these tasks,
* which will return negative in view of the notification. This causes
* schedule() to return as there are no more runnable tasks.
*
* Note that semaphores are not inherited across a fork(), so we don't
- * hold the lock at this point. Since server_select() drops the lock
- * prior to calling para_select(), we need to acquire it here.
+ * hold the lock at this point. Since server_poll() drops the lock
+ * prior to calling poll(), we need to acquire it here.
*/
mutex_lock(mmd_mutex);
return -E_CHILD_CONTEXT;
return 0;
}
-static int command_post_select(struct sched *s, void *context)
+static int command_post_monitor(struct sched *s, void *context)
{
struct server_command_task *sct = context;
unsigned n;
ret = task_get_notification(sct->task);
if (ret < 0)
- return ret;
+ goto fail;
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;
- }
+ if (ret < 0)
+ goto fail;
}
return 0;
+fail:
+ free(sct->listen_fds);
+ return ret;
}
static void init_server_command_task(struct server_command_task *sct,
sct->argv = argv;
if (!OPT_GIVEN(LISTEN_ADDRESS)) {
sct->num_listen_fds = 1;
- sct->listen_fds = para_malloc(sizeof(int));
+ sct->listen_fds = alloc(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));
+ sct->listen_fds = alloc(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));
sct->task = task_register(&(struct task_info) {
.name = "server command",
- .pre_select = command_pre_select,
- .post_select = command_post_select,
+ .pre_monitor = command_pre_monitor,
+ .post_monitor = command_post_monitor,
.context = sct,
}, &sched);
/*
if (ret < 0)
goto fail;
server_lpr = cmdline_lpr;
- daemon_set_loglevel(ENUM_STRING_VAL(LOGLEVEL));
+ daemon_set_loglevel(OPT_UINT32_VAL(LOGLEVEL));
daemon_drop_privileges_or_die(OPT_STRING_VAL(USER),
OPT_STRING_VAL(GROUP));
version_handle_flag("server", OPT_GIVEN(VERSION));
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();
-
/*
* Although afs uses its own signal handling we must ignore SIGUSR1
* _before_ the afs child process gets born by init_afs() below. It's
killpg(0, SIGUSR1);
}
-static int server_select(int max_fileno, fd_set *readfds, fd_set *writefds,
- struct timeval *timeout_tv)
+static int server_poll(struct pollfd *fds, nfds_t nfds, int timeout)
{
int ret;
+ daemon_set_loglevel(mmd->loglevel);
status_refresh();
mutex_unlock(mmd_mutex);
- ret = para_select(max_fileno + 1, readfds, writefds, timeout_tv);
+ ret = xpoll(fds, nfds, timeout);
mutex_lock(mmd_mutex);
return ret;
}
struct server_command_task server_command_task_struct,
*sct = &server_command_task_struct;
- sched.default_timeout.tv_sec = 1;
- sched.select_function = server_select;
+ sched.default_timeout = 1000;
+ sched.poll_function = server_poll;
server_init(argc, argv, sct);
mutex_lock(mmd_mutex);
ret = schedule(&sched);
/*
- * We hold the mmd lock: it was re-acquired in server_select()
- * after the select call.
+ * We hold the mmd lock: it was re-acquired in server_poll()
+ * after the poll(2) call.
*/
mutex_unlock(mmd_mutex);
sched_shutdown(&sched);
deplete_close_on_fork_list();
if (ret < 0)
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+ vss_shutdown();
} else {
+ vss_shutdown();
alarm(ALARM_TIMEOUT);
close_listed_fds();
ret = handle_connect(sct->child_fd);
}
- vss_shutdown();
shm_detach(mmd);
user_list_deplete();
free_lpr();