Merge branch 'refs/heads/t/image_id_mm'
authorAndre Noll <maan@tuebingen.mpg.de>
Fri, 1 Apr 2016 23:59:11 +0000 (01:59 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sat, 2 Apr 2016 00:11:35 +0000 (02:11 +0200)
A single commit that was cooking for several months.

* refs/heads/t/image_id_mm:
  server: Add mood methods image_id and lyrics_id.

49 files changed:
Doxyfile
Makefile.real
NEWS
aac_afh.c
afh.h
afh_common.c
afh_recv.c
afs.c
afs.h
aft.c
audiod.c
client.c
client_common.c
command.c
configure.ac
daemon.c
daemon.h
dccp_send.c
error.h
filter.c
filter.h
filter_common.c
gui.c
http_send.c
interactive.c
m4/gengetopt/afh_recv.m4
m4/gengetopt/audiod.m4
m4/gengetopt/priority.m4 [new file with mode: 0644]
m4/gengetopt/server.m4
mood.c
mp3_afh.c
net.c
ogg_afh_common.c
opus_afh.c
opus_common.c
para.h
play.c
playlist.c
recv_common.c
send.h
server.c
spxdec_filter.c
string.c
t/makefile.test
t/t0004-server.sh
t/t0005-man.sh
udp_send.c
vss.c
web/manual.m4

index 4009ac4..50c7469 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -1471,7 +1471,7 @@ MATHJAX_CODEFILE       =
 # The default value is: YES.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-SEARCHENGINE           = YES
+SEARCHENGINE           = NO
 
 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
 # implemented using a web server instead of a web client using Javascript. There
index 94d8edf..289e027 100644 (file)
@@ -1,3 +1,12 @@
+# Implicit rules are implemented in make as suffix rules. The following rule
+# empties the suffix list to disable the predefined implicit rules. This
+# increases performance and avoids hard-to-debug behaviour.
+.SUFFIXES:
+MAKEFLAGS += -Rr
+ifeq ("$(origin CC)", "default")
+        CC := cc
+endif
+
 vardir := /var/paraslash
 mandir := $(datarootdir)/man/man1
 STRIP := $(CROSS_COMPILE)strip
@@ -10,6 +19,7 @@ uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS")
 uname_rs := $(shell uname -rs)
 cc_version := $(shell $(CC) --version | head -n 1)
 GIT_VERSION := $(shell ./GIT-VERSION-GEN git-version.h)
+build_date := $(shell date)
 
 ifeq ("$(origin O)", "command line")
        build_dir := $(O)
@@ -82,11 +92,10 @@ $(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,\
 $(subst z,Z,$1))))))))))))))))))))))))))
 
 CPPFLAGS += -DBINDIR='"$(bindir)"'
-CPPFLAGS += -DBUILD_DATE='"$(shell date)"'
-CPPFLAGS += -DUNAME_RS='"$(shell uname -rs)"'
-CPPFLAGS += -DCC_VERSION='"$(shell $(CC) --version | head -n 1)"'
+CPPFLAGS += -DBUILD_DATE='"$(build_date)"'
+CPPFLAGS += -DUNAME_RS='"$(uname_rs)"'
+CPPFLAGS += -DCC_VERSION='"$(cc_version)"'
 CPPFLAGS += -DMAIN_INPUT_FILE_IS_$(*F)
-CPPFLAGS += $(arch_cppflags)
 CPPFLAGS += -I/usr/local/include
 CPPFLAGS += -I$(cmdline_dir)
 CPPFLAGS += -I$(cmdlist_dir)
@@ -165,7 +174,8 @@ $(man_dir)/para_server.1: man_util_command_lists := $(server_command_lists)
 $(man_dir)/para_audiod.1: man_util_command_lists := $(audiod_command_lists)
 $(man_dir)/para_play.1: man_util_command_lists := $(play_command_lists)
 
-$(man_dir)/para_%.1: $(ggo_dir)/%.ggo man_util.bash | $(man_dir) $(help2man_dir)
+$(man_dir)/para_%.1: $(ggo_dir)/%.ggo man_util.bash \
+               git-version.h | $(man_dir) $(help2man_dir)
        @[ -z "$(Q)" ] || echo 'MAN $<'
        $(Q) \
                COMMAND_LISTS="$(man_util_command_lists)" \
diff --git a/NEWS b/NEWS
index 7faa0dd..1481f68 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,13 +5,19 @@ NEWS
 current master branch "cascading gradient"
 ------------------------------------------
 
+The highlight of this release is the new -m flag for para_afh which
+lets it modify the meta tags of the given audio file(s). This feature
+is supported for all audio formats. Many small cleanups and bug fixes
+not mentioned here have accumulated and are also part of the release.
+
        - para_afh learned to modify meta tags of mp3 wma ogg spx
          opus flac aac files.
        - afs commands propagate error codes to the client.
        - The check command now also checks the attribute table for
          inconsistencies.
        - New -v flag for the version command (print verbose version string)
-
+       - New option --priority for para_server and para_audiod.
+       - New mood methods: image_id and lyrics_id.
 
 --------------------------------------
 0.5.5 (2015-09-20) "magnetic momentum"
