Always check the return value of mark_fd_nonblocking().
[paraslash.git] / audiod.c
index dfb61db..df725f9 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2007 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -197,34 +197,34 @@ static void close_receiver(int slot_num)
        if (s->format < 0 || !s->receiver_node)
                return;
        a = &afi[s->format];
-       PARA_NOTICE_LOG("closing %s receiver in slot %d (eof = %d)\n",
-               audio_formats[s->format] , slot_num, s->receiver_node->eof);
+       PARA_NOTICE_LOG("closing %s receiver in slot %d\n",
+               audio_formats[s->format], slot_num);
        a->receiver->close(s->receiver_node);
        free(s->receiver_node);
        s->receiver_node = NULL;
 }
 
-static void kill_all_decoders(void)
+static void kill_all_decoders(int error)
 {
        int i;
 
        FOR_EACH_SLOT(i) {
                struct slot_info *s = &slot[i];
-               if (s->wng && !s->wng->eof) {
+               if (s->wng && !s->wng->error) {
                        PARA_INFO_LOG("unregistering writer node group in slot %d\n",
                                i);
                        wng_unregister(s->wng);
-                       s->wng->eof = 1;
+                       s->wng->error = error;
                }
-               if (s->fc && !s->fc->eof) {
+               if (s->fc && !s->fc->error) {
                        PARA_INFO_LOG("unregistering filter chain in slot %d\n", i);
                        unregister_task(&s->fc->task);
-                       s->fc->eof = 1;
+                       s->fc->error = error;
                }
-               if (s->receiver_node && !s->receiver_node->eof) {
+               if (s->receiver_node && !s->receiver_node->error) {
                        PARA_INFO_LOG("unregistering receiver_node in slot %d\n", i);
                        unregister_task(&s->receiver_node->task);
-                       s->receiver_node->eof = 1;
+                       s->receiver_node->error = error;
                }
        }
 }
@@ -264,9 +264,9 @@ int num_filters(int audio_format_num)
 
 static void filter_event_handler(struct task *t)
 {
-       PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-t->ret));
+       PARA_NOTICE_LOG("%s\n", para_strerror(-t->ret));
        struct filter_chain *fc = t->private_data;
-       fc->eof = 1;
+       fc->error = t->ret;
        unregister_task(t);
 }
 
@@ -285,13 +285,13 @@ static void open_filters(int slot_num)
        INIT_LIST_HEAD(&s->fc->filters);
        s->fc->inbuf = s->receiver_node->buf;
        s->fc->in_loaded = &s->receiver_node->loaded;
-       s->fc->input_eof = &s->receiver_node->eof;
+       s->fc->input_error = &s->receiver_node->error;
        s->fc->task.pre_select = filter_pre_select;
        s->fc->task.event_handler = filter_event_handler;
        s->fc->task.private_data = s->fc;
-       s->fc->eof = 0;
+       s->fc->error = 0;
 
-       s->receiver_node->output_eof = &s->fc->eof;
+       s->receiver_node->output_error = &s->fc->error;
        sprintf(s->fc->task.status, "filter chain");
        for (i = 0; i < nf; i++) {
                struct filter_node *fn = para_calloc(sizeof(struct filter_node));
@@ -314,8 +314,8 @@ static void wng_event_handler(struct task *t)
 {
        struct writer_node_group *wng = t->private_data;
 
-       PARA_INFO_LOG("%s\n", PARA_STRERROR(-t->ret));
-       wng->eof = 1;
+       PARA_INFO_LOG("%s\n", para_strerror(-t->ret));
+       wng->error = t->ret;
        wng_unregister(wng);
 }
 
@@ -333,15 +333,15 @@ static void open_writers(int slot_num)
        if (s->fc) {
                s->wng->buf = s->fc->outbuf;
                s->wng->loaded = s->fc->out_loaded;
-               s->wng->input_eof = &s->fc->eof;
+               s->wng->input_error = &s->fc->error;
                s->wng->channels = &s->fc->channels;
                s->wng->samplerate = &s->fc->samplerate;
-               s->fc->output_eof = &s->wng->eof;
+               s->fc->output_error = &s->wng->error;
                PARA_INFO_LOG("samplerate: %d\n", *s->wng->samplerate);
        } else {
                s->wng->buf = s->receiver_node->buf;
                s->wng->loaded = &s->receiver_node->loaded;
-               s->wng->input_eof = &s->receiver_node->eof;
+               s->wng->input_error = &s->receiver_node->error;
        }
        s->wng->task.event_handler = wng_event_handler;
        for (i = 0; i < a->num_writers; i++) {
@@ -350,7 +350,7 @@ static void open_writers(int slot_num)
        }
        ret = wng_open(s->wng);
        if (ret < 0) {
-               PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                return;
        }
        s->wstime = *now;
@@ -360,16 +360,19 @@ static void open_writers(int slot_num)
 static void rn_event_handler(struct task *t)
 {
        struct receiver_node *rn = t->private_data;
-       const struct timeval restart_delay = {0, 10 * 1000};
        int i;
 
-       PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-t->ret));
+       PARA_NOTICE_LOG("%s\n", para_strerror(-t->ret));
        unregister_task(t);
-       rn->eof = 1;
+       rn->error = t->ret;
        /* set restart barrier */
        FOR_EACH_SLOT(i) {
+               struct timeval restart_delay = {0, 10 * 1000};
                if (slot[i].receiver_node != rn)
                        continue;
+               if (rn->error != -E_RECV_EOF)
+                       /* don't reconnect immediately on errors */
+                       restart_delay.tv_sec = 5;
                tv_add(now, &restart_delay, &afi[slot[i].format].restart_barrier);
        }
 }
