Remove socket address parameter of create_local_socket().
[paraslash.git] / audiod.c
index f12dbc1b999a0892abdcea5791692f1f5dfab3c3..40f02f74907c1b1b60778acb4a742c018fb51014 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -93,14 +93,10 @@ enum vss_status_flags {
  */
 struct sched sched = {.max_fileno = 0};
 
-/**
- * The task for obtaining para_server's status (para_client stat).
- *
- * \sa struct task, struct sched.
- */
+/* The task for obtaining para_server's status (para_client stat). */
 struct status_task {
        /** The associated task structure of audiod. */
-       struct task task;
+       struct task *task;
        /** Client data associated with the stat task. */
        struct client_task *ct;
        /** Do not restart client command until this time. */
@@ -168,7 +164,7 @@ struct command_task {
        /** the local listening socket */
        int fd;
        /** the associated task structure */
-       struct task task;
+       struct task *task;
 };
 
 /** iterate over all supported audio formats */
@@ -219,7 +215,7 @@ static int get_matching_audio_format_nums(const char *re)
  * from the status items received from para_server and the start time of the
  * (first) writer of the given slot.
  *
- * It has to to take into account that probably the stream was not started at
+ * It has to take into account that the stream was probably not started at
  * the beginning of the file, that the clock between the server and the client
  * host may differ and that playback of the stream was delayed, e.g. because
  * the prebuffer filter is used in the filter configuration of the given slot.
@@ -314,17 +310,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;
@@ -391,8 +376,10 @@ static void close_receiver(int slot_num)
                audio_formats[s->format], slot_num);
        a->receiver->close(s->receiver_node);
        btr_remove_node(&s->receiver_node->btrn);
+       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);
 }
@@ -407,6 +394,7 @@ static void writer_cleanup(struct writer_node *wn)
        PARA_INFO_LOG("closing %s\n", writer_names[wn->writer_num]);
        w->close(wn);
        btr_remove_node(&wn->btrn);
+       task_reap(&wn->task);
 }
 
 static void close_writers(struct slot_info *s)
@@ -444,6 +432,7 @@ static void close_filters(struct slot_info *s)
                if (f->close)
                        f->close(fn);
                btr_remove_node(&fn->btrn);
+               task_reap(&fn->task);
        }
        free(s->fns);
        s->fns = NULL;
@@ -459,7 +448,7 @@ static void notify_receivers(int error)
                        continue;
                if (!s->receiver_node)
                        continue;
-               task_notify(&s->receiver_node->task, error);
+               task_notify(s->receiver_node->task, error);
        }
 }
 
@@ -497,22 +486,26 @@ static void open_filters(struct slot_info *s)
        s->fns = para_calloc(nf * sizeof(struct filter_node));
        parent = s->receiver_node->btrn;
        for (i = 0; i < nf; i++) {
+               char buf[20];
                struct filter *f = filters + a->filter_nums[i];
                fn = s->fns + i;
                fn->filter_num = a->filter_nums[i];
                fn->conf = a->filter_conf[i];
-               fn->task.pre_select = f->pre_select;
-               fn->task.post_select = f->post_select;
                fn->btrn = btr_new_node(&(struct btr_node_description)
                        EMBRACE(.name = f->name, .parent = parent,
                                .handler = f->execute, .context = fn));
 
                f->open(fn);
-               register_task(&sched, &fn->task);
+               sprintf(buf, "%s (slot %d)", f->name, (int)(s - slot));
+               fn->task = task_register(&(struct task_info) {
+                       .name = buf,
+                       .pre_select = f->pre_select,
+                       .post_select = f->post_select,
+                       .context = fn,
+               }, &sched);
                parent = fn->btrn;
                PARA_NOTICE_LOG("%s filter %d/%d (%s) started in slot %d\n",
                        audio_formats[s->format], i,  nf, f->name, (int)(s - slot));
-               sprintf(fn->task.status, "%s (slot %d)", f->name, (int)(s - slot));
        }
 }
 