index 5b2e9fb..d3e6945 100644 (file)
--- a/aac_afh.c
+++ b/aac_afh.c
@@ -46,23 +46,13 @@ static int aac_find_stsz(unsigned char *buf, size_t buflen, off_t *skip)
 
 static int atom_cmp(const unsigned char *buf1, const char *buf2)
 {
-       const unsigned char *b2 = (unsigned char *)buf2;
-
-       if (buf1[0] != b2[0])
-               return 1;
-       if (buf1[1] != b2[1])
-               return 1;
-       if (buf1[2] != b2[2])
-               return 1;
-       if (buf1[3] != b2[3])
-               return 1;
-       return 0;
+       return memcmp(buf1, buf2, 4)? 1 : 0;
 }
 
 static int read_atom_header(unsigned char *buf, uint64_t *subsize, unsigned char type[5])
 {
        int i;
-       uint64_t size = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+       uint64_t size = aac_read_int32(buf);
 
        memcpy(type, buf + 4, 4);
        type[4] = '\0';
@@ -174,7 +164,7 @@ static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
        if (ret < 0)
                return ret;
        afhi->chunks_total = ret;
-       PARA_DEBUG_LOG("sz table has %lu entries\n", afhi->chunks_total);
+       PARA_DEBUG_LOG("sz table has %" PRIu32 " entries\n", afhi->chunks_total);
        afhi->chunk_table = para_malloc((afhi->chunks_total + 1) * sizeof(size_t));
        for (i = 1; i <= afhi->chunks_total; i++) {
                if (skip + 4 > numbytes)
@@ -189,7 +179,7 @@ static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
 }
 
 static int aac_set_chunk_tv(struct afh_info *afhi,
-               mp4AudioSpecificConfig *mp4ASC, long unsigned *seconds)
+               mp4AudioSpecificConfig *mp4ASC, uint32_t *seconds)
 {
        float tmp = mp4ASC->sbr_present_flag == 1? 2047 : 1023;
        struct timeval total;
@@ -200,7 +190,7 @@ static int aac_set_chunk_tv(struct afh_info *afhi,
        ms = 1000.0 * afhi->chunks_total * tmp / mp4ASC->samplingFrequency;
        ms2tv(ms, &total);
        tv_divide(afhi->chunks_total, &total, &afhi->chunk_tv);
-       PARA_INFO_LOG("%luHz, %lus (%lu x %lums)\n",
+       PARA_INFO_LOG("%luHz, %lus (%" PRIu32 " x %lums)\n",
                mp4ASC->samplingFrequency, ms / 1000,
                afhi->chunks_total, tv2ms(&afhi->chunk_tv));
        if (ms < 1000)
diff --git a/afh.h b/afh.h
index 62e38c0..7a30947 100644 (file)
--- a/afh.h
+++ b/afh.h
@@ -28,9 +28,9 @@ struct taginfo {
 /** Audio format dependent information. */
 struct afh_info {
        /** The number of chunks this audio file contains. */
-       long unsigned chunks_total;
+       uint32_t chunks_total;
        /** The length of the audio file in seconds. */
-       long unsigned seconds_total;
+       uint32_t seconds_total;
        /** Audio handler specific info about the file. */
        char *techinfo;
        /** Id3 tags, vorbis comments, aac tags. */
index b1f8b25..063ae8f 100644 (file)
@@ -367,9 +367,9 @@ unsigned afh_get_afhi_txt(int audio_format_num, struct afh_info *afhi, char **re
                "%s: %s\n" /* format */
                "%s: %dHz\n" /* frequency */
                "%s: %d\n" /* channels */
-               "%s: %lu\n" /* seconds total */
+               "%s: %" PRIu32 "\n" /* seconds total */
                "%s: %lu: %lu\n" /* chunk time */
-               "%s: %lu\n" /* num chunks */
+               "%s: %" PRIu32 "\n" /* num chunks */
                "%s: %s\n" /* techinfo */
                "%s: %s\n" /* artist */
                "%s: %s\n" /* title */
index ff79485..1646346 100644 (file)
@@ -40,11 +40,11 @@ static int afh_execute(struct btr_node *btrn, const char *cmd, char **result)
 
        *result = NULL;
        if (!strcmp(cmd, "seconds_total")) {
-               *result = make_message("%lu", pard->afhi.seconds_total);
+               *result = make_message("%" PRIu32, pard->afhi.seconds_total);
                return 1;
        }
        if (!strcmp(cmd, "chunks_total")) {
-               *result = make_message("%lu", pard->afhi.chunks_total);
+               *result = make_message("%" PRIu32, pard->afhi.chunks_total);
                return 1;
        }
        if (!strcmp(cmd, "afhi")) {
diff --git a/afs.c b/afs.c
index bd70505..ee1c6b5 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -97,10 +97,11 @@ static char *current_mop; /* mode or playlist specifier. NULL means dummy mood *
 /**
  * A random number used to "authenticate" the connection.
  *
- * para_server picks this number by random before forking the afs process.  The
- * command handlers write this number together with the id of the shared memory
- * area containing the query. This way, a malicious local user has to know this
- * number to be able to cause the afs process to crash by sending fake queries.
+ * para_server picks this number by random before it forks the afs process. The
+ * command handlers know this number as well and write it to the afs socket,
+ * together with the id of the shared memory area which contains the payload of
+ * the afs command. A local process has to know this number to abuse the afs
+ * service provided by the local socket.
  */
 extern uint32_t afs_socket_cookie;
 
@@ -423,7 +424,7 @@ static int pass_afd(int fd, char *buf, size_t size)
 {
        struct msghdr msg = {.msg_iov = NULL};
        struct cmsghdr *cmsg;
-       char control[255];
+       char control[255] __a_aligned(8);
        int ret;
        struct iovec iov;
 
@@ -693,7 +694,7 @@ static int make_database_dir(void)
 
        get_database_dir();
        ret = para_mkdir(database_dir, 0777);
-       if (ret >= 0 || is_errno(-ret, EEXIST))
+       if (ret >= 0 || ret == -ERRNO_TO_PARA_ERROR(EEXIST))
                return 1;
        return ret;
 }
diff --git a/afs.h b/afs.h
index e77cdf0..25ff421 100644 (file)
--- a/afs.h
+++ b/afs.h
@@ -6,8 +6,6 @@
 
 /** \file afs.h Exported symbols of the audio file selector. */
 
-#include <regex.h>
-
 /** Audio file selector data stored in the audio file table. */
 struct afs_info {
        /** Seconds since the epoch. */
diff --git a/aft.c b/aft.c
index 8a8e528..261054d 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -676,21 +676,27 @@ int load_afd(int shmid, struct audio_file_data *afd)
 static int get_local_time(uint64_t *seconds, char *buf, size_t size,
        time_t current_time, enum ls_listing_mode lm)
 {
-       struct tm t;
+       struct tm *tm;
+       /*
+        * Omit year but show time if the given value is closer to the current
+        * time than this many seconds.
+        */
+       const time_t m = 6 * 30 * 24 * 3600; /* six months */
 
-       if (!localtime_r((time_t *)seconds, &t))
+       tm = localtime((time_t *)seconds);
+       if (!tm)
                return -E_LOCALTIME;
        if (lm == LS_MODE_MBOX) {
-               if (!strftime(buf, size, "%c", &t))
+               if (!strftime(buf, size, "%c", tm))
                        return -E_STRFTIME;
                return 1;
        }
-       if (*seconds + 6 * 30 * 24 * 3600 > current_time) {
-               if (!strftime(buf, size, "%b %e %k:%M", &t))
+       if (*seconds > current_time - m && *seconds < current_time + m) {
+               if (!strftime(buf, size, "%b %e %k:%M", tm))
                        return -E_STRFTIME;
                return 1;
        }
-       if (!strftime(buf, size, "%b %e  %Y", &t))
+       if (!strftime(buf, size, "%b %e %Y", tm))
                return -E_STRFTIME;
        return 1;
 }
@@ -915,12 +921,14 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
        WRITE_STATUS_ITEM(b, SI_FREQUENCY, "%dHz\n", afhi->frequency);
        WRITE_STATUS_ITEM(b, SI_CHANNELS, "%d\n", afhi->channels);
        WRITE_STATUS_ITEM(b, SI_DURATION, "%s\n", duration_buf);
-       WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%lu\n", afhi->seconds_total);
+       WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n",
+               afhi->seconds_total);
        WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time);
        WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%d\n", afsi->num_played);
        WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp);
        WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv));
-       WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%lu\n", afhi->chunks_total);
+       WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n",
+               afhi->chunks_total);
        WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo);
        WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist);
        WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title);
@@ -1737,6 +1745,8 @@ static int com_add_callback(struct afs_callback_arg *aca)
        objs[AFTCOL_AFSI].size = AFSI_SIZE;
        save_afsi(&default_afsi, &objs[AFTCOL_AFSI]);
        ret = osl(osl_add_and_get_row(audio_file_table, objs, &aft_row));
+       if (ret < 0)
+               goto out;
        ret = afs_event(AUDIO_FILE_ADD, &aca->pbout, aft_row);
 out:
        if (ret < 0)
@@ -2391,6 +2401,7 @@ static int com_setatt_callback(struct afs_callback_arg *aca)
        ) {
                char c;
                unsigned char bitnum;
+               uint64_t one = 1;
 
                len = strlen(p);
                ret = -E_ATTR_SYNTAX;
@@ -2406,9 +2417,9 @@ static int com_setatt_callback(struct afs_callback_arg *aca)
                        goto out;
                }
                if (c == '+')
-                       cad.add_mask |= (1UL << bitnum);
+                       cad.add_mask |= (one << bitnum);
                else
-                       cad.del_mask |= (1UL << bitnum);
+                       cad.del_mask |= (one << bitnum);
        }
        ret = -E_ATTR_SYNTAX;
        if (!cad.add_mask && !cad.del_mask)
index accf024..798142f 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -525,11 +525,11 @@ static void close_filters(struct slot_info *s)
                return;
        for (i = a->num_filters - 1; i >= 0; i--) {
                struct filter_node *fn = s->fns + i;
-               struct filter *f;
+               const struct filter *f;
 
                if (!fn)
                        continue;
-               f = filters + fn->filter_num;
+               f = filter_get(fn->filter_num);
                if (f->close)
                        f->close(fn);
                btr_remove_node(&fn->btrn);
@@ -588,7 +588,7 @@ static void open_filters(struct slot_info *s)
        parent = s->receiver_node->btrn;
        for (i = 0; i < nf; i++) {
                char buf[20];
-               struct filter *f = filters + a->filter_nums[i];
+               const struct filter *f = filter_get(a->filter_nums[i]);
                fn = s->fns + i;
                fn->filter_num = a->filter_nums[i];
                fn->conf = a->filter_conf[i];
@@ -858,7 +858,7 @@ static int add_filter(int format, char *cmdline)
        a->filter_conf[nf] = cfg;
        a->num_filters++;
        PARA_INFO_LOG("%s filter %d: %s\n", audio_formats[format], nf,
-               filters[filter_num].name);
+               filter_get(filter_num)->name);
        return filter_num;
 }
 
