X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=audiod.c;h=accf0244f957809b9c55b7e56b61127492264d62;hp=acf41376f50f196414d327bfb11f506c4fe8d7e2;hb=213b3181e7f8ebd07ec37e256188ea9094722cef;hpb=fdbdd1fd575d7d37d4fb182252107a4d3816853c diff --git a/audiod.c b/audiod.c index acf41376..accf0244 100644 --- a/audiod.c +++ b/audiod.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "para.h" #include "error.h" @@ -68,6 +69,30 @@ struct audio_format_info { struct timeval restart_barrier; }; +/* Describes one instance of a receiver-filter-writer chain. */ +struct slot_info { + /* Number of the audio format in this slot. */ + int format; + /* The stream_start status item announced by para_server. */ + struct timeval server_stream_start; + /* The offset status item announced by para_server. */ + unsigned offset_seconds; + /* The seconds_total status item announced by para_server. */ + unsigned seconds_total; + /* The receiver info associated with this slot. */ + struct receiver_node *receiver_node; + /* The array of filter nodes. */ + struct filter_node *fns; + /* The array of writers attached to the last filter. */ + struct writer_node *wns; +}; + +/** Maximal number of simultaneous instances. */ +#define MAX_STREAM_SLOTS 5 + +/** Iterate over all slots. */ +#define FOR_EACH_SLOT(_slot) for (_slot = 0; _slot < MAX_STREAM_SLOTS; _slot++) + /** * para_audiod uses \p MAX_STREAM_SLOTS different slots, each of which may * be associated with a receiver/filter/writer triple. This array holds all @@ -144,10 +169,12 @@ 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; +static uid_t *uid_whitelist; + /** * the task that calls the status command of para_server * @@ -198,6 +225,35 @@ static int get_audio_format_num(const char *name) return -E_UNSUPPORTED_AUDIO_FORMAT; } +/** + * Return the flags for the \a decoder_flags status item. + * + * Allocates a string which contains one octal digit per slot. Bit zero (value + * 1) is set if a receiver is active. Bit one (value 2) and bit three (value 4) + * have the analogous meaning for filter and writer, respectively. + * + * \return String that must be freed by the caller. + */ +__malloc char *audiod_get_decoder_flags(void) +{ + int i; + char flags[MAX_STREAM_SLOTS + 1]; + + FOR_EACH_SLOT(i) { + struct slot_info *s = &slot[i]; + char flag = '0'; + if (s->receiver_node) + flag += 1; + if (s->fns) + flag += 2; + if (s->wns) + flag += 4; + flags[i] = flag; + } + flags[MAX_STREAM_SLOTS] = '\0'; + return para_strdup(flags); +} + static int get_matching_audio_format_nums(const char *re) { int i, ret; @@ -214,28 +270,44 @@ static int get_matching_audio_format_nums(const char *re) return ret; } +static int get_play_time_slot_num(void) +{ + int i, oldest_slot = -1; + struct timeval oldest_wstime = {0, 0}; + + FOR_EACH_SLOT(i) { + struct slot_info *s = &slot[i]; + struct timeval wstime; + if (!s->wns || !s->wns[0].btrn) + continue; + btr_get_node_start(s->wns[0].btrn, &wstime); + if (oldest_slot >= 0 && tv_diff(&wstime, &oldest_wstime, NULL) > 0) + continue; + oldest_wstime = wstime; + oldest_slot = i; + } + return oldest_slot; +} + /** - * Compute the play time based on information of the given slot. - * - * \param slot_num The slot number (negative means: no slot). + * Compute the play time based on information of the current slot. * * This computes a string of the form "0:07 [3:33] (3%/3:40)" using information * from the status items received from para_server and the start time of the - * (first) writer of the given slot. + * (first) writer of the current slot. * * 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. + * the prebuffer filter is used in the filter configuration. * - * If no writer is active in the given slot, or \a slot_num is negative - * (indicating that para_audiod runs in standby mode), an approximation based - * only on the status items is computed and the returned string is prefixed - * with "~". + * If no writer is active, for example because para_audiod runs in standby + * mode, an approximation based only on the status items is computed and the + * returned string is prefixed with "~". * * \return A string that must be freed by the caller. */ -char *get_time_string(int slot_num) +char *get_time_string(void) { int ret, seconds = 0, length; struct timeval *tmp, sum, sss, /* server stream start */ @@ -243,6 +315,7 @@ char *get_time_string(int slot_num) wstime, /* writer start time */ wtime, /* now - writer start */ rskip; /* receiver start - sss */ + int slot_num = get_play_time_slot_num(); struct slot_info *s = slot_num < 0? NULL : &slot[slot_num]; char *msg; @@ -320,7 +393,7 @@ empty: static void parse_config_or_die(void) { - int ret; + int ret, i; char *config_file; struct audiod_cmdline_parser_params params = { .override = 0, @@ -340,6 +413,7 @@ static void parse_config_or_die(void) ret = file_exists(config_file); if (conf.config_file_given && !ret) { PARA_EMERG_LOG("can not read config file %s\n", config_file); + free(config_file); goto err; } if (ret) { @@ -347,16 +421,35 @@ static void parse_config_or_die(void) daemon_set_loglevel(conf.loglevel_arg); } free(config_file); + if (conf.user_allow_given > 0) { + uid_whitelist = para_malloc(conf.user_allow_given + * sizeof(uid_t)); + for (i = 0; i < conf.user_allow_given; i++) { + int32_t val; + struct passwd *pw; + ret = para_atoi32(conf.user_allow_arg[i], &val); + if (ret >= 0) { + uid_whitelist[i] = val; + continue; + } + errno = 0; /* see getpwnam(3) */ + pw = getpwnam(conf.user_allow_arg[i]); + if (!pw) { + PARA_EMERG_LOG("invalid username: %s\n", + conf.user_allow_arg[i]); + goto err; + } + uid_whitelist[i] = pw->pw_uid; + } + } return; err: - free(config_file); exit(EXIT_FAILURE); } 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); @@ -986,12 +1079,6 @@ static void init_local_sockets(struct command_task *ct) 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; @@ -1036,7 +1123,7 @@ static int command_post_select(struct sched *s, void *context) for (i = 0; i < 2; i++) { if (ct->fd[i] < 0) continue; - ret = handle_connect(ct->fd[i], &s->rfds); + ret = handle_connect(ct->fd[i], &s->rfds, uid_whitelist); if (ret < 0) { PARA_ERROR_LOG("%s\n", para_strerror(-ret)); if (ret == -E_AUDIOD_TERM) { @@ -1163,6 +1250,7 @@ static void audiod_cleanup(void) close_unused_slots(); audiod_cmdline_parser_free(&conf); close_stat_clients(); + free(uid_whitelist); } /* @@ -1405,7 +1493,7 @@ int main(int argc, char *argv[]) PARA_EMERG_LOG("%s\n", para_strerror(-ret)); exit(EXIT_FAILURE); } - daemon_log_welcome("para_audiod"); + daemon_log_welcome("audiod"); daemon_set_start_time(); set_initial_status(); FOR_EACH_SLOT(i) @@ -1418,11 +1506,11 @@ 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; @@ -1430,6 +1518,7 @@ int main(int argc, char *argv[]) ret = schedule(&sched); audiod_cleanup(); sched_shutdown(&sched); + signal_shutdown(signal_task); if (ret < 0) PARA_EMERG_LOG("%s\n", para_strerror(-ret));