@@ -566,10 +559,12 @@ static int open_receiver(int format)
        s->receiver_node = rn;
        PARA_NOTICE_LOG("started %s: %s receiver in slot %d\n",
                audio_formats[format], r->name, slot_num);
-       rn->task.pre_select = r->pre_select;
-       rn->task.post_select = r->post_select;
-       sprintf(rn->task.status, "%s receiver node", r->name);
-       register_task(&sched, &rn->task);
+       rn->task = task_register(&(struct task_info) {
+               .name = r->name,
+               .pre_select = r->pre_select,
+               .post_select = r->post_select,
+               .context = rn,
+       }, &sched);
        return slot_num;
 }
 
@@ -584,7 +579,7 @@ static bool receiver_running(void)
 
                if (!s->receiver_node)
                        continue;
-               if (s->receiver_node->task.error >= 0)
+               if (task_status(s->receiver_node->task) >= 0)
                        return true;
                if (ss1 == ss2)
                        return true;
@@ -611,7 +606,7 @@ struct btr_node *audiod_get_btr_root(void)
                struct timeval rstime;
                if (!s->receiver_node)
                        continue;
-               if (s->receiver_node->task.error < 0)
+               if (task_status(s->receiver_node->task) < 0)
                        continue;
                btr_get_node_start(s->receiver_node->btrn, &rstime);
                if (newest_slot >= 0 && tv_diff(&rstime, &newest_rstime, NULL) < 0)
@@ -647,7 +642,7 @@ static bool must_start_decoder(void)
        return true;
 }
 
-static unsigned compute_time_diff(const struct timeval *status_time)
+static void compute_time_diff(const struct timeval *status_time)
 {
        struct timeval tmp, diff;
        static unsigned count;
@@ -655,8 +650,6 @@ static unsigned compute_time_diff(const struct timeval *status_time)
        const struct timeval max_deviation = {0, 500 * 1000};
        const int time_smooth = 5;
 
-       if (!status_time)
-               return count;
        sign = tv_diff(status_time, now, &diff);
 //             PARA_NOTICE_LOG("%s: sign = %i, sa_time_diff_sign = %i\n", __func__,
 //                     sign, sa_time_diff_sign);
@@ -686,7 +679,6 @@ static unsigned compute_time_diff(const struct timeval *status_time)
        );
 out:
        stat_task->sa_time_diff_sign = sa_time_diff_sign;
-       return count;
 }
 
 static int update_item(int itemnum, char *buf)
@@ -966,7 +958,6 @@ static int parse_stream_args(void)
 /* does not unlink socket on errors */
 static int audiod_get_socket(void)
 {
-       struct sockaddr_un unix_addr;
        int ret, fd;
 
        if (conf.socket_given)
@@ -980,7 +971,7 @@ 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,
+       ret = create_local_socket(socket_name,
                S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH);
        if (ret < 0)
                goto err;
@@ -998,52 +989,57 @@ err:
        exit(EXIT_FAILURE);
 }
 
-static void signal_pre_select(struct sched *s, struct task *t)
+static void signal_pre_select(struct sched *s, void *context)
 {
-       struct signal_task *st = container_of(t, struct signal_task, task);
+       struct signal_task *st = context;
        para_fd_set(st->fd, &s->rfds, &s->max_fileno);
 }
 
-static int signal_post_select(struct sched *s, __a_unused struct task *t)
+static int signal_post_select(struct sched *s, void *context)
 {
-       int signum;
+       struct signal_task *st = context;
+       int ret, 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;
 }
 
-static void signal_setup_default(struct signal_task *st)
+static void command_pre_select(struct sched *s, void *context)
 {
-       st->task.pre_select = signal_pre_select;
-       st->task.post_select = signal_post_select;
-       sprintf(st->task.status, "signal task");
-}
-
-static void command_pre_select(struct sched *s, struct task *t)
-{
-       struct command_task *ct = container_of(t, struct command_task, task);
+       struct command_task *ct = context;
        para_fd_set(ct->fd, &s->rfds, &s->max_fileno);
 }
 