@@ -993,20 +993,20 @@ static int init_default_filters(void)
                }
                /* add "dec" to audio format name */
                tmp = make_message("%sdec", audio_formats[i]);
-               for (j = 0; filters[j].name; j++)
-                       if (!strcmp(tmp, filters[j].name))
+               for (j = 0; filter_get(j); j++)
+                       if (!strcmp(tmp, filter_get(j)->name))
                                break;
                free(tmp);
                ret = -E_UNSUPPORTED_FILTER;
-               if (!filters[j].name)
+               if (!filter_get(j))
                        goto out;
-               tmp = para_strdup(filters[j].name);
+               tmp = para_strdup(filter_get(j)->name);
                ret = add_filter(i, tmp);
                free(tmp);
                if (ret < 0)
                        goto out;
                PARA_INFO_LOG("%s -> default filter: %s\n", audio_formats[i],
-                       filters[j].name);
+                       filter_get(j)->name);
        }
 out:
        return ret;
@@ -1474,6 +1474,7 @@ int main(int argc, char *argv[])
        writer_init();
        if (conf.help_given || conf.detailed_help_given)
                print_help_and_die();
+       daemon_set_priority(conf.priority_arg);
        daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg);
        parse_config_or_die();
        daemon_init_colors_or_die(conf.color_arg, color_arg_auto, color_arg_no,
index 35b49a1..31cfff0 100644 (file)
--- a/client.c
+++ b/client.c
@@ -204,7 +204,6 @@ I9E_DUMMY_COMPLETER(pause);
 I9E_DUMMY_COMPLETER(play);
 I9E_DUMMY_COMPLETER(si);
 I9E_DUMMY_COMPLETER(term);
-I9E_DUMMY_COMPLETER(version);
 I9E_DUMMY_COMPLETER(stop);
 I9E_DUMMY_COMPLETER(addatt);
 I9E_DUMMY_COMPLETER(init);
@@ -218,6 +217,13 @@ static void help_completer(struct i9e_completion_info *ci,
        result->matches = i9e_complete_commands(ci->word, completers);
 }
 
+static void version_completer(struct i9e_completion_info *ci,
+               struct i9e_completion_result *cr)
+{
+       char *opts[] = {"-v", NULL};
+       i9e_complete_option(opts, ci, cr);
+}
+
 static void stat_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
@@ -317,11 +323,7 @@ static void lsatt_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
        char *opts[] = {"-i", "-l", "-r", NULL};
-
-       if (ci->word[0] == '-')
-               i9e_complete_option(opts, ci, cr);
-       else
-               complete_attributes(ci->word, &cr->matches);
+       i9e_complete_option(opts, ci, cr);
 }
 
 static void mvatt_completer(struct i9e_completion_info *ci,
index b47364c..cd1ccc6 100644 (file)
@@ -403,7 +403,7 @@ static int client_post_select(struct sched *s, void *context)
                                        btr_consume(ct->btrn[1], sz);
                        }
                }
