#include "ipc.h"
#include "list.h"
#include "sched.h"
-#include "signal.h"
#include "fd.h"
+#include "signal.h"
#include "mood.h"
#include "sideband.h"
#include "command.h"
static int server_socket;
static struct command_task command_task_struct;
-static struct signal_task signal_task_struct;
+static struct signal_task *signal_task;
static enum play_mode current_play_mode;
static char *current_mop; /* mode or playlist specifier. NULL means dummy mood */
{
int ret, socket_fd;
char *socket_name = conf.afs_socket_arg;
- struct sockaddr_un unix_addr;
unlink(socket_name);
- ret = create_local_socket(socket_name, &unix_addr,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH);
+ ret = create_local_socket(socket_name, 0);
if (ret < 0) {
- PARA_EMERG_LOG("%s: %s\n", para_strerror(-ret), socket_name);
- exit(EXIT_FAILURE);
+ ret = create_local_socket(socket_name,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH);
+ if (ret < 0) {
+ PARA_EMERG_LOG("%s: %s\n", para_strerror(-ret),
+ socket_name);
+ exit(EXIT_FAILURE);
+ }
}
socket_fd = ret;
- if (listen(socket_fd , 5) < 0) {
- PARA_EMERG_LOG("can not listen on socket\n");
- exit(EXIT_FAILURE);
- }
- ret = mark_fd_nonblocking(socket_fd);
- if (ret < 0) {
- close(socket_fd);
- return ret;
- }
PARA_INFO_LOG("listening on socket %s (fd %d)\n", socket_name,
socket_fd);
return socket_fd;
return ret;
}
-static void signal_pre_select(struct sched *s, void *context)
-{
- struct signal_task *st = context;
- para_fd_set(st->fd, &s->rfds, &s->max_fileno);
-}
-
static int afs_signal_post_select(struct sched *s, __a_unused void *context)
{
int signum, ret;
static void register_signal_task(struct sched *s)
{
- struct signal_task *st = &signal_task_struct;
-
para_sigaction(SIGPIPE, SIG_IGN);
- st->fd = para_signal_init();
- PARA_INFO_LOG("signal pipe: fd %d\n", st->fd);
+ signal_task = signal_init_or_die();
para_install_sighandler(SIGINT);
para_install_sighandler(SIGTERM);
para_install_sighandler(SIGHUP);
- st->task = task_register(&(struct task_info) {
+ signal_task->task = task_register(&(struct task_info) {
.name = "signal",
.pre_select = signal_pre_select,
.post_select = afs_signal_post_select,
- .context = st,
+ .context = signal_task,
}, s);
}
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;
*/
static struct status_task *stat_task = &status_task_struct;
- /**
- * the task for handling audiod commands
+ /*
+ * The task for handling audiod commands.
+ *
+ * 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.
*
- * \sa struct task, struct sched
+ * 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;
};
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);
}
/* 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 {
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)
-{
- struct signal_task *st = context;
- para_fd_set(st->fd, &s->rfds, &s->max_fileno);
-}
-
static int signal_post_select(struct sched *s, void *context)
{
struct signal_task *st = 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 = 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));
- if (ret == -E_AUDIOD_TERM) {
- task_notify_all(s, -ret);
- return ret;
- }
- } else if (ret > 0)
+ 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 */
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;
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",
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;
ret = schedule(&sched);
audiod_cleanup();
sched_shutdown(&sched);
+ signal_shutdown(signal_task);
if (ret < 0)
PARA_EMERG_LOG("%s\n", para_strerror(-ret));