X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=audiod.c;h=119adbc0be2ddbf24a7d06de4b77a5a3d88bd230;hp=2351a8ed82d1a13aa6de9e24f9e25aa23e3aa010;hb=55adba3f7fc5619bd433c13d07ecb62e7b4d46a8;hpb=15d4c69ddcf88dd9046ed8d2847a428145a32045 diff --git a/audiod.c b/audiod.c index 2351a8ed..119adbc0 100644 --- a/audiod.c +++ b/audiod.c @@ -1,8 +1,4 @@ -/* - * Copyright (C) 2005 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ +/* Copyright (C) 2005 Andre Noll , see file COPYING. */ /** \file audiod.c The paraslash's audio daemon. */ @@ -21,6 +17,7 @@ #include "recv_cmd.lsg.h" #include "para.h" #include "error.h" +#include "lsu.h" #include "crypt.h" #include "list.h" #include "sched.h" @@ -109,9 +106,7 @@ struct slot_info { * 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 * information on the status of these slots. - * - * \sa struct slot_info - * */ + */ struct slot_info slot[MAX_STREAM_SLOTS]; /** The vss status flags audiod is interested in. */ @@ -167,8 +162,8 @@ struct status_task { char *stat_item_values[NUM_STAT_ITEMS] = {NULL}; /** - * the current mode of operation of which can be changed by the on/off/cycle - * commands. It is either, AUDIOD_OFF, AUDIOD_ON or AUDIOD_STANDBY. + * The current mode of operation (AUDIOD_OFF, AUDIOD_ON or AUDIOD_STANDBY). + * Set by the on/off/cycle commands. */ int audiod_status = AUDIOD_ON; @@ -179,33 +174,20 @@ static struct status_task status_task_struct; static uid_t *uid_whitelist; /** - * the task that calls the status command of para_server + * The task that calls the status command of para_server. * - * \sa struct status_task + * \sa \ref struct status_task. */ static struct status_task *stat_task = &status_task_struct; -/* - * 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. - * - * 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 sockets. */ - int fd[2]; - /** the associated task structure */ + /** The local listening socket. */ + int fd; + /** The associated task structure. */ struct task *task; }; -/** iterate over all supported audio formats */ +/** Iterate over all supported audio formats. */ #define FOR_EACH_AUDIO_FORMAT(af) for (af = 0; af < NUM_AUDIO_FORMATS; af++) /** @@ -320,6 +302,7 @@ char *get_time_string(void) rskip; /* receiver start - sss */ int slot_num = get_play_time_slot_num(); struct slot_info *s = slot_num < 0? NULL : &slot[slot_num]; + bool writer_active = s && s->wns && s->wns[0].btrn; char *msg; if (audiod_status == AUDIOD_OFF) @@ -333,11 +316,11 @@ char *get_time_string(void) } /* * Valid status items and playing, set length and tmp to the stream - * start. We use the slot info and fall back to the info from current - * status items if no slot info is available. + * start. We use the writer start time from the slot info and fall back + * to the info from current status items if no writer is active yet. */ tmp = &stat_task->server_stream_start; - if (s && s->wns && s->wns[0].btrn) { /* writer active in this slot */ + if (writer_active) { btr_get_node_start(s->wns[0].btrn, &wstime); if (wstime.tv_sec != 0) { /* writer wrote something */ if (s->server_stream_start.tv_sec == 0) { @@ -354,7 +337,7 @@ char *get_time_string(void) tv_diff(tmp, &stat_task->sa_time_diff, &sss); else tv_add(tmp, &stat_task->sa_time_diff, &sss); - if (!s || !s->wns || !s->wns[0].btrn || wstime.tv_sec == 0) { + if (!writer_active) { struct timeval diff; tv_diff(now, &sss, &diff); seconds = diff.tv_sec + stat_task->offset_seconds; @@ -396,81 +379,36 @@ empty: static void parse_config_or_die(void) { - int ret; - char *cf, *errctx = NULL; - void *map; - size_t sz; + int i, ret; + uint32_t n; - if (OPT_GIVEN(CONFIG_FILE)) - cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE)); - else { - char *home = para_homedir(); - cf = make_message("%s/.paraslash/audiod.conf", home); - free(home); - } - ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL); + ret = lsu_merge_config_file_options(OPT_STRING_VAL(CONFIG_FILE), + "audiod.conf", &lpr, CMD_PTR, audiod_suite, 0U /* flags */); if (ret < 0) { - if (ret != -E_EMPTY && ret != -ERRNO_TO_PARA_ERROR(ENOENT)) - goto free_cf; - if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && OPT_GIVEN(CONFIG_FILE)) - goto free_cf; - } else { - int cf_argc; - char **cf_argv; - struct lls_parse_result *cf_lpr, *merged_lpr; - ret = lls(lls_convert_config(map, sz, NULL, &cf_argv, &errctx)); - para_munmap(map, sz); - if (ret < 0) - goto free_cf; - cf_argc = ret; - ret = lls(lls_parse(cf_argc, cf_argv, CMD_PTR, &cf_lpr, &errctx)); - lls_free_argv(cf_argv); - if (ret < 0) - goto free_cf; - ret = lls(lls_merge(lpr, cf_lpr, CMD_PTR, &merged_lpr, - &errctx)); - lls_free_parse_result(cf_lpr, CMD_PTR); - if (ret < 0) - goto free_cf; - lls_free_parse_result(lpr, CMD_PTR); - lpr = merged_lpr; + PARA_EMERG_LOG("failed to parse config file: %s\n", + para_strerror(-ret)); + exit(EXIT_FAILURE); } daemon_set_loglevel(ENUM_STRING_VAL(LOGLEVEL)); - if (OPT_GIVEN(USER_ALLOW)) { - uint32_t n = OPT_GIVEN(USER_ALLOW); - int i; - - uid_whitelist = para_malloc(n * sizeof(uid_t)); - for (i = 0; i < n; i++) { - const char *arg = lls_string_val(i, - OPT_RESULT(USER_ALLOW)); - int32_t val; - struct passwd *pw; - ret = para_atoi32(arg, &val); - if (ret >= 0) { - uid_whitelist[i] = val; - continue; - } - errno = 0; /* see getpwnam(3) */ - pw = getpwnam(arg); - if (!pw) { - PARA_EMERG_LOG("invalid username: %s\n", arg); - free(uid_whitelist); - goto free_cf; - } - uid_whitelist[i] = pw->pw_uid; + n = OPT_GIVEN(USER_ALLOW); + if (n == 0) + return; + uid_whitelist = para_malloc(n * sizeof(uid_t)); + for (i = 0; i < n; i++) { + const char *arg = lls_string_val(i, OPT_RESULT(USER_ALLOW)); + int32_t val; + struct passwd *pw; + ret = para_atoi32(arg, &val); + if (ret >= 0) { + uid_whitelist[i] = val; + continue; } - } - ret = 0; -free_cf: - free(cf); - if (ret < 0) { - if (errctx) - PARA_ERROR_LOG("%s\n", errctx); - free(errctx); - lls_free_parse_result(lpr, CMD_PTR); - PARA_EMERG_LOG("%s\n", para_strerror(-ret)); - exit(EXIT_FAILURE); + pw = getpwnam(arg); + if (!pw) { + PARA_EMERG_LOG("invalid username: %s\n", arg); + exit(EXIT_FAILURE); + } + uid_whitelist[i] = pw->pw_uid; } } @@ -507,7 +445,8 @@ 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; + if (audiod_status == AUDIOD_ON) + stat_task->current_audio_format_num = -1; tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000), &a->restart_barrier); } @@ -541,6 +480,23 @@ static void close_writers(struct slot_info *s) s->wns = NULL; } +static void notify_writers(int error) +{ + int i; + + FOR_EACH_SLOT(i) { + struct slot_info *s = slot + i; + struct audio_format_info *a; + int j; + + if (s->format < 0) + continue; + a = afi + s->format; + for (j = 0; j < a->num_writers; j++) + task_notify(s->wns[j].task, error); + } +} + static void close_filters(struct slot_info *s) { int i; @@ -680,6 +636,7 @@ static int open_receiver(int format) EMBRACE(.name = name, .context = rn)); ret = r->open(rn); if (ret < 0) { + PARA_ERROR_LOG("could not open %s receiver\n", name); btr_remove_node(&rn->btrn); free(rn); return ret; @@ -792,8 +749,8 @@ static void compute_time_diff(const struct timeval *status_time) if (count > 5) { int s = tv_diff(&diff, &stat_task->sa_time_diff, &tmp); if (tv_diff(&max_deviation, &tmp, NULL) < 0) - PARA_WARNING_LOG("time diff jump: %lums\n", - s * tv2ms(&tmp)); + PARA_WARNING_LOG("time diff jump: %c%lums\n", + s < 0? '-' : '+', tv2ms(&tmp)); } count++; sa_time_diff_sign = tv_convex_combination( @@ -815,38 +772,38 @@ static int update_item(int itemnum, char *buf) { long unsigned sec, usec; - if (stat_task->clock_diff_count && itemnum != SI_CURRENT_TIME) + if (stat_task->clock_diff_count && itemnum != SI_current_time) return 1; free(stat_item_values[itemnum]); stat_item_values[itemnum] = para_strdup(buf); stat_client_write_item(itemnum); switch (itemnum) { - case SI_STATUS_FLAGS: + case SI_status_flags: stat_task->vss_status = 0; if (strchr(buf, 'N')) stat_task->vss_status |= VSS_STATUS_FLAG_NEXT; if (strchr(buf, 'P')) stat_task->vss_status |= VSS_STATUS_FLAG_PLAYING; break; - case SI_OFFSET: + case SI_offset: stat_task->offset_seconds = atoi(buf); break; - case SI_SECONDS_TOTAL: + case SI_seconds_total: stat_task->length_seconds = atoi(buf); break; - case SI_STREAM_START: + case SI_stream_start: if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) { stat_task->server_stream_start.tv_sec = sec; stat_task->server_stream_start.tv_usec = usec; } break; - case SI_CURRENT_TIME: + case SI_current_time: if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) { struct timeval tv = {sec, usec}; compute_time_diff(&tv); } break; - case SI_FORMAT: + case SI_format: stat_task->current_audio_format_num = get_audio_format_num(buf); } @@ -862,7 +819,7 @@ static int parse_stream_command(const char *txt, const char **cmd) return -E_MISSING_COLON; *cmd = p + 1; len = p - txt; - re = malloc(len + 1); + re = para_malloc(len + 1); strncpy(re, txt, len); re[len] = '\0'; ret = get_matching_audio_format_nums(re); @@ -1013,7 +970,7 @@ static int init_default_filters(void) } /* add "dec" to audio format name */ tmp = make_message("%sdec", audio_formats[i]); - for (j = 0; filter_get(j); j++) + for (j = 1; filter_get(j); j++) if (!strcmp(tmp, filter_name(j))) break; free(tmp); @@ -1078,7 +1035,7 @@ static int parse_stream_args(void) } /* does not unlink socket on errors */ -static void init_local_sockets(struct command_task *ct) +static void init_local_socket(struct command_task *ct) { if (OPT_GIVEN(SOCKET)) socket_name = para_strdup(OPT_STRING_VAL(SOCKET)); @@ -1091,12 +1048,10 @@ static void init_local_sockets(struct command_task *ct) PARA_NOTICE_LOG("local socket: %s\n", socket_name); if (OPT_GIVEN(FORCE)) unlink(socket_name); - 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_IROTH | S_IWOTH); - if (ct->fd[0] >= 0 || ct->fd[1] >= 0) + ct->fd = create_local_socket(socket_name); + if (ct->fd >= 0) return; - PARA_EMERG_LOG("%s\n", para_strerror(-ct->fd[1])); + PARA_EMERG_LOG("%s\n", para_strerror(-ct->fd)); exit(EXIT_FAILURE); } @@ -1113,7 +1068,7 @@ static int signal_post_select(struct sched *s, void *context) case SIGINT: case SIGTERM: case SIGHUP: - PARA_NOTICE_LOG("received signal %d\n", signum); + PARA_WARNING_LOG("terminating on signal %d\n", signum); task_notify_all(s, E_AUDIOD_SIGNAL); return -E_AUDIOD_SIGNAL; } @@ -1123,16 +1078,12 @@ static int signal_post_select(struct sched *s, void *context) static void command_pre_select(struct sched *s, void *context) { struct command_task *ct = context; - int i; - - for (i = 0; i < 2; i++) - if (ct->fd[i] >= 0) - para_fd_set(ct->fd[i], &s->rfds, &s->max_fileno); + para_fd_set(ct->fd, &s->rfds, &s->max_fileno); } static int command_post_select(struct sched *s, void *context) { - int ret, i; + int ret; struct command_task *ct = context; static struct timeval last_status_dump; struct timeval tmp, delay; @@ -1141,19 +1092,15 @@ static int command_post_select(struct sched *s, void *context) ret = task_get_notification(ct->task); 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; - } + ret = handle_connect(ct->fd, &s->rfds); + if (ret < 0) { + PARA_NOTICE_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; @@ -1181,7 +1128,7 @@ dump: static void init_command_task(struct command_task *ct) { - init_local_sockets(ct); /* doesn't return on errors */ + init_local_socket(ct); /* doesn't return on errors */ ct->task = task_register(&(struct task_info) { .name = "command", @@ -1288,8 +1235,9 @@ static void start_stop_decoders(void) struct slot_info *sl; close_unused_slots(); - if (audiod_status != AUDIOD_ON || - !(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING)) + if (audiod_status != AUDIOD_ON) + return notify_writers(E_NOT_PLAYING); + if (!(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING)) return notify_receivers(E_NOT_PLAYING); if (!must_start_decoder()) return; @@ -1408,10 +1356,10 @@ static int status_post_select(struct sched *s, void *context) client_open(argc, argv, &st->ct, NULL, NULL, st->btrn, s); set_stat_task_restart_barrier(5); } - free(stat_item_values[SI_BASENAME]); - stat_item_values[SI_BASENAME] = para_strdup( + free(stat_item_values[SI_basename]); + stat_item_values[SI_basename] = para_strdup( "no connection to para_server"); - stat_client_write_item(SI_BASENAME); + stat_client_write_item(SI_basename); st->last_status_read = *now; out: start_stop_decoders(); @@ -1520,9 +1468,8 @@ int main(int argc, char *argv[]) version_handle_flag("audiod", OPT_GIVEN(VERSION)); handle_help_flags(); parse_config_or_die(); - init_random_seed_or_die(); + crypt_init(); daemon_set_priority(OPT_UINT32_VAL(PRIORITY)); - recv_init(); if (daemon_init_colors_or_die(OPT_UINT32_VAL(COLOR), COLOR_AUTO, COLOR_NO, OPT_GIVEN(LOGFILE))) { for (i = 0; i < OPT_GIVEN(LOG_COLOR); i++) @@ -1569,7 +1516,7 @@ int main(int argc, char *argv[]) audiod_cleanup(); sched_shutdown(&sched); signal_shutdown(signal_task); - + crypt_shutdown(); out: lls_free_parse_result(lpr, CMD_PTR); if (errctx)