-               /* fall though */
+               /* fall through */
        case CL_EXECUTING:
                if (ct->btrn[0]) {
                        ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
index e8f6948..93de2d2 100644 (file)
--- a/command.c
+++ b/command.c
@@ -75,20 +75,14 @@ static void dummy(__a_unused int s)
 {
 }
 
-static void mmd_dup(struct misc_meta_data *new_mmd)
-{
-       mutex_lock(mmd_mutex);
-       *new_mmd = *mmd;
-       mutex_unlock(mmd_mutex);
-}
-
 /*
- * Compute human readable string containing vss status for given integer value.
+ * Compute human readable vss status text.
  *
- * We don't want to use vss_playing() and friends here because we take a
- * snapshot of the mmd struct and use the copy for computing the state of the
- * vss. If the real data were used, we would take the mmd lock for a rather
- * long time or risk to get an inconsistent view.
+ * We can't call vss_playing() and friends here because those functions read
+ * the flags from the primary mmd structure, so calling them from command
+ * handler context would require to take the mmd lock. At the time the function
+ * is called we already took a copy of the mmd structure and want to use the
+ * flags value of the copy for computing the vss status text.
  */
 static char *vss_status_tohuman(unsigned int flags)
 {
@@ -167,9 +161,8 @@ static unsigned get_status(struct misc_meta_data *nmmd, int parser_friendly,
 static int check_sender_args(int argc, char * const * argv, struct sender_command_data *scd)
 {
        int i;
-       /* this has to match sender.h */
-       const char *subcmds[] = {"add", "delete", "allow", "deny", "on", "off", NULL};
 
+       const char *subcmds[] = {SENDER_SUBCOMMANDS NULL};
        scd->sender_num = -1;
        if (argc < 3)
                return -E_COMMAND_SYNTAX;
@@ -189,19 +182,19 @@ static int check_sender_args(int argc, char * const * argv, struct sender_comman
        if (!senders[scd->sender_num].client_cmds[scd->cmd_num])
                return -E_SENDER_CMD;
        switch (scd->cmd_num) {
-       case SENDER_ON:
-       case SENDER_OFF:
+       case SENDER_on:
+       case SENDER_off:
                if (argc != 3)
                        return -E_COMMAND_SYNTAX;
                break;
-       case SENDER_DENY:
-       case SENDER_ALLOW:
+       case SENDER_deny:
+       case SENDER_allow:
                if (argc != 4 || parse_cidr(argv[3], scd->host,
                                sizeof(scd->host), &scd->netmask) == NULL)
                        return -E_COMMAND_SYNTAX;
                break;
-       case SENDER_ADD:
-       case SENDER_DELETE:
+       case SENDER_add:
+       case SENDER_delete:
                if (argc != 4)
                        return -E_COMMAND_SYNTAX;
                return parse_fec_url(argv[3], scd);
@@ -364,8 +357,8 @@ static int com_sender(struct command_context *cc)
        }
 
        switch (scd.cmd_num) {
-       case SENDER_ADD:
-       case SENDER_DELETE:
+       case SENDER_add:
+       case SENDER_delete:
                assert(senders[scd.sender_num].resolve_target);
                ret = senders[scd.sender_num].resolve_target(cc->argv[3], &scd);
                if (ret < 0)
@@ -532,7 +525,13 @@ static int com_stat(struct command_context *cc)
        if (i != cc->argc)
                return -E_COMMAND_SYNTAX;
        for (;;) {
-               mmd_dup(nmmd);
+               /*
+                * Copy the mmd structure to minimize the time we hold the mmd
+                * lock.
+                */
+               mutex_lock(mmd_mutex);
+               *nmmd = *mmd;
+               mutex_unlock(mmd_mutex);
                ret = get_status(nmmd, parser_friendly, &s);
                ret = send_sb(&cc->scc, s, ret, SBD_OUTPUT, false);
                if (ret < 0)
index 2b2f296..5960b08 100644 (file)
@@ -65,20 +65,6 @@ AC_DEFUN([LIB_SUBST_FLAGS], [
        AC_SUBST($1_ldflags)
 ])
 
-AC_PATH_PROG(UNAMEPATH, uname, no)
-if test "$UNAMEPATH" = "no"; then
-       AC_MSG_ERROR(unable to determine system type)
-fi
-AC_MSG_CHECKING(os type)
-OSTYPE="`$UNAMEPATH -s`"
-AC_MSG_RESULT("$OSTYPE")
-
-if test "$OSTYPE" = "SunOS"; then
-       # needed on SunOS for socket magic
-       arch_cppflags="-D_XOPEN_SOURCE=500 -D__EXTENSIONS__"
-       AC_SUBST(arch_cppflags)
-fi
-
 AC_C_BIGENDIAN()
 
 AC_PATH_PROG([GENGETOPT], [gengetopt])
index 94c4a8c..478b0f4 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -11,6 +11,7 @@
 #include <sys/types.h> /* getgrnam() */
 #include <grp.h>
 #include <signal.h>
+#include <sys/resource.h>
 
 #include "para.h"
 #include "daemon.h"
@@ -260,6 +261,21 @@ void daemon_log_welcome(const char *name)
        PARA_INFO_LOG("welcome to para_%s-" PACKAGE_VERSION " \n", name);
 }
 
+/**
+ * Renice the calling process.
+ *
+ * \param prio The priority value to set.
+ *
+ * Errors are not considered fatal, but a warning message is logged if the
+ * underlying call to setpriority(2) fails.
+ */
+void daemon_set_priority(int prio)
+{
+       if (setpriority(PRIO_PROCESS, 0, prio) < 0)
+               PARA_WARNING_LOG("could not set priority to %d: %s\n", prio,
+                       strerror(errno));
+}
+
 /**
  * Give up superuser privileges.
  *
index ca3da14..621420a 100644 (file)
--- a/daemon.h
+++ b/daemon.h
@@ -5,6 +5,7 @@ void daemonize(bool parent_waits);
 void daemon_open_log_or_die(void);
 void daemon_close_log(void);
 void daemon_log_welcome(const char *whoami);
+void daemon_set_priority(int prio);
 void daemon_drop_privileges_or_die(const char *username, const char *groupname);
 void daemon_set_start_time(void);
 time_t daemon_get_uptime(const struct timeval *current_time);
index b038fc0..92dd933 100644 (file)
@@ -225,12 +225,12 @@ void dccp_send_init(struct sender *s)
        s->shutdown_clients = dccp_shutdown_clients;
        s->resolve_target = NULL;
        s->help = generic_sender_help;
-       s->client_cmds[SENDER_ON] = dccp_com_on;
-       s->client_cmds[SENDER_OFF] = dccp_com_off;
-       s->client_cmds[SENDER_DENY] = dccp_com_deny;
-       s->client_cmds[SENDER_ALLOW] = dccp_com_allow;
-       s->client_cmds[SENDER_ADD] = NULL;
-       s->client_cmds[SENDER_DELETE] = NULL;
+       s->client_cmds[SENDER_on] = dccp_com_on;
+       s->client_cmds[SENDER_off] = dccp_com_off;
+       s->client_cmds[SENDER_deny] = dccp_com_deny;
+       s->client_cmds[SENDER_allow] = dccp_com_allow;
+       s->client_cmds[SENDER_add] = NULL;
+       s->client_cmds[SENDER_delete] = NULL;
 
        k = conf.dccp_data_slices_per_group_arg;
        n = conf.dccp_slices_per_group_arg;
diff --git a/error.h b/error.h
index 5d5666c..b735233 100644 (file)
--- a/error.h
+++ b/error.h
@@ -396,6 +396,7 @@ extern const char **para_errlist[];
        PARA_ERROR(SIZE_PREFIX, "bad size prefix"), \
        PARA_ERROR(REGEX, "regular expression error"), \
        PARA_ERROR(ARG_NOT_FOUND, "argument not found in arg vector"), \
+       PARA_ERROR(BAD_LL, "invalid loglevel"), \
 
 
 #define EXEC_ERRORS \
@@ -418,7 +419,6 @@ extern const char **para_errlist[];
        PARA_ERROR(MP4ASC, "audio spec config error"), \
        PARA_ERROR(AAC_AFH_INIT, "failed to init aac decoder"), \
        PARA_ERROR(MP4V2, "mp4v2 library error"), \
-       PARA_ERROR(NO_AUDIO_TRACK, "file contains no valid audio track"), \
 
 #define AAC_COMMON_ERRORS \
        PARA_ERROR(ESDS, "did not find esds atom"), \
@@ -579,20 +579,8 @@ extern const char **para_errlist[];
 /** Set the osl error bit for the given number. */
 #define OSL_ERRNO_TO_PARA_ERROR(num) ((num) | (1 << OSL_ERROR_BIT))
 
-/** Check whether a given number is a system error number.
- *
- * \param num The value to be checked.
- * \param _errno The system error number.
- *
- * \return True if \a num is paraslash's representation of the system
- * error identified by \a _errno.
- */
-_static_inline_ bool is_errno(int num, int _errno)
-{
-       assert(num > 0 && _errno > 0);
-       return ERRNO_TO_PARA_ERROR(_errno) == num;
-}
 
+static const char *weak_osl_strerror(int) __attribute__ ((weakref("osl_strerror")));
 /**
  * Paraslash's version of strerror(3).
  *
@@ -603,12 +591,12 @@ _static_inline_ bool is_errno(int num, int _errno)
 _static_inline_ const char *para_strerror(int num)
 {
        assert(num > 0);
-#ifdef _OSL_H
-       if (IS_OSL_ERROR(num))
-               return osl_strerror(num & ((1 << OSL_ERROR_BIT) - 1));
-#endif
+       if (IS_OSL_ERROR(num)) {
+               assert(weak_osl_strerror);
+               return weak_osl_strerror(num & ~(1U << OSL_ERROR_BIT));
+       }
        if (IS_SYSTEM_ERROR(num))
-               return strerror(num & ((1 << SYSTEM_ERROR_BIT) - 1));
+               return strerror(num & ~(1U << SYSTEM_ERROR_BIT));
        return para_errlist[ERRNUM_TO_SS(num)][ERRNUM_TO_INDEX(num)];
 }
 
index f9ba17a..1ba1268 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -106,7 +106,7 @@ int main(int argc, char *argv[])
 {
        static struct sched s;
        int i, ret;
-       struct filter *f;
+       const struct filter *f;
        struct btr_node *parent;
        struct filter_node **fns;
 
@@ -133,7 +133,7 @@ int main(int argc, char *argv[])
                        goto out_cleanup;
                }
                fn->filter_num = ret;
-               f = filters + fn->filter_num;
+               f = filter_get(fn->filter_num);
                PARA_DEBUG_LOG("filter #%d: %s\n", i, f->name);
                fn->btrn = btr_new_node(&(struct btr_node_description)
                        EMBRACE(.name = f->name, .parent = parent,
@@ -159,7 +159,7 @@ out_cleanup:
        for (i--; i >= 0; i--) {
                struct filter_node *fn = fns[i];
 
-               f = filters + fn->filter_num;
+               f = filter_get(fn->filter_num);
                if (f->close)
                        f->close(fn);
                btr_remove_node(&fn->btrn);
index 135a688..31eedcc 100644 (file)
--- a/filter.h
+++ b/filter.h
@@ -96,10 +96,12 @@ struct filter {
        /**
         * Set scheduler timeout and add file descriptors to fd sets.
         *
-        * This function is used to control the timeout value for select. It
-        * only allowed to decrease the current value. The second purpose of
-        * this function is to set file descriptors to be watched by the
-        * subsequent select call to the two fd sets.
+        * This function controls the timeout value for the next call to
+        * select(2). It may decrease the current timeout but shall never
+        * increase it. The second purpose of this function is to add file
+        * descriptors to the two fd sets of the sched structure. The
+        * descriptors in these sets will be watched by the subsequent
+        * select(2) call.
         */
        void (*pre_select)(struct sched *s, void *context);
        /**
@@ -138,8 +140,5 @@ static inline void write_int16_host_endian(char *buf, int val)
 
 DECLARE_FILTER_INITS
 
-/** Iterate over the array of supported filters. */
-#define FOR_EACH_SUPPORTED_FILTER(j)  for (j = 0; j < NUM_SUPPORTED_FILTERS; j++)
-
 /** The filter array, one structure for each supported filter. */
-extern struct filter filters[NUM_SUPPORTED_FILTERS];
+const struct filter *filter_get(int filter_num);
index 009ac93..099d056 100644 (file)
 #include "error.h"
 #include "string.h"
 
+/** Iterate over the array of supported filters. */
+#define FOR_EACH_SUPPORTED_FILTER(j)  for (j = 0; j < NUM_SUPPORTED_FILTERS; j++)
+
 /** The array of supported filters. */
-struct filter filters[NUM_SUPPORTED_FILTERS] = {FILTER_ARRAY};
+static struct filter filters[NUM_SUPPORTED_FILTERS] = {FILTER_ARRAY};
+
+const struct filter *filter_get(int filter_num)
+{
+       assert(filter_num >= 0);
+       assert(filter_num < NUM_SUPPORTED_FILTERS);
+       return filters + filter_num;
+}
 
 /**
  * Call the init function of each supported filter.
@@ -31,7 +41,7 @@ void filter_init(void)
        int i;
 
        FOR_EACH_SUPPORTED_FILTER(i)
-               filters[i].init(filters + i);
+               filter_get(i)->init((struct filter *)filter_get(i));
 }
 
 /*
@@ -40,7 +50,7 @@ void filter_init(void)
  */
 static int parse_filter_args(int filter_num, char *options, void **conf)
 {
-       struct filter *f = &filters[filter_num];
+       const struct filter *f = filter_get(filter_num);
        int ret, argc;
        char **argv;
 
@@ -80,7 +90,7 @@ int check_filter_arg(char *fa, void **conf)
        *conf = NULL;
 //     PARA_DEBUG_LOG("arg: %s\n", fa);
        FOR_EACH_SUPPORTED_FILTER(j) {
-               const char *name = filters[j].name;
+               const char *name = filter_get(j)->name;
                size_t len = strlen(name);
                char c;
                if (strlen(fa) < len)
@@ -90,7 +100,7 @@ int check_filter_arg(char *fa, void **conf)
                c = fa[len];
                if (c && c != ' ')
                        continue;
-               if (c && !filters[j].parse_config)
+               if (c && !filter_get(j)->parse_config)
                        return -E_BAD_FILTER_OPTIONS;
                return parse_filter_args(j, c? fa + len + 1 :
                        fa + strlen(fa), conf);
@@ -113,12 +123,12 @@ void print_filter_helps(unsigned flags)
                        printf_or_die("\n                  ");
                        num = 0;
                }
-               num += printf_or_die("%s%s", i? " " : "", filters[i].name);
+               num += printf_or_die("%s%s", i? " " : "", filter_get(i)->name);
        }
        printf_or_die("\n");
 
        FOR_EACH_SUPPORTED_FILTER(i) {
-               struct filter *f = filters + i;
+               struct filter *f = (struct filter *)filter_get(i);
 
                if (!f->help.short_help)
                        continue;
diff --git a/gui.c b/gui.c
index 1a89681..9d96e70 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -296,7 +296,7 @@ static int align_str(WINDOW* win, char *str, unsigned int len,
                waddstr(win, str);
        } else {
                add_spaces(win, num / 2);
-               waddstr(win, str[0]? str: "");
+               waddstr(win, str);
                add_spaces(win, num - num / 2);
        }
        return 1;
@@ -776,7 +776,7 @@ static void init_curses(void)
 {
        if (curses_active())
                return;
-       if (top.win && refresh() == ERR) /* refresh is really needed */
+       if (refresh() == ERR) /* refresh is really needed */
                die(EXIT_FAILURE, "refresh() failed\n");
        if (LINES < theme.lines_min || COLS < theme.cols_min)
                die(EXIT_FAILURE, "Terminal (%dx%d) too small"
index daf39e7..9d0f49a 100644 (file)
@@ -256,12 +256,12 @@ void http_send_init(struct sender *s)
        s->shutdown_clients = http_shutdown_clients;
        s->resolve_target = NULL;
        s->help = generic_sender_help;
-       s->client_cmds[SENDER_ON] = http_com_on;
-       s->client_cmds[SENDER_OFF] = http_com_off;
-       s->client_cmds[SENDER_DENY] = http_com_deny;
-       s->client_cmds[SENDER_ALLOW] = http_com_allow;
-       s->client_cmds[SENDER_ADD] = NULL;
-       s->client_cmds[SENDER_DELETE] = NULL;
+       s->client_cmds[SENDER_on] = http_com_on;
+       s->client_cmds[SENDER_off] = http_com_off;
+       s->client_cmds[SENDER_deny] = http_com_deny;
+       s->client_cmds[SENDER_allow] = http_com_allow;
+       s->client_cmds[SENDER_add] = NULL;
+       s->client_cmds[SENDER_delete] = NULL;
 
        init_sender_status(hss, conf.http_access_arg, conf.http_access_given,
                conf.http_port_arg, conf.http_max_clients_arg,
index 484f955..ce48af3 100644 (file)
@@ -26,11 +26,11 @@ struct i9e_private {
        struct i9e_client_info *ici;
        FILE *stderr_stream;
        int num_columns;
+       int num_key_bindings;
        char empty_line[1000];
        struct task *task;
        struct btr_node *stdout_btrn;
        bool last_write_was_status;
-       bool line_handler_running;
        bool input_eof;
        bool caught_sigint;
        bool caught_sigterm;
@@ -413,19 +413,17 @@ static void update_winsize(void)
        i9ep->empty_line[i9ep->num_columns] = '\0';
 }
 
-/**
- * Defined key sequences are mapped to keys starting with this offset. I.e.
- * pressing the first defined key sequence yields the key number \p KEY_OFFSET.
- */
-#define KEY_OFFSET 64
-
-static int dispatch_key(__a_unused int count, int key)
+static int dispatch_key(__a_unused int count, __a_unused int key)
 {
-       int ret;
+       int i, ret;
 
-       assert(key >= KEY_OFFSET);
-       ret = i9ep->ici->key_handler(key - KEY_OFFSET);
-       return ret < 0? ret : 0;
+       for (i = i9ep->num_key_bindings - 1; i >= 0; i--) {
+               if (strcmp(rl_executing_keyseq, i9ep->ici->bound_keyseqs[i]))
+                       continue;
+               ret = i9ep->ici->key_handler(i);
+               return ret < 0? ret : 0;
+       }
+       assert(0);
 }
 
 /**
@@ -469,13 +467,11 @@ int i9e_open(struct i9e_client_info *ici, struct sched *s)
        if (ici->bound_keyseqs) {
                char *seq;
                int i;
-               /* FIXME: This is an arbitrary constant.  */
-               for (i = 0; i < 32 && (seq = ici->bound_keyseqs[i]); i++) {
-                       char buf[2] = {KEY_OFFSET + i, '\0'};
-                       /* readline needs an allocated buffer for the macro */
-                       rl_generic_bind(ISMACR, seq, para_strdup(buf), i9ep->bare_km);
-                       rl_bind_key_in_map(KEY_OFFSET + i, dispatch_key, i9ep->bare_km);
-               }
+               /* bind each key sequence to the our dispatcher */
+               for (i = 0; (seq = ici->bound_keyseqs[i]); i++)
+                       rl_generic_bind(ISFUNC, seq, (char *)dispatch_key,
+                               i9ep->bare_km);
+               i9ep->num_key_bindings = i;
        }
        if (ici->history_file)
                read_history(ici->history_file);
@@ -483,7 +479,6 @@ int i9e_open(struct i9e_client_info *ici, struct sched *s)
        if (ici->producer) {
                rl_callback_handler_install("", i9e_line_handler);
                i9e_attach_to_stdout(ici->producer);
-               rl_set_keymap(i9ep->bare_km);
        } else
                rl_callback_handler_install(i9ep->ici->prompt, i9e_line_handler);
        return 1;
@@ -560,8 +555,6 @@ void ie9_print_status_bar(char *buf, unsigned len)
  * Tell i9e that the caller received a signal.
  *
  * \param sig_num The number of the signal received.
- *
- * Currently the function only cares about \p SIGINT, but this may change.
  */
 void i9e_signal_dispatch(int sig_num)
 {
index 08c3152..28a0a9e 100644 (file)
@@ -22,19 +22,19 @@ required
 
 option "begin-chunk" b
 #~~~~~~~~~~~~~~~~~~~~~
-"skip a number of chunks"
+"skip the beginning of the file"
 int typestr = "chunk_num"
 default = "0"
 optional
 details = "
        The chunk_num argument must be between -num_chunks and
-       num_chunks - 1 inclusively where num_chunks is the total number
-       of chunks which is printed when using the --info option. If
-       chunk_num is negative, the given number of chunks are counted
-       backwards from the end of the file. For example --begin-chunk
-       -100 instructs para_afh to start output at chunk num_chunks
-       - 100. This is mainly useful for cutting off the end of an
-       audio file.
+       num_chunks - 1, inclusively, where num_chunks is the total
+       number of chunks of the audio file given by the argument to
+       --filename. If chunk_num is negative, the given number of
+       chunks are counted backwards from the end of the file. For
+       example --begin-chunk -100 instructs the afh receiver to
+       start output at chunk num_chunks - 100. This is useful for
+       selecting the last part of an audio file.
 "
 
 option "end-chunk" e
index 732f808..75c0458 100644 (file)
@@ -20,6 +20,7 @@ include(log_timing.m4)
 include(daemon.m4)
 include(user.m4)
 include(group.m4)
+include(priority.m4)
 
 <qu>
 ########################
diff --git a/m4/gengetopt/priority.m4 b/m4/gengetopt/priority.m4
new file mode 100644 (file)
index 0000000..0b37dc0
--- /dev/null
@@ -0,0 +1,16 @@
+option "priority" -
+#~~~~~~~~~~~~~~~~~~
+"adjust scheduling priority"
+int typestr = "prio"
+default = "0"
+optional
+details = "
+       The priority (also known as nice value) is a value in the range -20
+       to 19. Lower priorities cause more favorable scheduling. Since only
+       privileged processes may request a negative priority, specifying
+       a negative value works only if the daemon is started with root
+       privileges.
+
+       Failure to set the given priority value is not considered an error
+       but a log message is printed in this case.
+"
index 916e885..6aca7ba 100644 (file)
@@ -18,6 +18,7 @@ include(color.m4)
 include(daemon.m4)
 include(user.m4)
 include(group.m4)
+include(priority.m4)
 
 <qu>
 option "port" p
diff --git a/mood.c b/mood.c
index d29c62c..daa8196 100644 (file)
--- a/mood.c
+++ b/mood.c
@@ -446,7 +446,7 @@ static int64_t normalized_value(int64_t x, int64_t n, int64_t sum, int64_t qd)
 {
        if (!n || !qd)
                return 0;
-       return 100 * (n * x - sum) / (int64_t)int_sqrt(n * qd);
+       return 100 * (n * x - sum) / (int64_t)int_sqrt(n) / (int64_t)int_sqrt(qd);
 }
 
 static long compute_score(struct afs_info *afsi, long mood_score)
@@ -460,7 +460,7 @@ static long compute_score(struct afs_info *afsi, long mood_score)
 
 static int add_afs_statistics(const struct osl_row *row)
 {
-       uint64_t n, x, s;
+       uint64_t n, x, s, q;
        struct afs_info afsi;
        int ret;
 
@@ -470,14 +470,18 @@ static int add_afs_statistics(const struct osl_row *row)
        n = statistics.num;
        x = afsi.last_played;
        s = statistics.last_played_sum;
-       if (n > 0)
-               statistics.last_played_qd += (x - s / n) * (x - s / n) * n / (n + 1);
+       if (n > 0) {
+               q = (x > s / n)? x - s / n : s / n - x;
+               statistics.last_played_qd += q * q * n / (n + 1);
+       }
        statistics.last_played_sum += x;
 
        x = afsi.num_played;
        s = statistics.num_played_sum;
-       if (n > 0)
-               statistics.num_played_qd += (x - s / n) * (x - s / n) * n / (n + 1);
+       if (n > 0) {
+               q = (x > s / n)? x - s / n : s / n - x;
+               statistics.num_played_qd += q * q * n / (n + 1);
+       }
        statistics.num_played_sum += x;
        statistics.num++;
        return 1;
@@ -604,7 +608,8 @@ static int add_if_admissible(struct osl_row *aft_row, void *data)
  * the last number a_n was replaced by b) may be computed in O(1) time in terms
  * of n, q, a_n, b, and S as
  *
- *     q' = q + d * s - (2 * S + d) * d / n,
+ *     q' = q + d * s - (2 * S + d) * d / n
+ *        = q + d * (s - 2 * S / n - d /n),
  *
  * where d = b - a_n, and s = b + a_n.
  *
@@ -621,7 +626,7 @@ _static_inline_ int64_t update_quadratic_deviation(int64_t n, int64_t old_qd,
 {
        int64_t delta = new_val - old_val;
        int64_t sigma = new_val + old_val;
-       return old_qd + delta * sigma - (2 * old_sum + delta) * delta / n;
+       return old_qd + delta * (sigma - 2 * old_sum / n - delta / n);
 }
 
 static int update_afs_statistics(struct afs_info *old_afsi, struct afs_info *new_afsi)
index 484172a..73e744e 100644 (file)
--- a/mp3_afh.c
+++ b/mp3_afh.c
@@ -656,7 +656,7 @@ static int mp3_read_info(unsigned char *map, size_t numbytes, int fd,
        afhi->channels = header_channels(&header);
        afhi->seconds_total = (tv2ms(&total_time) + 500) / 1000;
        tv_divide(afhi->chunks_total, &total_time, &afhi->chunk_tv);
-       PARA_DEBUG_LOG("%lu chunks, each %lums\n", afhi->chunks_total,
+       PARA_DEBUG_LOG("%" PRIu32 "chunks, each %lums\n", afhi->chunks_total,
                tv2ms(&afhi->chunk_tv));
        ret = mp3_get_id3(map, numbytes, fd, &afhi->tags);
        afhi->techinfo = make_message("%cbr, %s, %s tags", vbr? 'v' : 'c',
diff --git a/net.c b/net.c
index 463033b..42418e5 100644 (file)
--- a/net.c
+++ b/net.c
@@ -1018,7 +1018,7 @@ static void dispose_fds(int *fds, unsigned num)
  */
 int recv_cred_buffer(int fd, char *buf, size_t size)
 {
-       char control[255];
+       char control[255] __a_aligned(8);
        struct msghdr msg;
        struct cmsghdr *cmsg;
        struct iovec iov;
index b8b0006..e49b803 100644 (file)
@@ -159,7 +159,7 @@ int ogg_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
        afhi->seconds_total = num_frames / afhi->frequency;
        /* use roughly one page per chunk */
        frames_per_chunk = num_frames / i;
-       PARA_INFO_LOG("%lu seconds, %d frames/chunk\n",
+       PARA_INFO_LOG("%" PRIu32 "seconds, %d frames/chunk\n",
                afhi->seconds_total, frames_per_chunk);
        ct_size = 250;
        afhi->chunk_table = para_malloc(ct_size * sizeof(uint32_t));
index ace8300..e7511d3 100644 (file)
@@ -96,7 +96,8 @@ static int opus_packet_callback(ogg_packet *packet, int packet_num,
                if (ret < 0)
                        return ret;
                afhi->channels = oh->channels;
-               afhi->techinfo = make_message("header version %d, input sample rate: %dHz",
+               afhi->techinfo = make_message(
+                       "header version %d, input sample rate: %" PRIu32 "Hz",
                        oh->version, oh->input_sample_rate);
                /*
                 * The input sample rate is irrelevant for afhi->frequency as
index 927df1f..67a8841 100644 (file)
@@ -104,7 +104,7 @@ int opus_parse_header(const char *packet, int len, struct opus_header *h)
        if (!read_chars(&p, &ch, 1))
                return -E_OPUS_HEADER;
        h->version = ch;
-       if((h->version & 240) != 0) /* Only major version 0 supported. */
+       if ((h->version & 240) != 0) /* Only major version 0 supported. */
                return -E_OPUS_HEADER;
 
        if (!read_chars(&p, &ch, 1))
diff --git a/para.h b/para.h
index e5b18e4..f08d43a 100644 (file)
--- a/para.h
+++ b/para.h
@@ -206,7 +206,7 @@ _static_inline_ bool iov_valid(const struct iovec *iov)
  *
  *     2. The wav header (para_write only).
  *
- *     3. The --format option of para_write.
+ *     3. The --sample-format option of para_write.
  */
 #define SAMPLE_FORMATS \
        SAMPLE_FORMAT(SF_S8, "8 bit signed"), \
diff --git a/play.c b/play.c
index 1b3cc93..55c9ec1 100644 (file)
--- a/play.c
+++ b/play.c
@@ -263,7 +263,7 @@ static int get_playback_error(struct play_task *pt)
 static int eof_cleanup(struct play_task *pt)
 {
        struct writer *w = writers + DEFAULT_WRITER;
-       struct filter *decoder = filters + pt->fn.filter_num;
+       const struct filter *decoder = filter_get(pt->fn.filter_num);
        int ret;
 
        ret = get_playback_error(pt);
@@ -368,7 +368,7 @@ static int load_file(struct play_task *pt)
        const char *af;
        char *tmp, buf[20];
        int ret;
-       struct filter *decoder;
+       const struct filter *decoder;
 
        btr_remove_node(&pt->rn.btrn);
        if (!pt->rn.receiver || pt->next_file != pt->current_file) {
@@ -393,7 +393,7 @@ static int load_file(struct play_task *pt)
        if (ret < 0)
                goto fail;
        pt->fn.filter_num = ret;
-       decoder = filters + ret;
+       decoder = filter_get(ret);
        pt->fn.btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = decoder->name, .parent = pt->rn.btrn,
                        .handler = decoder->execute, .context = &pt->fn));
@@ -921,6 +921,8 @@ static int com_jmp(struct play_task *pt, int argc, char **argv)
                return ret;
        if (percent < 0 || percent > 100)
                return -ERRNO_TO_PARA_ERROR(EINVAL);
+       if (percent == 100)
+               return com_next(pt, 1, (char *[]){"next", NULL});
        if (pt->playing && !pt->fn.btrn)
                return 0;
        pt->start_chunk = percent * pt->num_chunks / 100;
@@ -1029,7 +1031,7 @@ static void sigint_handler(int sig)
  * stderr. Once the i9e subsystem has been initialized, we switch to the i9e
  * log facility.
  */
-static void session_open(__a_unused struct play_task *pt)
+static void session_open(struct play_task *pt)
 {
        int ret;
        char *history_file;
index 9616ed0..0139203 100644 (file)
@@ -191,8 +191,6 @@ static int handle_audio_file_event(enum afs_events event, void *data)
        char *new_path;
        const struct osl_row *row = data;
 
-       if (!current_playlist.name)
-               return 1;
        if (event == AUDIO_FILE_RENAME) {
                ret = row_belongs_to_score_table(row, NULL);
                if (ret < 0)
@@ -237,7 +235,9 @@ int playlists_event_handler(enum afs_events event,
        int ret;
        struct afsi_change_event_data *aced = data;
 
-       switch(event) {
+       if (!current_playlist.name)
+               return 1;
+       switch (event) {
        case AFSI_CHANGE:
                return playlist_update_audio_file(aced->aft_row);
        case AUDIO_FILE_RENAME:
index aa2823c..59630df 100644 (file)
@@ -55,10 +55,10 @@ static void *parse_receiver_args(int receiver_num, char *options)
  * \param \ra string of the form receiver_name:options
  * \param receiver_num contains the number of the receiver upon success
  *
- * This function checks whether \a ra starts with the name of a supported
- * paraslash receiver, optionally followed by a colon and any options for that
- * receiver. If a valid receiver name was found the remaining part of \a ra is
- * passed to the receiver's config parser.
+ * This function checks whether \a ra starts with the name of a receiver,
+ * optionally followed by options for that receiver. If a valid receiver name
+ * was found the remaining part of \a ra is passed to the receiver's config
+ * parser.
  *
  * \return On success, a pointer to the receiver-specific gengetopt args info
  * struct is returned and \a receiver_num contains the number of the receiver.
diff --git a/send.h b/send.h
index 09eb78b..0c74f0e 100644 (file)
--- a/send.h
+++ b/send.h
@@ -6,16 +6,21 @@
 
 /** \file send.h Sender-related defines and structures. */
 
-/** The sender subcommands. */
+#define SENDER_SUBCOMMANDS \
+       SENDER_SUBCOMMAND(add) /**< Add a target (udp only). */ \
+       SENDER_SUBCOMMAND(delete) /**< Delete a target (udp only). */ \
+       SENDER_SUBCOMMAND(allow) /**< Allow connections from given IP address(es). */ \
+       SENDER_SUBCOMMAND(deny) /**< Deny connections from given IP address(es). */ \
+       SENDER_SUBCOMMAND(on) /**< Activate the sender. */ \
+       SENDER_SUBCOMMAND(off) /**< Deactivate the sender. */ \
+
+#define SENDER_SUBCOMMAND(_name) SENDER_ ## _name,
 enum sender_subcommand {
-       SENDER_ADD, /**< Add a target (udp only). */
-       SENDER_DELETE, /**< Delete a target (udp only). */
-       SENDER_ALLOW, /**< Allow connections from given IP address(es). */
-       SENDER_DENY, /**< Deny connections from given IP address(es). */
-       SENDER_ON, /**< Activate the sender. */
-       SENDER_OFF, /**< Deactivate the sender. */
+       SENDER_SUBCOMMANDS
        NUM_SENDER_CMDS /**< Used as array size in struct \ref sender. */
 };
+#undef SENDER_SUBCOMMAND
+#define SENDER_SUBCOMMAND(_name) #_name,
 
 /**
  * Describes one supported sender of para_server.
index 7cb6e52..71a9ec5 100644 (file)
--- a/server.c
+++ b/server.c
@@ -463,6 +463,7 @@ static void server_init(int argc, char **argv)
        version_handle_flag("server", conf.version_given);
        if (conf.help_given || conf.detailed_help_given)
                print_help_and_die();
+       daemon_set_priority(conf.priority_arg);
        daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg);
        /* parse config file, open log and set defaults */
        parse_config_or_die(0);
index b7b6329..644d287 100644 (file)
@@ -128,7 +128,14 @@ static int speexdec_init(struct filter_node *fn)
 #define le_short(s) ((short) (s))
 #endif
 
+/**
+ * Size of the output buffer.
+ *
+ * Valid streams have frame sizes in the range from 160 to 640. To avoid buffer
+ * overflows, we bail out if the decoder reports a value bigger than this.
+ */
 #define MAX_FRAME_SIZE 2000
+
 /* Copy Ogg packet to Speex bitstream */
 static int speexdec_write_frames(int packet_no,
                struct private_spxdec_data *psd, int skip_samples,
@@ -139,7 +146,14 @@ static int speexdec_write_frames(int packet_no,
        for (j = 0; j != psd->shi.nframes; j++) {
                short output[MAX_FRAME_SIZE], *btr_output;
                int skip = skip_samples + psd->lookahead, skip_idx = 0;
-               int samples, new_frame_size = psd->shi.frame_size;
+               int samples, this_frame_size,
+                       new_frame_size = psd->shi.frame_size;
+
+               if (speex_decoder_ctl(psd->shi.state, SPEEX_GET_FRAME_SIZE,
+                               &this_frame_size) == 0) {
+                       if (this_frame_size > MAX_FRAME_SIZE)
+                               return -E_SPX_DECODE_OVERFLOW;
+               };
 
                if (speex_decode_int(psd->shi.state, &psd->bits, output) < 0)
                        return -E_SPX_DECODE;
index c352851..701448e 100644 (file)
--- a/string.c
+++ b/string.c
@@ -633,7 +633,7 @@ int get_loglevel_by_name(const char *txt)
                return LL_CRIT;
        if (loglevel_equal(txt, "emerg"))
                return LL_EMERG;
-       return -1;
+       return -E_BAD_LL;
 }
 
 static int get_next_word(const char *buf, const char *delim, char **word)
@@ -1073,7 +1073,7 @@ __must_check int strwidth(const char *s, size_t *result)
                return -ERRNO_TO_PARA_ERROR(errno);
        if (num_wchars == 0)
                return 0;
-       dest = para_malloc(num_wchars * sizeof(*dest));
+       dest = para_malloc((num_wchars + 1) * sizeof(*dest));
        src = s;
        memset(&state, 0, sizeof(state));
        num_wchars = mbsrtowcs(dest, &src, num_wchars, &state);
index 6ef9ac8..15bb685 100644 (file)
@@ -1,4 +1,4 @@
-RM ?= rm -f
+RM = rm -f
 
 results_dir := $(test_dir)/test-results
 trash_dir := $(test_dir)/trashes
index a14a04e..7612851 100755 (executable)
@@ -45,7 +45,7 @@ bad[$i]='.'
 let i++
 commands[$i]="ls_ogg"
 required_objects[$i]='ogg_afh'
-cmdline[$i]="ls -lv ${oggs_base[@]}"
+cmdline[$i]="ls -l=v ${oggs_base[@]}"
 good[$i]='^basename:'
 
 let i++
index 7a627aa..fa32d41 100755 (executable)
@@ -32,8 +32,12 @@ test_require_objects "audiod"
 if [[ -n "$result" ]]; then
        test_skip 'para_audiod' "missing object(s): $result"
 else
-       test_expect_success 'para_audiod: recv/filter/writer options' \
-               "grep_man '$regex' audiod"
+       test_expect_success 'para_audiod: receivers' \
+               "grep_man 'Options for the http receiver' audiod"
+       test_expect_success 'para_audiod: filters' \
+               "grep_man 'Options for the compress filter' audiod"
+       test_expect_success 'para_audiod: writers' \
+               "grep_man 'Options for the file writer' audiod"
 fi
 
 # check various command lists
@@ -60,5 +64,4 @@ fi
 # para_play is always built
 regex='LIST OF COMMANDS.\{100,\}'
 test_expect_success 'para_play: play commands' "grep_man '$regex' play"
-regex="$rfw_regex"
 test_done
index 3379f98..bbc38f0 100644 (file)
@@ -156,11 +156,6 @@ err:
        return -ERRNO_TO_PARA_ERROR(errno);
 }
 
-static void udp_init_session(struct sender_client *sc)
-{
-       PARA_NOTICE_LOG("sending to udp %s\n", sc->name);
-}
-
 static void udp_shutdown_targets(void)
 {
        struct sender_client *sc, *tmp;
@@ -192,14 +187,14 @@ static int udp_resolve_target(const char *url, struct sender_command_data *scd)
 
 static int udp_com_on(__a_unused struct sender_command_data *scd)
 {
-       sender_status = SENDER_ON;
+       sender_status = SENDER_on;
        return 1;
 }
 
 static int udp_com_off(__a_unused struct sender_command_data *scd)
 {
        udp_shutdown_targets();
-       sender_status = SENDER_OFF;
+       sender_status = SENDER_off;
        return 1;
 }
 
@@ -239,7 +234,7 @@ static int udp_init_fec(struct sender_client *sc)
 {
        int mps;
 
-       udp_init_session(sc);
+       PARA_NOTICE_LOG("sending to udp %s\n", sc->name);
        mps = generic_max_transport_msg_size(sc->fd) - sizeof(struct udphdr);
        PARA_INFO_LOG("current MPS = %d bytes\n", mps);
        return mps;
@@ -282,7 +277,7 @@ static void udp_send_fec(struct sender_client *sc, char *buf, size_t len)
 {
        int ret;
 
-       if (sender_status == SENDER_OFF)
+       if (sender_status == SENDER_off)
                return;
        if (len == 0)
                return;
@@ -371,7 +366,7 @@ static char *udp_status(void)
                "status: %s\n"
                "port: %s\n"
                "targets: %s\n",
-               (sender_status == SENDER_ON)? "on" : "off",
+               (sender_status == SENDER_on)? "on" : "off",
                stringify_port(conf.udp_default_port_arg, "udp"),
                tgts? tgts : "(none)"
        );
@@ -430,15 +425,15 @@ void udp_send_init(struct sender *s)
        s->post_select = NULL;
        s->shutdown_clients = udp_shutdown_targets;
        s->resolve_target = udp_resolve_target;
-       s->client_cmds[SENDER_ON] = udp_com_on;
-       s->client_cmds[SENDER_OFF] = udp_com_off;
-       s->client_cmds[SENDER_DENY] = NULL;
-       s->client_cmds[SENDER_ALLOW] = NULL;
-       s->client_cmds[SENDER_ADD] = udp_com_add;
-       s->client_cmds[SENDER_DELETE] = udp_com_delete;
-       sender_status = SENDER_OFF;
+       s->client_cmds[SENDER_on] = udp_com_on;
+       s->client_cmds[SENDER_off] = udp_com_off;
+       s->client_cmds[SENDER_deny] = NULL;
+       s->client_cmds[SENDER_allow] = NULL;
+       s->client_cmds[SENDER_add] = udp_com_add;
+       s->client_cmds[SENDER_delete] = udp_com_delete;
+       sender_status = SENDER_off;
        udp_init_target_list();
        if (!conf.udp_no_autostart_given)
-               sender_status = SENDER_ON;
+               sender_status = SENDER_on;
        PARA_DEBUG_LOG("udp sender init complete\n");
 }
diff --git a/vss.c b/vss.c
index cbc05d1..51db768 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -905,7 +905,7 @@ static void vss_pre_select(struct sched *s, void *context)
 
 static int recv_afs_msg(int afs_socket, int *fd, uint32_t *code, uint32_t *data)
 {
-       char control[255], buf[8];
+       char control[255] __a_aligned(8), buf[8];
        struct msghdr msg = {.msg_iov = NULL};
        struct cmsghdr *cmsg;
        struct iovec iov;
index 88e3116..59abc53 100644 (file)
@@ -2011,21 +2011,19 @@ Doxygen
 ~~~~~~~
 
 Doxygen is a documentation system for various programming
-languages. The paraslash project uses Doxygen for generating the API
-reference on the web pages, but good source code documentation is
-also beneficial to people trying to understand the code structure
-and the interactions between the various source files.
+languages. The API reference on the paraslash web page is generated
+by doxygen.
 
 It is more illustrative to look at the source code for examples than
-to describe the conventions for documenting the source in this manual,
-so we only describe which parts of the code need doxygen comments,
-but leave out details on documentation conventions.
+to describe the conventions in this manual, so we only describe which
+parts of the code need doxygen comments, but leave out details on
+documentation conventions.
 
 As a rule, only the public part of the C source is documented with
 Doxygen. This includes structures, defines and enumerations in header
 files as well as public (non-static) C functions.  These should be
-documented completely. For example each parameter and the return
-value of a public function should get a descriptive comment.
+documented completely. For example, each parameter and the return
+value of a public function should get a descriptive doxygen comment.
 
 No doxygen comments are necessary for static functions and for
 structures and enumerations in C files (which are used only within