2 * Copyright (C) 1997-2009 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file server.c Paraslash's main server. */
11 * \mainpage Paraslash API Reference
13 * Starting points for getting an overview:
16 * - The main programs: \ref server.c, \ref audiod.c, \ref client.c,
17 * \ref audioc.c, \ref fsck.c, \ref afh.c
18 * - Server: \ref server_command, \ref sender,
19 * - Audio file selector: \ref audio_format_handler, \ref mood, \ref afs_table,
20 * - Client: \ref receiver, \ref receiver_node, \ref filter, \ref filter_node.
23 * The gory details, listed by topic:
25 * - Audio format handlers: \ref send_common.c \ref mp3_afh.c, \ref ogg_afh.c, \ref aac_afh.c,
26 * - Decoders: \ref mp3dec_filter.c, \ref oggdec_filter.c, \ref aacdec_filter.c,
27 * - Volume normalizer: \ref compress_filter.c,
28 * - Output: \ref alsa_write.c, \ref osx_write.c,
29 * - http: \ref http_recv.c, \ref http_send.c,
30 * - udp: \ref udp_recv.c, \ref udp_send.c,
31 * - dccp: \ref dccp_recv.c, \ref dccp_send.c,
32 * - Audio file selector: \ref afs.c, \ref aft.c, \ref mood.c,
33 * - Afs structures: \ref afs_table, \ref audio_file_data,
34 * \ref afs_info \ref afh_info,
35 * - Afs tables: \ref aft.c, \ref mood.c, \ref playlist.c,
36 * \ref attribute.c, \ref score.c,
37 * - The virtual streaming system: \ref vss.c, \ref chunk_queue.c.
41 * - Scheduling: \ref sched.c, \ref sched.h,
42 * - Networking: \ref net.c,
43 * - File descriptors: \ref fd.c,
44 * - Signals: \ref signal.c,
45 * - Daemons: \ref daemon.c,
46 * - Strings: \ref string.c, \ref string.h,
47 * - Time: \ref time.c,
48 * - Spawning processes: \ref exec.c,
49 * - Inter process communication: \ref ipc.c,
50 * - The object storage layer: \ref osl.c,
51 * - Blob tables: \ref blob.c,
52 * - The error subssystem: \ref error.h.
53 * - Access control for paraslash senders: \ref acl.c, \ref acl.h.
55 * Low-level data structures:
57 * - Doubly linked lists: \ref list.h,
58 * - Red-black trees: \ref rbtree.h, \ref rbtree.c,
59 * - Ring buffer: \ref ringbuffer.c, \ref ringbuffer.h,
60 * - Hashing: \ref hash.h, \ref sha1.h, \ref sha1.c,
61 * - Crypto: \ref crypt.c.
71 #include "server.cmdline.h"
78 #include "close_on_fork.h"
87 #include "user_list.h"
90 /** Define the array of error lists needed by para_server. */
93 /** Shut down non-authorized connections after that many seconds. */
94 #define ALARM_TIMEOUT 10
97 * Pointer to shared memory area for communication between para_server
98 * and its children. Exported to vss.c. command.c and to afs.
100 struct misc_meta_data *mmd;
103 * The configuration of para_server
105 * It also contains the options for the audio file selector, audio format
106 * handler and all supported senders.
108 struct server_args_info conf;
110 /** A random value used in child context for authentication. */
111 uint32_t afs_socket_cookie;
113 /** The mutex protecting the shared memory area containing the mmd struct. */
116 /* global variables for server-internal use */
117 static FILE *logfile;
118 /** The file containing user information (public key, permissions). */
119 static char *user_list_file = NULL;
120 static int mmd_shm_id;
123 /** The task responsible for server command handling. */
124 struct server_command_task {
125 /** TCP port on which para_server listens for connections. */
127 /** Copied from para_server's main function. */
129 /** Argument vector passed to para_server's main function. */
131 /** The command task structure for scheduling. */
135 static int want_colors(void)
137 if (conf.color_arg == color_arg_no)
139 if (conf.color_arg == color_arg_yes)
143 return isatty(STDERR_FILENO);
146 static int get_loglevel_by_name(const char *txt, size_t n)
148 if (!strncasecmp(txt, "debug", n))
150 if (!strncasecmp(txt, "info", n))
152 if (!strncasecmp(txt, "notice", n))
154 if (!strncasecmp(txt, "warning", n))
156 if (!strncasecmp(txt, "error", n))
158 if (!strncasecmp(txt, "crit", n))
160 if (!strncasecmp(txt, "emerg", n))
165 static char log_colors[NUM_LOGLEVELS][COLOR_MAXLEN];
167 static void init_colors_or_die(void)
170 static const char *default_log_colors[NUM_LOGLEVELS] = {
171 [LL_DEBUG] = "normal",
172 [LL_INFO] = "white bold",
173 [LL_NOTICE] = "cyan bold",
174 [LL_WARNING] = "green bold",
175 [LL_ERROR] = "yellow bold",
176 [LL_CRIT] = "magenta bold",
177 [LL_EMERG] = "red bold",
180 for (i = 0; i < NUM_LOGLEVELS; i++) {
181 ret = color_parse(default_log_colors[i], log_colors[i]);
185 for (i = 0; i < conf.log_color_given; i++) {
186 char *arg = conf.log_color_arg[i], *p = strchr(arg, ':');
190 ret = get_loglevel_by_name(arg, p - arg);
195 ret = color_parse(p, log_colors[ll]);
201 PARA_EMERG_LOG("color syntax error, arg %d (%s)\n", i,
202 conf.log_color_arg[i]);
207 * Para_server's log function.
209 * \param ll The log level.
210 * \param fmt The format string describing the log message.
212 __printf_2_3 void para_log(int ll, const char* fmt,...)
218 char *color, str[MAXLINE] = "";
220 ll = PARA_MIN(ll, NUM_LOGLEVELS - 1);
221 ll = PARA_MAX(ll, LL_DEBUG);
222 if (ll < conf.loglevel_arg)
225 fp = logfile? logfile : stderr;
226 color = want_colors()? log_colors[ll] : NULL;
229 fprintf(fp, "%s", color);
233 strftime(str, MAXLINE, "%b %d %H:%M:%S", tm);
234 fprintf(fp, "%s ", str);
236 if (conf.loglevel_arg <= LL_INFO)
237 fprintf(fp, "%i: ", ll);
238 if (conf.loglevel_arg <= LL_INFO) { /* log pid */
239 pid_t mypid = getpid();
240 fprintf(fp, "(%d) ", (int)mypid);
243 vfprintf(fp, fmt, argp);
246 fprintf(fp, "%s", COLOR_RESET);
250 * setup shared memory area and get mutex for locking
252 static void init_ipc_or_die(void)
255 int ret = shm_new(sizeof(struct misc_meta_data));
260 ret = shm_attach(ret, ATTACH_RW, &shm);
272 mmd->num_commands = 0;
274 mmd->num_connects = 0;
275 mmd->active_connections = 0;
276 mmd->vss_status_flags = VSS_NEXT;
277 mmd->new_vss_status_flags = VSS_NEXT;
280 PARA_EMERG_LOG("%s\n", para_strerror(-ret));
285 * (Re-)read the server configuration files.
287 * \param override Passed to gengetopt to activate the override feature.
289 * This function also re-opens the logfile and sets the global \a
290 * user_list_file variable.
292 void parse_config_or_die(int override)
294 char *home = para_homedir();
301 if (conf.config_file_given)
302 cf = para_strdup(conf.config_file_arg);
304 cf = make_message("%s/.paraslash/server.conf", home);
305 free(user_list_file);
306 if (!conf.user_list_given)
307 user_list_file = make_message("%s/.paraslash/server.users", home);
309 user_list_file = para_strdup(conf.user_list_arg);
310 ret = stat(cf, &statbuf);
311 if (ret && conf.config_file_given) {
313 PARA_EMERG_LOG("can not stat config file %s\n", cf);
317 int tmp = conf.daemon_given;
318 struct server_cmdline_parser_params params = {
319 .override = override,
322 .check_ambiguity = 0,
325 server_cmdline_parser_config_file(cf, &conf, ¶ms);
326 conf.daemon_given = tmp;
328 if (conf.logfile_given)
329 logfile = open_log(conf.logfile_arg);
331 init_colors_or_die();
338 free(user_list_file);
339 user_list_file = NULL;
343 static void signal_pre_select(struct sched *s, struct task *t)
345 struct signal_task *st = container_of(t, struct signal_task, task);
346 para_fd_set(st->fd, &s->rfds, &s->max_fileno);
350 * called when server gets SIGHUP or when client invokes hup command.
352 static void handle_sighup(void)
354 PARA_NOTICE_LOG("SIGHUP\n");
355 parse_config_or_die(1); /* reopens log */
356 init_user_list(user_list_file); /* reload user list */
358 kill(mmd->afs_pid, SIGHUP);
361 static void signal_post_select(struct sched *s, struct task *t)
363 struct signal_task *st = container_of(t, struct signal_task, task);
365 if (!FD_ISSET(st->fd, &s->rfds))
368 st->signum = para_next_signal();
369 switch (st->signum) {
376 int ret = para_reap_child(&pid);
379 if (pid != mmd->afs_pid)
381 PARA_EMERG_LOG("fatal: afs died\n");
385 /* die on sigint/sigterm. Kill all children too. */
388 PARA_EMERG_LOG("terminating on signal %d\n", st->signum);
391 mutex_destroy(mmd_mutex);
393 shm_destroy(mmd_shm_id);
399 static void init_signal_task(void)
401 static struct signal_task signal_task_struct,
402 *st = &signal_task_struct;
404 st->task.pre_select = signal_pre_select;
405 st->task.post_select = signal_post_select;
406 sprintf(st->task.status, "signal task");
408 st->fd = para_signal_init(); /* always successful */
410 PARA_NOTICE_LOG("setting up signal handlers\n");
411 if (para_install_sighandler(SIGINT) < 0)
413 if (para_install_sighandler(SIGTERM) < 0)
415 if (para_install_sighandler(SIGHUP) < 0)
417 if (para_install_sighandler(SIGCHLD) < 0)
419 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
421 if (signal(SIGUSR1, SIG_IGN) == SIG_ERR)
423 add_close_on_fork_list(st->fd);
424 register_task(&st->task);
427 PARA_EMERG_LOG("could not install signal handlers\n");
431 static void command_pre_select(struct sched *s, struct task *t)
433 struct server_command_task *sct = container_of(t, struct server_command_task, task);
434 para_fd_set(sct->listen_fd, &s->rfds, &s->max_fileno);
437 static void command_post_select(struct sched *s, struct task *t)
439 struct server_command_task *sct = container_of(t, struct server_command_task, task);
445 if (!FD_ISSET(sct->listen_fd, &s->rfds))
447 ret = para_accept(sct->listen_fd, NULL, 0);
451 peer_name = remote_name(new_fd);
452 PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
454 mmd->active_connections++;
458 ret = -ERRNO_TO_PARA_ERROR(errno);
463 /* parent keeps accepting connections */
466 alarm(ALARM_TIMEOUT);
468 para_signal_shutdown();
470 * put info on who we are serving into argv[0] to make
471 * client ip visible in top/ps
473 for (i = sct->argc - 1; i >= 0; i--)
474 memset(sct->argv[i], 0, strlen(sct->argv[i]));
475 sprintf(sct->argv[0], "para_server (serving %s)", peer_name);
476 return handle_connect(new_fd, peer_name);
479 PARA_CRIT_LOG("%s\n", para_strerror(-ret));
482 static void init_server_command_task(int argc, char **argv)
485 static struct server_command_task server_command_task_struct,
486 *sct = &server_command_task_struct;
488 PARA_NOTICE_LOG("initializing tcp command socket\n");
489 sct->task.pre_select = command_pre_select;
490 sct->task.post_select = command_post_select;
493 ret = para_listen(AF_UNSPEC, IPPROTO_TCP, conf.port_arg);
496 sct->listen_fd = ret;
497 ret = mark_fd_nonblocking(sct->listen_fd);
500 add_close_on_fork_list(sct->listen_fd); /* child doesn't need the listener */
501 register_task(&sct->task);
504 PARA_EMERG_LOG("%s\n", para_strerror(-ret));
508 static void init_random_seed(void)
511 int fd, ret = para_open("/dev/urandom", O_RDONLY, 0);
516 ret = read(fd, &seed, sizeof(seed));
518 ret = -ERRNO_TO_PARA_ERROR(errno);
521 if (ret != sizeof(seed)) {
522 ret = -ERRNO_TO_PARA_ERROR(EIO);
532 PARA_EMERG_LOG("can not seed pseudo random number generator: %s\n",
533 para_strerror(-ret));
537 static int init_afs(void)
539 int ret, afs_server_socket[2];
541 ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, afs_server_socket);
544 afs_socket_cookie = para_random((uint32_t)-1);
545 mmd->afs_pid = fork();
546 if (mmd->afs_pid < 0)
548 if (!mmd->afs_pid) { /* child (afs) */
549 close(afs_server_socket[0]);
550 afs_init(afs_socket_cookie, afs_server_socket[1]);
552 close(afs_server_socket[1]);
553 ret = mark_fd_nonblocking(afs_server_socket[0]);
556 add_close_on_fork_list(afs_server_socket[0]);
557 PARA_INFO_LOG("afs_socket: %d, afs_socket_cookie: %u\n",
558 afs_server_socket[0], (unsigned) afs_socket_cookie);
559 return afs_server_socket[0];
562 static void server_init(int argc, char **argv)
564 struct server_cmdline_parser_params params = {
568 .check_ambiguity = 0,
575 /* parse command line options */
576 server_cmdline_parser_ext(argc, argv, &conf, ¶ms);
577 HANDLE_VERSION_FLAG("server", conf);
578 drop_privileges_or_die(conf.user_arg, conf.group_arg);
579 /* parse config file, open log and set defaults */
580 parse_config_or_die(0);
581 log_welcome("para_server", conf.loglevel_arg);
582 init_ipc_or_die(); /* init mmd struct and mmd->lock */
583 /* make sure, the global now pointer is uptodate */
584 gettimeofday(now, NULL);
585 server_uptime(UPTIME_SET); /* reset server uptime */
586 init_user_list(user_list_file);
588 if (conf.daemon_given)
590 PARA_NOTICE_LOG("initializing audio format handlers\n");
592 PARA_NOTICE_LOG("initializing the audio file selector\n");
593 afs_socket = init_afs();
595 PARA_NOTICE_LOG("initializing virtual streaming system\n");
596 init_vss_task(afs_socket);
597 init_server_command_task(argc, argv);
598 PARA_NOTICE_LOG("server init complete\n");
601 static void status_refresh(void)
603 static int prev_uptime = -1, prev_events = -1;
604 int uptime = server_uptime(UPTIME_GET), ret = 1;
606 if (prev_events != mmd->events)
608 if (mmd->new_vss_status_flags != mmd->vss_status_flags)
610 if (uptime / 60 != prev_uptime / 60)
616 prev_uptime = uptime;
617 prev_events = mmd->events;
618 mmd->vss_status_flags = mmd->new_vss_status_flags;
620 PARA_DEBUG_LOG("%d events, forcing status update\n",
626 static int server_select(int max_fileno, fd_set *readfds, fd_set *writefds,
627 struct timeval *timeout_tv)
632 mutex_unlock(mmd_mutex);
633 ret = para_select(max_fileno + 1, readfds, writefds, timeout_tv);
634 mutex_lock(mmd_mutex);
639 * The main function of para_server.
641 * \param argc Usual argument count.
642 * \param argv Usual argument vector.
644 * \return EXIT_SUCCESS or EXIT_FAILURE.
646 int main(int argc, char *argv[])
649 static struct sched s = {
654 .select_function = server_select
656 server_init(argc, argv);
657 mutex_lock(mmd_mutex);
660 PARA_EMERG_LOG("%s\n", para_strerror(-ret));