-static int command_post_select(struct sched *s, struct task *t)
+static int command_post_select(struct sched *s, void *context)
 {
        int ret;
-       struct command_task *ct = container_of(t, struct command_task, task);
+       struct command_task *ct = context;
        static struct timeval last_status_dump;
        struct timeval tmp, delay;
        bool force = true;
 
-       ret = handle_connect(ct->fd, &s->rfds);
+       ret = task_get_notification(ct->task);
        if (ret < 0)
+               return ret;
+       ret = handle_connect(ct->fd, &s->rfds);
+       if (ret < 0) {
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
-       else if (ret > 0)
+               if (ret == -E_AUDIOD_TERM) {
+                       task_notify_all(s, -ret);
+                       return ret;
+               }
+       } else if (ret > 0)
                goto dump;
 
        /* if last status dump was less than 500ms ago, do nothing */
@@ -1070,17 +1066,21 @@ dump:
 
 static void init_command_task(struct command_task *ct)
 {
-       ct->task.pre_select = command_pre_select;
-       ct->task.post_select = command_post_select;
-       ct->task.error = 0;
        ct->fd = audiod_get_socket(); /* doesn't return on errors */
-       sprintf(ct->task.status, "command task");
+
+       ct->task = task_register(&(struct task_info) {
+               .name = "command",
+               .pre_select = command_pre_select,
+               .post_select = command_post_select,
+               .context = ct,
+       }, &sched);
 }
 
 static void close_stat_pipe(void)
 {
        if (!stat_task->ct)
                return;
+       task_reap(&stat_task->ct->task);
        client_close(stat_task->ct);
        stat_task->ct = NULL;
        clear_and_dump_items();
@@ -1106,17 +1106,17 @@ static bool must_close_slot(int slot_num)
 
        if (s->format < 0)
                return false;
-       if (s->receiver_node && s->receiver_node->task.error >= 0)
+       if (s->receiver_node && task_status(s->receiver_node->task) >= 0)
                return false;
        for (i = 0; i < a->num_filters; i++)
-               if (s->fns && s->fns[i].task.error >= 0)
+               if (s->fns && task_status(s->fns[i].task) >= 0)
                        return false;
        if (a->num_writers > 0) {
                for (i = 0; i < a->num_writers; i++)
-                       if (s->wns && s->wns[i].task.error >= 0)
+                       if (s->wns && task_status(s->wns[i].task) >= 0)
                                return false;
        } else {
-               if (s->wns && s->wns[0].task.error >= 0)
+               if (s->wns && task_status(s->wns[0].task) >= 0)
                        return false;
        }
        return true;
@@ -1142,31 +1142,20 @@ 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)
 {
-       int i;
-
        if (socket_name)
                unlink(socket_name);
        close_stat_pipe();
-       FOR_EACH_SLOT(i)
-               close_slot(i);
+       close_unused_slots();
        audiod_cmdline_parser_free(&conf);
        close_stat_clients();
-       PARA_EMERG_LOG("%s\n", msg);
-       exit(status);
 }
 
 /*
@@ -1177,7 +1166,6 @@ static void start_stop_decoders(void)
 {
        int ret;
        struct slot_info *sl;
-       struct audio_format_info *a;
 
        close_unused_slots();
        if (audiod_status != AUDIOD_ON ||
@@ -1191,17 +1179,15 @@ static void start_stop_decoders(void)
                return;
        }
        sl = slot + ret;
-       a = afi + sl->format;
-       if (a->num_filters)
-               open_filters(sl);
+       open_filters(sl);
        open_writers(sl);
        activate_grab_clients(&sched);
        btr_log_tree(sl->receiver_node->btrn, LL_NOTICE);
 }
 
-static void status_pre_select(struct sched *s, struct task *t)
+static void status_pre_select(struct sched *s, void *context)
 {
-       struct status_task *st = container_of(t, struct status_task, task);
+       struct status_task *st = context;
        int i, ret, cafn = stat_task->current_audio_format_num;
 
        if (must_start_decoder())
@@ -1231,15 +1217,19 @@ min_delay:
 }
 
 /* restart the client task if necessary */
-static int status_post_select(struct sched *s, struct task *t)
+static int status_post_select(struct sched *s, void *context)
 {
-       struct status_task *st = container_of(t, struct status_task, task);
+       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;
-               if (st->ct->task.error >= 0) {
-                       task_notify(&st->ct->task, E_AUDIOD_OFF);
+               if (task_status(st->ct->task) >= 0) {
+                       task_notify(st->ct->task, E_AUDIOD_OFF);
                        goto out;
                }
                close_stat_pipe();
@@ -1249,7 +1239,6 @@ static int status_post_select(struct sched *s, struct task *t)
        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) {
@@ -1262,14 +1251,14 @@ static int status_post_select(struct sched *s, struct task *t)
                        struct timeval diff;
                        tv_diff(now, &st->last_status_read, &diff);
                        if (diff.tv_sec > 61)
-                               task_notify(&st->ct->task, E_STATUS_TIMEOUT);
+                               task_notify(st->ct->task, E_STATUS_TIMEOUT);
                        goto out;
                }
                btr_merge(st->btrn, st->min_iqs);
                sz = btr_next_buffer(st->btrn, &buf);
                ret = for_each_stat_item(buf, sz, update_item);
                if (ret < 0) {
-                       task_notify(&st->ct->task, -ret);
+                       task_notify(st->ct->task, -ret);
                        goto out;
                }
                if (sz != ret) {
@@ -1311,14 +1300,18 @@ out:
 static void init_status_task(struct status_task *st)
 {
        memset(st, 0, sizeof(struct status_task));
-       st->task.pre_select = status_pre_select;
-       st->task.post_select = status_post_select;
        st->sa_time_diff_sign = 1;
        st->clock_diff_count = conf.clock_diff_count_arg;
        st->current_audio_format_num = -1;
-       sprintf(st->task.status, "stat");
        st->btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = "stat"));
+
+       stat_task->task = task_register(&(struct task_info) {
+               .name = "stat",
+               .pre_select = status_pre_select,
+               .post_select = status_post_select,
+               .context = stat_task,
+       }, &sched);
 }
 
 static void set_initial_status(void)
@@ -1354,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
  *
@@ -1398,9 +1379,10 @@ int main(int argc, char *argv[])
        writer_init();
        if (conf.help_given || conf.detailed_help_given)
                print_help_and_die();
-       drop_privileges_or_die(conf.user_arg, conf.group_arg);
+       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);
@@ -1416,13 +1398,12 @@ int main(int argc, char *argv[])
                PARA_EMERG_LOG("%s\n", para_strerror(-ret));
                exit(EXIT_FAILURE);
        }
-       log_welcome("para_audiod");
-       set_server_start_time(NULL);
+       daemon_log_welcome("para_audiod");
+       daemon_set_start_time();
        set_initial_status();
        FOR_EACH_SLOT(i)
                clear_slot(i);
        setup_signal_handling();
-       signal_setup_default(sig_task);
 
        init_status_task(stat_task);
        init_command_task(cmd_task);
@@ -1430,13 +1411,20 @@ int main(int argc, char *argv[])
        if (conf.daemon_given)
                daemonize(false /* parent exits immediately */);
 
-       register_task(&sched, &sig_task->task);
-       register_task(&sched, &cmd_task->task);
-       register_task(&sched, &stat_task->task);
+       sig_task->task = task_register(&(struct task_info) {
+               .name = "signal",
+               .pre_select = signal_pre_select,
+               .post_select = signal_post_select,
+               .context = sig_task,
+       }, &sched);
+
        sched.default_timeout.tv_sec = 2;
        sched.default_timeout.tv_usec = 999 * 1000;
        ret = schedule(&sched);
+       audiod_cleanup();
+       sched_shutdown(&sched);
 
-       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;
 }