@@ -408,7 +411,7 @@ static int open_receiver(int format)
        register_task(&rn->task);
        return 1;
 err:
-       PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
        tv_add(now, &restart_delay, &afi[format].restart_barrier);
        return ret;
 }
@@ -420,7 +423,7 @@ static int receiver_running(int format)
        FOR_EACH_SLOT(i) {
                struct slot_info *s = &slot[i];
                if (s->format == format && s->receiver_node
-                               && !s->receiver_node->eof)
+                               && !s->receiver_node->error)
                        return 1;
        }
        return 0;
@@ -558,13 +561,13 @@ static void try_to_close_slot(int slot_num)
 
        if (s->format < 0)
                return;
-       if (s->receiver_node && !s->receiver_node->eof)
+       if (s->receiver_node && !s->receiver_node->error)
                return;
-       if (s->fc && !s->fc->eof)
+       if (s->fc && !s->fc->error)
                return;
-       if (s->wng && !s->wng->eof)
+       if (s->wng && !s->wng->error)
                return;
-       PARA_INFO_LOG("closing slot %d \n", slot_num);
+       PARA_INFO_LOG("closing slot %d\n", slot_num);
        wng_close(s->wng);
        close_filters(s->fc);
        free(s->fc);
@@ -585,7 +588,7 @@ static void audiod_pre_select(struct sched *s, __a_unused struct task *t)
 
        t->ret = 1;
        if (audiod_status != AUDIOD_ON || !stat_task->playing)
-               return kill_all_decoders();
+               return kill_all_decoders(-E_NOT_PLAYING);
        if (open_current_receiver(s))
                s->timeout = min_delay;
        FOR_EACH_SLOT(i) {
@@ -843,10 +846,11 @@ static int init_stream_io(void)
        return 1;
 }
 
+/* does not unlink socket on errors */
 static int audiod_get_socket(void)
 {
        struct sockaddr_un unix_addr;
-       int fd;
+       int ret, fd;
 
        if (conf.socket_given)
                socket_name = para_strdup(conf.socket_arg);
@@ -859,18 +863,22 @@ static int audiod_get_socket(void)
        PARA_NOTICE_LOG("local socket: %s\n", socket_name);
        if (conf.force_given)
                unlink(socket_name);
-       fd = create_local_socket(socket_name, &unix_addr,
-                       S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH);
-       if (fd < 0) {
-               PARA_EMERG_LOG("can not connect to socket\n");
-               exit(EXIT_FAILURE); /* do not unlink socket */
-       }
+       ret = create_local_socket(socket_name, &unix_addr,
+               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH);
+       if (ret < 0)
+               goto err;
+       fd = ret;
        if (listen(fd , 5) < 0) {
-               PARA_EMERG_LOG("can not listen on socket\n");
-               exit(EXIT_FAILURE); /* do not unlink socket */
+               ret = -ERRNO_TO_PARA_ERROR(errno);
+               goto err;
        }
-       mark_fd_nonblocking(fd);
+       ret = mark_fd_nonblocking(fd);
+       if (ret < 0)
+               goto err;
        return fd;
+err:
+       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+       exit(EXIT_FAILURE);
 }
 
 static void signal_event_handler(struct task *t)
@@ -930,7 +938,7 @@ static void command_post_select(struct sched *s, struct task *t)
                return;
        ret = handle_connect(ct->fd);
        if (ret < 0)
-               PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
 }
 
 static void init_command_task(struct command_task *ct)
@@ -1143,7 +1151,7 @@ int main(int argc, char *argv[])
        log_welcome("para_audiod", conf.loglevel_arg);
        i = init_stream_io();
        if (i < 0) {
-               PARA_EMERG_LOG("init stream io error: %s\n", PARA_STRERROR(-i));
+               PARA_EMERG_LOG("init stream io error: %s\n", para_strerror(-i));
                exit(EXIT_FAILURE);
        }
        server_uptime(UPTIME_SET);
@@ -1170,6 +1178,6 @@ int main(int argc, char *argv[])
        s.default_timeout.tv_usec = 99 * 1000;
        ret = schedule(&s);
 
-       PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
+       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
        return EXIT_FAILURE;
 }