X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=audiod.c;h=8f246ba53a04bad687af14d428bec276c822f001;hp=a072071c199d6fd3f90bb9448101ff62790c9db4;hb=218a175db8e7a43cad9073770ebdb24a7bdc64e8;hpb=4d9d588c5df359c3c5f279fbfd4ea51d3a2afc87 diff --git a/audiod.c b/audiod.c index a072071c..8f246ba5 100644 --- a/audiod.c +++ b/audiod.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -144,7 +144,7 @@ struct audiod_args_info conf; static char *socket_name; static struct audio_format_info afi[NUM_AUDIO_FORMATS]; -static struct signal_task signal_task_struct, *sig_task = &signal_task_struct; +static struct signal_task *signal_task; static struct status_task status_task_struct; @@ -155,14 +155,22 @@ static struct status_task status_task_struct; */ static struct status_task *stat_task = &status_task_struct; -/** - * the task for handling audiod commands +/* + * The task for handling audiod commands. * - * \sa struct task, struct sched + * We need two listening sockets for backward compability: on Linux systems + * fd[0] is an abstract socket (more precisely, a socket bound to an address in + * the abstract namespace), and fd[1] is the usual pathname socket. On other + * systems, fd[0] is negative, and only the pathname socket is used. + * + * For 0.5.x we accept connections on both sockets to make sure that old + * para_audioc versions can still connect. New versions use only the abstract + * socket. Hence after v0.6.0 we can go back to a single socket, either an + * abstract one (Linux) or a pathname socket (all other systems). */ struct command_task { - /** the local listening socket */ - int fd; + /** The local listening sockets. */ + int fd[2]; /** the associated task structure */ struct task *task; }; @@ -310,17 +318,6 @@ empty: return para_strdup(NULL); } -static int want_colors(void) -{ - if (conf.color_arg == color_arg_no) - return 0; - if (conf.color_arg == color_arg_yes) - return 1; - if (conf.logfile_given) - return 0; - return isatty(STDERR_FILENO); -} - static void parse_config_or_die(void) { int ret; @@ -358,8 +355,7 @@ err: static void setup_signal_handling(void) { - sig_task->fd = para_signal_init(); - PARA_INFO_LOG("signal pipe: fd %d\n", sig_task->fd); + signal_task = signal_init_or_die(); para_install_sighandler(SIGINT); para_install_sighandler(SIGTERM); para_install_sighandler(SIGHUP); @@ -390,6 +386,7 @@ static void close_receiver(int slot_num) task_reap(&s->receiver_node->task); free(s->receiver_node); s->receiver_node = NULL; + stat_task->current_audio_format_num = -1; tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000), &a->restart_barrier); } @@ -966,11 +963,8 @@ static int parse_stream_args(void) } /* does not unlink socket on errors */ -static int audiod_get_socket(void) +static void init_local_sockets(struct command_task *ct) { - struct sockaddr_un unix_addr; - int ret, fd; - if (conf.socket_given) socket_name = para_strdup(conf.socket_arg); else { @@ -982,40 +976,31 @@ static int audiod_get_socket(void) PARA_NOTICE_LOG("local socket: %s\n", socket_name); if (conf.force_given) unlink(socket_name); - ret = create_local_socket(socket_name, &unix_addr, + ct->fd[0] = create_local_socket(socket_name, 0); + ct->fd[1] = create_local_socket(socket_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH); - if (ret < 0) - goto err; - fd = ret; - if (listen(fd , 5) < 0) { - ret = -ERRNO_TO_PARA_ERROR(errno); - goto err; - } - ret = mark_fd_nonblocking(fd); - if (ret < 0) - goto err; - return fd; -err: - PARA_EMERG_LOG("%s\n", para_strerror(-ret)); + if (ct->fd[0] >= 0 || ct->fd[1] >= 0) + return; + PARA_EMERG_LOG("%s\n", para_strerror(-ct->fd[1])); exit(EXIT_FAILURE); } -static void signal_pre_select(struct sched *s, void *context) +static int signal_post_select(struct sched *s, void *context) { struct signal_task *st = context; - para_fd_set(st->fd, &s->rfds, &s->max_fileno); -} + int ret, signum; -static int signal_post_select(struct sched *s, __a_unused void *context) -{ - int signum; + ret = task_get_notification(st->task); + if (ret < 0) + return ret; signum = para_next_signal(&s->rfds); switch (signum) { case SIGINT: case SIGTERM: case SIGHUP: PARA_NOTICE_LOG("received signal %d\n", signum); - clean_exit(EXIT_FAILURE, "caught deadly signal"); + task_notify_all(s, E_AUDIOD_SIGNAL); + return -E_AUDIOD_SIGNAL; } return 0; } @@ -1023,21 +1008,38 @@ static int signal_post_select(struct sched *s, __a_unused void *context) static void command_pre_select(struct sched *s, void *context) { struct command_task *ct = context; - para_fd_set(ct->fd, &s->rfds, &s->max_fileno); + int i; + + for (i = 0; i < 2; i++) + if (ct->fd[i] >= 0) + para_fd_set(ct->fd[i], &s->rfds, &s->max_fileno); } static int command_post_select(struct sched *s, void *context) { - int ret; + int ret, i; struct command_task *ct = context; static struct timeval last_status_dump; struct timeval tmp, delay; - bool force = true; + bool force = false; - ret = handle_connect(ct->fd, &s->rfds); + ret = task_get_notification(ct->task); if (ret < 0) - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); - else if (ret > 0) + return ret; + for (i = 0; i < 2; i++) { + if (ct->fd[i] < 0) + continue; + ret = handle_connect(ct->fd[i], &s->rfds); + if (ret < 0) { + PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + if (ret == -E_AUDIOD_TERM) { + task_notify_all(s, -ret); + return ret; + } + } else if (ret > 0) + force = true; + } + if (force == true) goto dump; /* if last status dump was less than 500ms ago, do nothing */ @@ -1054,8 +1056,8 @@ static int command_post_select(struct sched *s, void *context) delay.tv_sec = 5; delay.tv_usec = 0; tv_add(&last_status_dump, &delay, &tmp); - if (tv_diff(now, &tmp, NULL) < 0) - force = false; + if (tv_diff(now, &tmp, NULL) > 0) + force = true; dump: audiod_status_dump(force); last_status_dump = *now; @@ -1064,7 +1066,7 @@ dump: static void init_command_task(struct command_task *ct) { - ct->fd = audiod_get_socket(); /* doesn't return on errors */ + init_local_sockets(ct); /* doesn't return on errors */ ct->task = task_register(&(struct task_info) { .name = "command", @@ -1140,19 +1142,13 @@ static void close_unused_slots(void) close_slot(i); } -/** - * Close the connection to para_server and exit. - * - * \param status The exit status which is passed to exit(3). - * \param msg The log message - * - * Log \a msg with loglevel \p EMERG, close the connection to para_server and - * all slots, and call \p exit(status). \a status should be either EXIT_SUCCESS - * or EXIT_FAILURE. +/* + * Cleanup all resources. * - * \sa exit(3). + * This performs various cleanups, removes the audiod socket and closes the + * connection to para_server. */ -void __noreturn clean_exit(int status, const char *msg) +static void audiod_cleanup(void) { if (socket_name) unlink(socket_name); @@ -1160,8 +1156,6 @@ void __noreturn clean_exit(int status, const char *msg) close_unused_slots(); audiod_cmdline_parser_free(&conf); close_stat_clients(); - PARA_EMERG_LOG("%s\n", msg); - exit(status); } /* @@ -1226,7 +1220,11 @@ min_delay: static int status_post_select(struct sched *s, void *context) { struct status_task *st = context; + int ret; + ret = task_get_notification(st->task); + if (ret < 0) + return ret; if (audiod_status == AUDIOD_OFF) { if (!st->ct) goto out; @@ -1241,7 +1239,6 @@ static int status_post_select(struct sched *s, void *context) if (st->ct) { char *buf; size_t sz; - int ret; ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF); if (ret < 0) { @@ -1350,18 +1347,6 @@ __noreturn static void print_help_and_die(void) exit(0); } -static void init_colors_or_die(void) -{ - int i; - - if (!want_colors()) - return; - daemon_set_default_log_colors(); - daemon_set_flag(DF_COLOR_LOG); - for (i = 0; i < conf.log_color_given; i++) - daemon_set_log_color_or_die(conf.log_color_arg[i]); -} - /** * the main function of para_audiod * @@ -1396,7 +1381,8 @@ int main(int argc, char *argv[]) print_help_and_die(); daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg); parse_config_or_die(); - init_colors_or_die(); + daemon_init_colors_or_die(conf.color_arg, color_arg_auto, color_arg_no, + conf.logfile_given, conf.log_color_arg, conf.log_color_given); init_random_seed_or_die(); daemon_set_flag(DF_LOG_TIME); daemon_set_flag(DF_LOG_HOSTNAME); @@ -1425,18 +1411,21 @@ int main(int argc, char *argv[]) if (conf.daemon_given) daemonize(false /* parent exits immediately */); - sig_task->task = task_register(&(struct task_info) { + signal_task->task = task_register(&(struct task_info) { .name = "signal", .pre_select = signal_pre_select, .post_select = signal_post_select, - .context = sig_task, + .context = signal_task, }, &sched); sched.default_timeout.tv_sec = 2; sched.default_timeout.tv_usec = 999 * 1000; ret = schedule(&sched); + audiod_cleanup(); sched_shutdown(&sched); + signal_shutdown(signal_task); - PARA_EMERG_LOG("%s\n", para_strerror(-ret)); - return EXIT_FAILURE; + if (ret < 0) + PARA_EMERG_LOG("%s\n", para_strerror(-ret)); + return ret < 0? EXIT_FAILURE : EXIT_SUCCESS; }