From: Andre Noll
Date: Sun, 17 Nov 2013 15:51:54 +0000 (+0100)
Subject: Merge branch 'maint'
X-Git-Tag: v0.5.1~7
X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=a29e6451e79365af6dce8d14f3056fc107b059fb;hp=e66a7267ca6cc374496dda803c6f9fdb631e99c0
Merge branch 'maint'
---
diff --git a/.gitignore b/.gitignore
index 9091a9c2..d340f207 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,7 +17,7 @@ TODO
*_command_list.h
*_command_list.man
paraslash-git.tar.bz2
-skencil/overview.pdf
+web/dia/overview.pdf
*.swp
error2.h
web_sync
diff --git a/FEATURES b/FEATURES
index 6ad420df..395d0f15 100644
--- a/FEATURES
+++ b/FEATURES
@@ -5,7 +5,7 @@ Features
* Runs on Linux, Mac OS, FreeBSD, NetBSD, Solaris and probably other
Unixes
- * Mp3, ogg/vorbis, ogg/speex, aac (m4a), wma and flac support
+ * Mp3, ogg/vorbis, ogg/speex, aac (m4a), wma, flac and ogg/opus support
* Native Alsa, OSS, CoreAudio output support
* Support for ESD, Pulseaudio, AIX, Solaris, IRIX through libao
* Local or remote http, dccp and udp network audio streaming
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 32802232..df7ed327 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -16,7 +16,7 @@ elif [[ -d .git || -f .git ]] &&
case "$VN" in
*$LF*) (exit 1) ;;
v[0-9]*)
- git update-index -q --refresh
+ git update-index -q --refresh &>/dev/null
test -z "$(git diff-index --name-only HEAD --)" ||
VN="$VN-dirty" ;;
esac
diff --git a/Makefile.in b/Makefile.in
index f82afd7b..cf8b9f71 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -8,7 +8,7 @@ MANDIR := @datarootdir@/man/man1
PACKAGE_VERSION := @PACKAGE_VERSION@
PACKAGE_STRING := @PACKAGE_STRING@
install_sh := @install_sh@
-executables := @executables@
+executables := $(addprefix para_, @executables@)
ggo_descriptions_declared := @ggo_descriptions_declared@
GENGETOPT := @gengetopt@
@@ -34,6 +34,7 @@ object_dir := $(build_dir)/objects
dep_dir := $(build_dir)/deps
man_dir := $(build_dir)/man/man1
cmdline_dir := $(build_dir)/cmdline
+m4depdir := $(build_dir)/m4deps
DEBUG_CPPFLAGS += -g -Wunused -Wundef -W
DEBUG_CPPFLAGS += -Wredundant-decls
@@ -80,13 +81,12 @@ CPPFLAGS += @osl_cppflags@
LDFLAGS += @clock_gettime_ldflags@
-man_pages := $(patsubst %, $(man_dir)/%.1, @executables@)
+man_pages := $(patsubst %, $(man_dir)/%.1, $(executables))
autocrap := config.h.in configure
tarball_pfx := @PACKAGE_TARNAME@-$(PACKAGE_VERSION)
tarball_delete := $(addprefix $(tarball_pfx)/,\
- web .changelog_before_cvs .changelog_cvs .gitignore\
- skencil)
+ web .changelog_before_cvs .changelog_cvs .gitignore)
tarball := @PACKAGE_TARNAME@-$(PACKAGE_VERSION).tar.bz2
# To put more focus on warnings, be less verbose as default
@@ -98,12 +98,12 @@ else
endif
.PHONY: dep all clean distclean maintainer-clean install man tarball
-all: dep @executables@ $(man_pages)
+all: dep $(executables) $(man_pages)
dep: $(deps)
man: $(man_pages)
tarball: $(tarball)
-$(object_dir) $(man_dir) $(ggo_dir) $(cmdline_dir) $(dep_dir):
+$(object_dir) $(man_dir) $(ggo_dir) $(cmdline_dir) $(dep_dir) $(m4depdir):
$(Q) $(MKDIR_P) $@
-include $(m4_ggo_dir)/makefile
@@ -230,6 +230,7 @@ all_objs := @recv_objs@ @filter_objs@ @client_objs@ @gui_objs@ \
@audiod_objs@ @audioc_objs@ @fade_objs@ @server_objs@ \
@write_objs@ @afh_objs@ @play_objs@
deps := $(addprefix $(dep_dir)/, $(all_objs:.o=.d))
+m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, @executables@))
recv_objs := $(addprefix $(object_dir)/, @recv_objs@)
filter_objs := $(addprefix $(object_dir)/, @filter_objs@)
@@ -245,6 +246,7 @@ play_objs := $(addprefix $(object_dir)/, @play_objs@)
ifeq ($(findstring clean, $(MAKECMDGOALS)),)
-include $(deps)
+-include $(m4_deps)
endif
para_recv: $(recv_objs)
@@ -293,7 +295,7 @@ para_play: $(play_objs)
clean:
@[ -z "$(Q)" ] || echo 'CLEAN'
- $(Q) rm -f @executables@
+ $(Q) rm -f $(executables)
$(Q) rm -rf $(object_dir)
clean2: clean
@@ -307,14 +309,12 @@ distclean: clean2 test-clean
$(Q) rm -f GPATH GRTAGS GSYMS GTAGS
maintainer-clean: distclean
- rm -f *.tar.bz2 \
- config.h configure \
- config.h.in skencil/*.pdf skencil/*.ps
+ rm -f *.tar.bz2 config.h configure config.h.in
rm -rf web_sync
install: all man
$(MKDIR_P) $(BINDIR) $(MANDIR)
- $(install_sh) -s -m 755 @executables@ $(BINDIR)
+ $(install_sh) -s -m 755 $(executables) $(BINDIR)
$(install_sh) -m 644 $(man_pages) $(MANDIR)
$(MKDIR_P) $(VARDIR) >/dev/null 2>&1 || true # not fatal, so don't complain
diff --git a/NEWS b/NEWS
index 4127e38b..fc6ccffb 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,37 @@
----------------------------------------------
-0.?.? (to be announced) "invertible validity"
----------------------------------------------
+NEWS
+====
+
+----------------------------------------------
+0.5.1 (to be announced) "temporary implication"
+----------------------------------------------
+
+ - audiod improvements and fixes.
+ - buffer tree robustness improvements.
+
+----------------------------------------
+0.5.0 (2013-08-23) "invertible validity"
+----------------------------------------
+
+Some API-breaking changes, one serious bug fix, and a lot of bike-shedding.
+
+ - The sideband compatibility code has been removed, hence
+ sideband connections (introduced in 0.4.11) are now mandatory.
+ - Addblob commands can produce output.
+ - The stat command no longer sends garbage when para_server was
+ compiled against libgcrypt.
+ - Dependencies for gengetopt files are computed automatically.
+ This eliminates a constant source of build bugs.
+ - The setatt command now accepts file name patterns rather than only
+ path names.
+ - overview.pdf is now based on dia, a simple diagram creation program.
+ The new version is much more detailed and contains descriptions of
+ the various programs of the paraslash package.
+ - The separator of all multi-word options has been changed from
+ underscore to dash. For example --log_color becomes --log-color.
+ - Overhauled web pages and the new logo.
+
+Downloads: ./releases/paraslash-0.5.0.tar.bz2 (tarball),
+./releases/paraslash-0.5.0.tar.bz2.asc (signature)
--------------------------------------
0.4.13 (2013-07-29) "spectral gravity"
diff --git a/README b/README
index e991b734..24b971d3 100644
--- a/README
+++ b/README
@@ -1,26 +1,12 @@
-README
-======
+The paraslash package contains server and client software for network
+audio streaming and stand-alone utilities for decoding and playing
+audio files. See the user manual for details.
-----
-Paraslash is an acronym for
+Distribution of paraslash is covered by the GNU GPL, version 2 unless
+otherwise stated. See file COPYING.
-_Play, archive, rate and stream large audio sets happily_
+Web page: http://paraslash.systemlinux.org/
+Git URL: git://paraslash.systemlinux.org/git
+Email: Andre Noll
-The paraslash package contains server and client software for
-network streaming as well as stand-alone utilities for decoding
-mp3, ogg, aac and wma files. See the user manual for details.
-
-
--------
-LICENSE
--------
-
-Distribution of paraslash is covered by the GNU GPL, version 2. See file
-COPYING.
-
-----------
-THE AUTHOR
-----------
-
-Andre Noll
Comments and bug reports are welcome.
diff --git a/acl.c b/acl.c
index 60f835ae..e70ab9b3 100644
--- a/acl.c
+++ b/acl.c
@@ -57,7 +57,7 @@ static int acl_lookup(int fd, struct list_head *acl)
PARA_ERROR_LOG("Can not determine peer address: %s\n", strerror(errno));
goto no_match;
}
- v4_addr = extract_v4_addr(&ss);
+ extract_v4_addr(&ss, &v4_addr);
if (!v4_addr.s_addr)
goto no_match;
diff --git a/afs.c b/afs.c
index c87fdf78..2f9df845 100644
--- a/afs.c
+++ b/afs.c
@@ -565,10 +565,7 @@ int afs_cb_result_handler(struct osl_object *result, uint8_t band,
assert(cc);
if (!result->size)
return 1;
- if (cc->use_sideband)
- return send_sb(&cc->scc, result->data, result->size, band,
- true);
- return sc_send_bin_buffer(&cc->scc, result->data, result->size);
+ return send_sb(&cc->scc, result->data, result->size, band, true);
}
static void com_select_callback(int fd, const struct osl_object *query)
@@ -807,7 +804,7 @@ static void command_pre_select(struct sched *s, struct task *t)
* \return Zero if \a buf is \p NULL or \a size is zero. Negative on errors,
* and positive on success.
*/
-int pass_buffer_as_shm(int fd, uint8_t band, char *buf, size_t size)
+int pass_buffer_as_shm(int fd, uint8_t band, const char *buf, size_t size)
{
int ret, shmid;
void *shm;
@@ -1068,9 +1065,6 @@ int com_init(struct command_context *cc)
}
ret = send_callback_request(create_tables_callback, &query,
afs_cb_result_handler, cc);
- if (ret < 0 && !cc->use_sideband)
- /* ignore return value */
- sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
return ret;
}
diff --git a/afs.h b/afs.h
index b415bfec..a63968f1 100644
--- a/afs.h
+++ b/afs.h
@@ -207,7 +207,7 @@ typedef void callback_function(int fd, const struct osl_object *);
*/
typedef int callback_result_handler(struct osl_object *result, uint8_t band, void *private);
int afs_cb_result_handler(struct osl_object *result, uint8_t band, void *private);
-int pass_buffer_as_shm(int fd, uint8_t band, char *buf, size_t size);
+int pass_buffer_as_shm(int fd, uint8_t band, const char *buf, size_t size);
/** Structure passed to the AFS max_size handler. */
struct afs_max_size_handler_data {
diff --git a/aft.c b/aft.c
index a2883d4a..377740d1 100644
--- a/aft.c
+++ b/aft.c
@@ -1876,12 +1876,8 @@ static int add_one_audio_file(const char *path, void *private_data)
ret = 1;
if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */
if (pad->flags & ADD_FLAG_VERBOSE)
- send_ret = pad->cc->use_sideband?
- send_sb_va(&pad->cc->scc, SBD_OUTPUT,
- "lazy-ignore: %s\n", path)
- :
- sc_send_va_buffer(&pad->cc->scc,
- "lazy-ignore: %s\n", path);
+ send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
+ "lazy-ignore: %s\n", path);
goto out_free;
}
/* We still want to add this file. Compute its hash. */
@@ -1901,12 +1897,8 @@ static int add_one_audio_file(const char *path, void *private_data)
ret = 1;
if (pb && hs && hs == pb && !(pad->flags & ADD_FLAG_FORCE)) {
if (pad->flags & ADD_FLAG_VERBOSE)
- send_ret = pad->cc->use_sideband?
- send_sb_va(&pad->cc->scc, SBD_OUTPUT,
- "%s exists, not forcing update\n", path)
- :
- sc_send_va_buffer(&pad->cc->scc,
- "%s exists, not forcing update\n", path);
+ send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
+ "%s exists, not forcing update\n", path);
goto out_unmap;
}
/*
@@ -1923,12 +1915,8 @@ static int add_one_audio_file(const char *path, void *private_data)
munmap(map.data, map.size);
close(fd);
if (pad->flags & ADD_FLAG_VERBOSE) {
- send_ret = pad->cc->use_sideband?
- send_sb_va(&pad->cc->scc, SBD_OUTPUT,
- "adding %s\n", path)
- :
- sc_send_va_buffer(&pad->cc->scc,
- "adding %s\n", path);
+ send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
+ "adding %s\n", path);
if (send_ret < 0)
goto out_free;
}
@@ -1943,14 +1931,8 @@ out_unmap:
munmap(map.data, map.size);
out_free:
if (ret < 0 && send_ret >= 0)
- send_ret = pad->cc->use_sideband?
- send_sb_va(&pad->cc->scc, SBD_ERROR_LOG,
- "failed to add %s (%s)\n", path,
- para_strerror(-ret))
- :
- sc_send_va_buffer(&pad->cc->scc,
- "failed to add %s (%s)\n", path,
- para_strerror(-ret));
+ send_ret = send_sb_va(&pad->cc->scc, SBD_ERROR_LOG,
+ "failed to add %s (%s)\n", path, para_strerror(-ret));
free(obj.data);
clear_afhi(afhi_ptr);
/* Stop adding files only on send errors. */
@@ -1994,11 +1976,7 @@ int com_add(struct command_context *cc)
char *path;
ret = verify_path(cc->argv[i], &path);
if (ret < 0) {
- ret = cc->use_sideband?
- send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s: %s\n",
- cc->argv[i], para_strerror(-ret))
- :
- sc_send_va_buffer(&cc->scc, "%s: %s\n",
+ ret = send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s: %s\n",
cc->argv[i], para_strerror(-ret));
if (ret < 0)
return ret;
@@ -2006,14 +1984,9 @@ int com_add(struct command_context *cc)
}
ret = stat(path, &statbuf);
if (ret < 0) {
- ret = cc->use_sideband?
- send_sb_va(&cc->scc, SBD_ERROR_LOG,
- "failed to stat %s (%s)\n", path,
- strerror(errno))
- :
- sc_send_va_buffer(&cc->scc,
- "failed to stat %s (%s)\n", path,
- strerror(errno));
+ ret = send_sb_va(&cc->scc, SBD_ERROR_LOG,
+ "failed to stat %s (%s)\n", path,
+ strerror(errno));
free(path);
if (ret < 0)
return ret;
@@ -2025,12 +1998,8 @@ int com_add(struct command_context *cc)
else
ret = add_one_audio_file(path, &pad);
if (ret < 0) {
- if (cc->use_sideband)
- send_sb_va(&cc->scc, SBD_OUTPUT, "%s: %s\n", path,
- para_strerror(-ret));
- else
- sc_send_va_buffer(&cc->scc, "%s: %s\n", path,
- para_strerror(-ret));
+ send_sb_va(&cc->scc, SBD_OUTPUT, "%s: %s\n", path,
+ para_strerror(-ret));
free(path);
return ret;
}
@@ -2502,6 +2471,108 @@ int com_cpsi(struct command_context *cc)
return ret;
}
+struct change_atts_data {
+ uint64_t add_mask, del_mask;
+ struct para_buffer pb;
+};
+
+static int change_atts(__a_unused struct osl_table *table,
+ struct osl_row *row, __a_unused const char *name, void *data)
+{
+ int ret;
+ struct osl_object obj;
+ struct afs_info old_afsi, new_afsi;
+ struct afsi_change_event_data aced = {
+ .aft_row = row,
+ .old_afsi = &old_afsi
+ };
+ struct change_atts_data *cad = data;
+
+ ret = get_afsi_object_of_row(row, &obj);
+ if (ret < 0)
+ return ret;
+ ret = load_afsi(&old_afsi, &obj);
+ if (ret < 0)
+ return ret;
+ new_afsi = old_afsi;
+ new_afsi.attributes |= cad->add_mask;
+ new_afsi.attributes &= ~cad->del_mask;
+ save_afsi(&new_afsi, &obj); /* in-place update */
+ afs_event(AFSI_CHANGE, &cad->pb, &aced);
+ return 1;
+}
+
+static void com_setatt_callback(int fd, const struct osl_object *query)
+{
+ char *p;
+ int ret;
+ size_t len;
+ struct change_atts_data cad = {
+ .pb = {
+ .max_size = shm_get_shmmax(),
+ .max_size_handler = afs_max_size_handler,
+ .private_data = &(struct afs_max_size_handler_data) {
+ .fd = fd,
+ .band = SBD_OUTPUT
+ }
+ }
+ };
+ struct pattern_match_data pmd = {
+ .table = audio_file_table,
+ .loop_col_num = AFTCOL_HASH,
+ .match_col_num = AFTCOL_PATH,
+ .pm_flags = PM_SKIP_EMPTY_NAME,
+ .data = &cad,
+ .action = change_atts
+ };
+
+ for (p = query->data; p < (char *)query->data + query->size; p += len + 1) {
+ char c;
+ unsigned char bitnum;
+
+ len = strlen(p);
+ ret = -E_ATTR_SYNTAX;
+ if (len == 0)
+ goto out;
+ c = p[len - 1];
+ if (c != '+' && c != '-')
+ break;
+ p[len - 1] = '\0';
+ ret = get_attribute_bitnum_by_name(p, &bitnum);
+ if (ret < 0)
+ goto out;
+ if (c == '+')
+ cad.add_mask |= (1UL << bitnum);
+ else
+ cad.del_mask |= (1UL << bitnum);
+ }
+ ret = -E_ATTR_SYNTAX;
+ if (!cad.add_mask && !cad.del_mask)
+ goto out;
+ pmd.patterns.data = p;
+ assert(p < (char *)query->data + query->size);
+ pmd.patterns.size = (char *)query->data + query->size - p;
+ ret = for_each_matching_row(&pmd);
+ if (ret < 0)
+ goto out;
+ if (pmd.num_matches == 0)
+ para_printf(&cad.pb, "no matches\n");
+out:
+ if (ret < 0)
+ para_printf(&cad.pb, "%s\n", para_strerror(-ret));
+ if (cad.pb.offset)
+ pass_buffer_as_shm(fd, SBD_OUTPUT, cad.pb.buf, cad.pb.offset);
+ free(cad.pb.buf);
+}
+
+int com_setatt(struct command_context *cc)
+{
+ if (cc->argc < 3)
+ return -E_ATTR_SYNTAX;
+ return send_standard_callback_request(cc->argc - 1, cc->argv + 1,
+ com_setatt_callback, afs_cb_result_handler, cc);
+}
+
static void afs_stat_callback(int fd, const struct osl_object *query)
{
int *parser_friendly = query->data;
diff --git a/amp_filter.c b/amp_filter.c
index f62ea8a2..b0f36872 100644
--- a/amp_filter.c
+++ b/amp_filter.c
@@ -58,7 +58,7 @@ static void amp_open(struct filter_node *fn)
sscanf(stat_item_values[SI_AMPLIFICATION], "%u", &pad->amp);
else
pad->amp = conf->amp_arg;
- PARA_NOTICE_LOG("amplification: %u (scaling factor: %1.2f)\n",
+ PARA_INFO_LOG("amplification: %u (scaling factor: %1.2f)\n",
pad->amp, pad->amp / 64.0 + 1.0);
}
@@ -73,7 +73,7 @@ static int amp_post_select(__a_unused struct sched *s, struct task *t)
bool inplace = btr_inplace_ok(btrn);
if (pad->amp == 0) { /* no amplification */
- btr_splice_out_node(btrn);
+ btr_splice_out_node(&fn->btrn);
return -E_AMP_ZERO_AMP;
}
next_buffer:
diff --git a/attribute.c b/attribute.c
index 96b54c99..867e24b9 100644
--- a/attribute.c
+++ b/attribute.c
@@ -212,85 +212,10 @@ int com_lsatt(struct command_context *cc)
if (ret < 0)
send_strerror(cc, -ret);
else if (ret == 0 && cc->argc > 1)
- ret = cc->use_sideband?
- send_sb_va(&cc->scc, SBD_ERROR_LOG, "no matches\n")
- :
- sc_send_va_buffer(&cc->scc, "no matches\n");
+ ret = send_sb_va(&cc->scc, SBD_ERROR_LOG, "no matches\n");
return ret;
}
-static void com_setatt_callback(__a_unused int fd, const struct osl_object *query)
-{
- char *p;
- uint64_t add_mask = 0, del_mask = 0;
- int ret;
- size_t len;
- struct osl_object obj;
- struct osl_row *row;
-
- for (p = query->data; p < (char *)query->data + query->size; p += len + 1) {
- char c;
-
- len = strlen(p);
- ret = -E_ATTR_SYNTAX;
- if (!*p)
- goto out;
- c = p[len - 1];
- if (c != '+' && c != '-')
- break;
- p[len - 1] = '\0';
- obj.data = p;
- obj.size = len + 1;
- ret = osl(osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row));
- if (ret < 0)
- goto out;
- ret = osl(osl_get_object(attribute_table, row, ATTCOL_BITNUM,
- &obj));
- if (ret < 0)
- goto out;
- if (c == '+')
- add_mask |= (1UL << *(unsigned char *)obj.data);
- else
- del_mask |= (1UL << *(unsigned char *)obj.data);
- }
- ret = -E_ATTR_SYNTAX;
- if (!add_mask && !del_mask)
- goto out;
- PARA_DEBUG_LOG("masks: %llx:%llx\n",(long long unsigned)add_mask,
- (long long unsigned)del_mask);
- for (; p < (char *)query->data + query->size; p += len + 1) { /* TODO: fnmatch */
- struct afs_info old_afsi, new_afsi;
- struct afsi_change_event_data aced = {.old_afsi = &old_afsi};
-
- len = strlen(p);
- ret = aft_get_row_of_path(p, &aced.aft_row);
- if (ret < 0)
- goto out;
- ret = get_afsi_object_of_row(aced.aft_row, &obj);
- if (ret < 0)
- goto out;
- ret = load_afsi(&old_afsi, &obj);
- if (ret < 0)
- goto out;
- new_afsi = old_afsi;
- new_afsi.attributes |= add_mask;
- new_afsi.attributes &= ~del_mask;
- save_afsi(&new_afsi, &obj); /* in-place update */
- afs_event(AFSI_CHANGE, NULL, &aced);
- }
-out:
- if (ret < 0)
- PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
-}
-
-int com_setatt(struct command_context *cc)
-{
- if (cc->argc < 3)
- return -E_ATTR_SYNTAX;
- return send_standard_callback_request(cc->argc - 1, cc->argv + 1,
- com_setatt_callback, NULL, NULL);
-}
-
struct addatt_event_data {
const char *name;
unsigned char bitnum;
diff --git a/audiod.c b/audiod.c
index 8f2a72ac..5ef57781 100644
--- a/audiod.c
+++ b/audiod.c
@@ -520,12 +520,13 @@ static void open_writers(struct slot_info *s)
assert(s->wns == NULL);
s->wns = para_calloc(PARA_MAX(1U, a->num_writers)
* sizeof(struct writer_node));
- PARA_INFO_LOG("opening %s writers\n", audio_formats[s->format]);
for (i = 0; i < a->num_writers; i++) {
wn = s->wns + i;
wn->conf = a->writer_conf[i];
wn->writer_num = a->writer_nums[i];
register_writer_node(wn, parent, &sched);
+ PARA_NOTICE_LOG("%s writer started in slot %d\n",
+ writer_names[a->writer_nums[i]], (int)(s - slot));
}
}
@@ -914,7 +915,7 @@ out:
static int parse_filter_args(void)
{
- int i, j, ret, af_mask;
+ int i, j, ret, af_mask, num_matches;
for (i = 0; i < conf.filter_given; i++) {
char *arg;
@@ -922,13 +923,18 @@ static int parse_filter_args(void)
if (ret < 0)
goto out;
af_mask = ret;
+ num_matches = 0;
FOR_EACH_AUDIO_FORMAT(j) {
if ((af_mask & (1 << j)) == 0) /* no match */
continue;
ret = add_filter(j, arg);
if (ret < 0)
goto out;
+ num_matches++;
}
+ if (num_matches == 0)
+ PARA_WARNING_LOG("ignoring filter spec: %s\n",
+ conf.filter_arg[i]);
}
ret = init_default_filters(); /* use default values for the rest */
out:
@@ -1001,7 +1007,7 @@ static int signal_post_select(struct sched *s, __a_unused struct task *t)
case SIGINT:
case SIGTERM:
case SIGHUP:
- PARA_EMERG_LOG("terminating on signal %d\n", signum);
+ PARA_NOTICE_LOG("received signal %d\n", signum);
clean_exit(EXIT_FAILURE, "caught deadly signal");
}
return 0;
@@ -1025,19 +1031,35 @@ static int command_post_select(struct sched *s, struct task *t)
int ret;
struct command_task *ct = container_of(t, struct command_task, task);
static struct timeval last_status_dump;
- struct timeval tmp, delay = {0, 500 * 1000};
-
- tv_add(&last_status_dump, &delay, &tmp);
- if (tv_diff(&tmp, now, NULL) < 0) {
- audiod_status_dump();
- last_status_dump = *now;
- }
+ struct timeval tmp, delay;
+ bool force = true;
ret = handle_connect(ct->fd, &s->rfds);
if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
- audiod_status_dump();
- return 0;
+ else if (ret > 0)
+ goto dump;
+
+ /* if last status dump was less than 500ms ago, do nothing */
+ delay.tv_sec = 0;
+ delay.tv_usec = 500 * 1000;
+ tv_add(&last_status_dump, &delay, &tmp);
+ if (tv_diff(now, &tmp, NULL) < 0)
+ return 0;
+
+ /*
+ * If last status dump was more than 5s ago, force update. Otherwise,
+ * update only those items that have changed.
+ */
+ delay.tv_sec = 5;
+ delay.tv_usec = 0;
+ tv_add(&last_status_dump, &delay, &tmp);
+ if (tv_diff(now, &tmp, NULL) < 0)
+ force = false;
+dump:
+ audiod_status_dump(force);
+ last_status_dump = *now;
+ return 1;
}
static void init_command_task(struct command_task *ct)
@@ -1060,28 +1082,7 @@ static void close_stat_pipe(void)
stat_task->offset_seconds = 0;
stat_task->vss_status = 0;
stat_task->current_audio_format_num = -1;
- audiod_status_dump();
-}
-
-/**
- * close the connection to para_server and exit
- *
- * \param status the exit status which is passed to exit(3)
- * \param msg the log message
- *
- * Log \a msg with loglevel \p EMERG, close the connection to para_server if
- * open, and call \p exit(status). \a status should be either EXIT_SUCCESS or
- * EXIT_FAILURE.
- *
- * \sa exit(3)
- */
-void __noreturn clean_exit(int status, const char *msg)
-{
- PARA_EMERG_LOG("%s\n", msg);
- if (socket_name)
- unlink(socket_name);
- close_stat_pipe();
- exit(status);
+ audiod_status_dump(true);
}
/* avoid busy loop if server is down */
@@ -1115,20 +1116,51 @@ static bool must_close_slot(int slot_num)
return true;
}
+static void close_slot(int slot_num)
+{
+ struct slot_info *s = slot + slot_num;
+
+ PARA_INFO_LOG("closing slot %d\n", slot_num);
+ close_writers(s);
+ close_filters(s);
+ close_receiver(slot_num);
+ clear_slot(slot_num);
+}
+
static void close_unused_slots(void)
{
int i;
- FOR_EACH_SLOT(i) {
- struct slot_info *s = slot + i;
- if (!must_close_slot(i))
- continue;
- PARA_INFO_LOG("closing slot %d\n", i);
- close_writers(s);
- close_filters(s);
- close_receiver(i);
- clear_slot(i);
- }
+ FOR_EACH_SLOT(i)
+ if (must_close_slot(i))
+ close_slot(i);
+}
+
+/**
+ * Close the connection to para_server and exit.
+ *
+ * \param status The exit status which is passed to exit(3).
+ * \param msg The log message
+ *
+ * Log \a msg with loglevel \p EMERG, close the connection to para_server and
+ * all slots, and call \p exit(status). \a status should be either EXIT_SUCCESS
+ * or EXIT_FAILURE.
+ *
+ * \sa exit(3).
+ */
+void __noreturn clean_exit(int status, const char *msg)
+{
+ int i;
+
+ if (socket_name)
+ unlink(socket_name);
+ close_stat_pipe();
+ FOR_EACH_SLOT(i)
+ close_slot(i);
+ audiod_cmdline_parser_free(&conf);
+ close_stat_clients();
+ PARA_EMERG_LOG("%s\n", msg);
+ exit(status);
}
/*
@@ -1212,25 +1244,26 @@ static int status_post_select(struct sched *s, struct task *t)
char *buf;
size_t sz;
int ret;
- if (st->ct->task.error < 0) {
+
+ ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF);
+ if (ret < 0) {
close_stat_pipe();
goto out;
}
- if (st->ct->status != CL_RECEIVING)
+ if (st->ct->status != CL_EXECUTING)
goto out;
- ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF);
- if (ret <= 0) {
+ if (ret == 0) {
struct timeval diff;
tv_diff(now, &st->last_status_read, &diff);
if (diff.tv_sec > 61)
- task_notify(&st->ct->task, E_AUDIOD_OFF);
+ task_notify(&st->ct->task, E_STATUS_TIMEOUT);
goto out;
}
btr_merge(st->btrn, st->min_iqs);
sz = btr_next_buffer(st->btrn, &buf);
ret = for_each_stat_item(buf, sz, update_item);
if (ret < 0) {
- task_notify(&st->ct->task, E_AUDIOD_OFF);
+ task_notify(&st->ct->task, -ret);
goto out;
}
if (sz != ret) {
diff --git a/audiod.h b/audiod.h
index e54a8576..5485b424 100644
--- a/audiod.h
+++ b/audiod.h
@@ -68,12 +68,13 @@ extern int audiod_status;
void __noreturn clean_exit(int status, const char *msg);
int handle_connect(int accept_fd, fd_set *rfds);
-void audiod_status_dump(void);
+void audiod_status_dump(bool force);
char *get_time_string(int slot_num);
struct btr_node *audiod_get_btr_root(void);
void stat_client_write_item(int item_num);
void clear_and_dump_items(void);
+void close_stat_clients(void);
/** iterate over all slots */
#define FOR_EACH_SLOT(_slot) for (_slot = 0; _slot < MAX_STREAM_SLOTS; _slot++)
diff --git a/audiod_command.c b/audiod_command.c
index b49d659e..07b2c81c 100644
--- a/audiod_command.c
+++ b/audiod_command.c
@@ -30,7 +30,7 @@ extern struct sched sched;
extern char *stat_item_values[NUM_STAT_ITEMS];
-struct audiod_command audiod_cmds[] = {DEFINE_AUDIOD_CMD_ARRAY};
+static struct audiod_command audiod_cmds[] = {DEFINE_AUDIOD_CMD_ARRAY};
/** Iterate over the array of all audiod commands. */
#define FOR_EACH_COMMAND(c) for (c = 0; audiod_cmds[c].name; c++)
@@ -109,6 +109,31 @@ static int stat_client_add(int fd, uint64_t mask, int parser_friendly)
num_clients++;
return 1;
}
+
+static void close_stat_client(struct stat_client *sc)
+{
+ PARA_INFO_LOG("closing client fd %d\n", sc->fd);
+ close(sc->fd);
+ list_del(&sc->node);
+ free(sc);
+ num_clients--;
+}
+
+/**
+ * Empty the status clients list.
+ *
+ * This iterates over the list of connected status clients, closes each client
+ * file descriptor and frees the resources.
+ */
+void close_stat_clients(void)
+{
+ struct stat_client *sc, *tmp;
+
+ list_for_each_entry_safe(sc, tmp, &client_list, node)
+ close_stat_client(sc);
+ assert(num_clients == 0);
+}
+
/**
* Write a message to all connected status clients.
*
@@ -127,7 +152,7 @@ void stat_client_write_item(int item_num)
struct para_buffer *b;
list_for_each_entry_safe(sc, tmp, &client_list, node) {
- int fd = sc->fd, ret;
+ int ret;
if (!((one << item_num) & sc->item_mask))
continue;
@@ -135,15 +160,11 @@ void stat_client_write_item(int item_num)
if (!b->buf)
(void)WRITE_STATUS_ITEM(b, item_num, "%s\n",
msg? msg : "");
- ret = write(fd, b->buf, b->offset);
+ ret = write(sc->fd, b->buf, b->offset);
if (ret == b->offset)
continue;
/* write error or short write */
- close(fd);
- num_clients--;
- PARA_INFO_LOG("deleting client on fd %d\n", fd);
- list_del(&sc->node);
- free(sc);
+ close_stat_client(sc);
dump_stat_client_list();
}
free(pb.buf);
@@ -320,7 +341,6 @@ static int com_stat(int fd, int argc, char **argv)
if (!strncmp(arg, "-p", 2)) {
parser_friendly = 1;
b.flags = PBF_SIZE_PREFIX;
- continue;
}
}
if (i >= argc)
@@ -466,8 +486,10 @@ out:
/**
* Send the current audiod status to all connected stat clients.
+ *
+ * \param force Whether to write unchanged items.
*/
-void audiod_status_dump(void)
+void audiod_status_dump(bool force)
{
int slot_num = get_play_time_slot_num();
char *old, *new;
@@ -475,7 +497,7 @@ void audiod_status_dump(void)
old = stat_item_values[SI_PLAY_TIME];
new = get_time_string(slot_num);
if (new) {
- if (!old || strcmp(old, new)) {
+ if (force || !old || strcmp(old, new)) {
free(old);
stat_item_values[SI_PLAY_TIME] = new;
stat_client_write_item(SI_PLAY_TIME);
@@ -485,7 +507,7 @@ void audiod_status_dump(void)
new = get_server_uptime_str(now);
old = stat_item_values[SI_AUDIOD_UPTIME];
- if (!old || strcmp(old, new)) {
+ if (force || !old || strcmp(old, new)) {
free(old);
stat_item_values[SI_AUDIOD_UPTIME] = new;
stat_client_write_item(SI_AUDIOD_UPTIME);
@@ -494,7 +516,7 @@ void audiod_status_dump(void)
old = stat_item_values[SI_AUDIOD_STATUS];
new = audiod_status_string();
- if (!old || strcmp(old, new)) {
+ if (force || !old || strcmp(old, new)) {
free(old);
stat_item_values[SI_AUDIOD_STATUS] = new;
stat_client_write_item(SI_AUDIOD_STATUS);
@@ -503,7 +525,7 @@ void audiod_status_dump(void)
old = stat_item_values[SI_DECODER_FLAGS];
new = decoder_flags();
- if (!old || strcmp(old, new)) {
+ if (force || !old || strcmp(old, new)) {
free(old);
stat_item_values[SI_DECODER_FLAGS] = new;
stat_client_write_item(SI_DECODER_FLAGS);
diff --git a/blob.c b/blob.c
index cd571d74..373d8d00 100644
--- a/blob.c
+++ b/blob.c
@@ -311,12 +311,12 @@ static int com_rmblob(callback_function *f, struct command_context *cc)
afs_cb_result_handler, cc);
}
-static void com_addblob_callback(struct osl_table *table, __a_unused int fd,
+static void com_addblob_callback(struct osl_table *table, int fd,
const struct osl_object *query)
{
struct osl_object objs[NUM_BLOB_COLUMNS];
- char *name = query->data;
- size_t name_len = strlen(name) + 1;
+ char *name = query->data, *msg;
+ size_t name_len = strlen(name) + 1, msg_len;
uint32_t id;
unsigned num_rows;
int ret;
@@ -344,6 +344,10 @@ static void com_addblob_callback(struct osl_table *table, __a_unused int fd,
if (ret < 0 && ret != -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND))
goto out;
if (ret >= 0) { /* we already have a blob with this name */
+ ret = osl(osl_get_object(table, row, BLOBCOL_ID, &obj));
+ if (ret < 0)
+ goto out;
+ id = *(uint32_t *)obj.data;
obj.data = name + name_len;
obj.size = query->size - name_len;
ret = osl(osl_update_object(table, row, BLOBCOL_DEF, &obj));
@@ -377,81 +381,88 @@ static void com_addblob_callback(struct osl_table *table, __a_unused int fd,
afs_event(BLOB_ADD, NULL, table);
out:
if (ret < 0)
- PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
+ msg_len = xasprintf(&msg, "could not add %s: %s\n", name,
+ para_strerror(-ret));
+ else
+ msg_len = xasprintf(&msg, "added %s as id %u\n", name, id);
+ pass_buffer_as_shm(fd, SBD_OUTPUT, msg, msg_len);
+ free(msg);
}
-/*
- * write input from fd to dynamically allocated buffer,
- * but maximal max_size byte.
- */
-static int fd2buf(struct stream_cipher_context *scc, unsigned max_size, struct osl_object *obj)
+/* Write input from fd to dynamically allocated buffer, but maximal 10M. */
+static int fd2buf(struct stream_cipher_context *scc, struct osl_object *obj)
{
- const size_t chunk_size = 1024;
- size_t size = 2048, received = 0;
+ size_t max_size = 10 * 1024 * 1024;
int ret;
- char *buf = para_malloc(size);
+ struct iovec iov;
- for (;;) {
- ret = sc_recv_bin_buffer(scc, buf + received, chunk_size);
- if (ret <= 0)
- break;
- received += ret;
- if (received + chunk_size >= size) {
- size *= 2;
- ret = -E_INPUT_TOO_LARGE;
- if (size > max_size)
- break;
- buf = para_realloc(buf, size);
- }
+ obj->data = NULL;
+ obj->size = 0;
+again:
+ do {
+ ret = recv_sb(scc, SBD_BLOB_DATA, max_size, &iov);
+ } while (ret == 0);
+
+ if (ret < 0) {
+ free(obj->data);
+ obj->data = NULL;
+ obj->size = 0;
+ return ret;
}
- obj->data = buf;
- obj->size = received;
- if (ret < 0)
- free(buf);
- return ret;
+ if (iov.iov_len == 0) /* end of blob */
+ return 1;
+ if (!obj->data) {
+ obj->data = iov.iov_base;
+ obj->size = iov.iov_len;
+ } else {
+ obj->data = para_realloc(obj->data, obj->size + iov.iov_len);
+ memcpy(obj->data + obj->size, iov.iov_base, iov.iov_len);
+ obj->size += iov.iov_len;
+ free(iov.iov_base);
+ max_size -= iov.iov_len;
+ }
+ goto again;
+ return 1;
}
/*
* Read data from a file descriptor, and send it to the afs process.
*
- * \param scc crypt context containing the file descriptor to read data from.
+ * \param cc Contains the file descriptor to read data from.
* \param arg_obj Pointer to the arguments to \a f.
* \param f The callback function.
- * \param max_len Don't read more than that many bytes from stdin.
* \param result_handler See \ref send_callback_request.
* \param private_result_data See \ref send_callback_request.
*
- * This function is used by commands that wish to let para_server store
- * arbitrary data specified by the user (for instance the add_blob family of
- * commands). First, at most \a max_len bytes are read and decrypted from the
- * file descriptor given by \a scc. The result is concatenated with the buffer
- * given by \a arg_obj, and the combined buffer is made available to the afs
- * process via the callback method. See \ref send_callback_request for details.
+ * This function is used by the addblob commands that instruct para_server to
+ * store arbitrary data in a blob table. Input data is read and decrypted from
+ * the file descriptor given by \a cc. This data is concatenated with the
+ * buffer given by \a arg_obj, and the combined buffer is made available to the
+ * afs process via the callback method. See \ref send_callback_request for
+ * details.
*
* \return Negative on errors, the return value of the underlying call to
* send_callback_request() otherwise.
*/
static int stdin_command(struct command_context *cc, struct osl_object *arg_obj,
- callback_function *f, unsigned max_len,
- callback_result_handler *result_handler,
+ callback_function *f, callback_result_handler *result_handler,
void *private_result_data)
{
struct osl_object query, stdin_obj;
int ret;
- if (cc->use_sideband)
- ret = send_sb(&cc->scc, NULL, 0, SBD_AWAITING_DATA, false);
- else
- ret = sc_send_buffer(&cc->scc, AWAITING_DATA_MSG);
+ ret = send_sb(&cc->scc, NULL, 0, SBD_AWAITING_DATA, false);
if (ret < 0)
return ret;
- ret = fd2buf(&cc->scc, max_len, &stdin_obj);
+ ret = fd2buf(&cc->scc, &stdin_obj);
if (ret < 0)
return ret;
query.size = arg_obj->size + stdin_obj.size;
query.data = para_malloc(query.size);
memcpy(query.data, arg_obj->data, arg_obj->size);
- memcpy((char *)query.data + arg_obj->size, stdin_obj.data, stdin_obj.size);
+ if (stdin_obj.size > 0)
+ memcpy((char *)query.data + arg_obj->size, stdin_obj.data,
+ stdin_obj.size);
free(stdin_obj.data);
ret = send_callback_request(f, &query, result_handler, private_result_data);
free(query.data);
@@ -468,7 +479,7 @@ static int com_addblob(callback_function *f, struct command_context *cc)
return -E_BLOB_SYNTAX;
arg_obj.size = strlen(cc->argv[1]) + 1;
arg_obj.data = (char *)cc->argv[1];
- return stdin_command(cc, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL);
+ return stdin_command(cc, &arg_obj, f, afs_cb_result_handler, cc);
}
/* FIXME: Print output to client, not to log file */
diff --git a/buffer_tree.c b/buffer_tree.c
index aa9f1cdb..56ab2b24 100644
--- a/buffer_tree.c
+++ b/buffer_tree.c
@@ -544,14 +544,16 @@ static bool btr_no_children(struct btr_node *btrn)
}
/**
- * Find out whether a node is an orphan node.
+ * Find out whether a node is an orphan.
*
* \param btrn The buffer tree node.
*
* \return True if \a btrn has no parent.
*
- * This function will always return true for the root node. However in case
- * nodes have been removed from the tree, other nodes may become orphans too.
+ * This function returns true for the root node and false for any other node.
+ *
+ * After a (non-leaf) node was removed removed from the tree, the function
+ * returns true for all child nodes.
*/
bool btr_no_parent(struct btr_node *btrn)
{
@@ -833,7 +835,7 @@ size_t btr_get_input_queue_size(struct btr_node *btrn)
/**
* Remove a node from the buffer tree, reconnecting parent and children.
*
- * \param btrn The node to splice out.
+ * \param btrnp The node to splice out.
*
* This function is used by buffer tree nodes that do not exist during the
* whole lifetime of the buffer tree. Unlike btr_remove_node(), calling
@@ -841,9 +843,9 @@ size_t btr_get_input_queue_size(struct btr_node *btrn)
* but reconnects the buffer tree by making all child nodes of \a btrn children
* of the parent of \a btrn.
*/
-void btr_splice_out_node(struct btr_node *btrn)
+void btr_splice_out_node(struct btr_node **btrnp)
{
- struct btr_node *ch, *tmp;
+ struct btr_node *btrn = *btrnp, *ch, *tmp;
assert(btrn);
PARA_NOTICE_LOG("splicing out %s\n", btrn->name);
@@ -860,7 +862,7 @@ void btr_splice_out_node(struct btr_node *btrn)
list_del(&ch->node);
}
assert(list_empty(&btrn->children));
- btrn->parent = NULL;
+ *btrnp = NULL;
}
/**
@@ -1201,21 +1203,20 @@ int btr_node_status(struct btr_node *btrn, size_t min_iqs,
size_t iqs;
assert(btrn);
- if (type != BTR_NT_LEAF) {
- if (btr_no_children(btrn))
- return -E_BTR_NO_CHILD;
- if (btr_get_output_queue_size(btrn) > BTRN_MAX_PENDING)
- return 0;
- }
- if (type != BTR_NT_ROOT) {
- if (btr_eof(btrn))
- return -E_BTR_EOF;
- iqs = btr_get_input_queue_size(btrn);
- if (iqs == 0) /* we have a parent, because not eof */
- return 0;
- if (iqs < min_iqs && !btr_no_parent(btrn))
- return 0;
- }
+ if (type != BTR_NT_LEAF && btr_no_children(btrn))
+ return -E_BTR_NO_CHILD;
+ if (type != BTR_NT_ROOT && btr_eof(btrn))
+ return -E_BTR_EOF;
+
+ if (btr_get_output_queue_size(btrn) > BTRN_MAX_PENDING)
+ return 0;
+ if (type == BTR_NT_ROOT)
+ return 1;
+ iqs = btr_get_input_queue_size(btrn);
+ if (iqs == 0) /* we have a parent, because not eof */
+ return 0;
+ if (iqs < min_iqs && !btr_no_parent(btrn))
+ return 0;
return 1;
}
diff --git a/buffer_tree.h b/buffer_tree.h
index 20dcd62d..6127dd92 100644
--- a/buffer_tree.h
+++ b/buffer_tree.h
@@ -192,7 +192,7 @@ size_t btr_next_buffer(struct btr_node *btrn, char **bufp);
size_t btr_next_buffer_omit(struct btr_node *btrn, size_t omit, char **bufp);
void btr_consume(struct btr_node *btrn, size_t numbytes);
int btr_exec_up(struct btr_node *btrn, const char *command, char **value_result);
-void btr_splice_out_node(struct btr_node *btrn);
+void btr_splice_out_node(struct btr_node **btrnp);
void btr_pushdown(struct btr_node *btrn);
void *btr_context(struct btr_node *btrn);
void btr_merge(struct btr_node *btrn, size_t dest_size);
diff --git a/client.c b/client.c
index 2d6ef31f..873edc16 100644
--- a/client.c
+++ b/client.c
@@ -452,7 +452,7 @@ static int client_i9e_line_handler(char *line)
ret = client_connect(ct, &sched, NULL, NULL);
if (ret < 0)
return ret;
- i9e_attach_to_stdout(ct->btrn);
+ i9e_attach_to_stdout(ct->btrn[0]);
return 1;
}
@@ -528,26 +528,37 @@ __noreturn static void print_completions(void)
#endif /* HAVE_READLINE */
-static int supervisor_post_select(struct sched *s, __a_unused struct task *t)
+struct supervisor_task {
+ bool stdout_task_started;
+ struct task task;
+};
+
+static int supervisor_post_select(struct sched *s, struct task *t)
{
+ struct supervisor_task *svt = container_of(t, struct supervisor_task,
+ task);
+
if (ct->task.error < 0)
return ct->task.error;
+ if (!svt->stdout_task_started && ct->status == CL_EXECUTING) {
+ stdout_set_defaults(&sot);
+ register_task(s, &sot.task);
+ svt->stdout_task_started = true;
+ return 1;
+ }
if (ct->status == CL_SENDING) {
stdin_set_defaults(&sit);
register_task(s, &sit.task);
return -E_TASK_STARTED;
}
- if (ct->status == CL_RECEIVING) {
- stdout_set_defaults(&sot);
- register_task(s, &sot.task);
- return -E_TASK_STARTED;
- }
return 0;
}
-static struct task svt = {
- .post_select = supervisor_post_select,
- .status = "supervisor task"
+static struct supervisor_task supervisor_task = {
+ .task = {
+ .post_select = supervisor_post_select,
+ .status = "supervisor task"
+ }
};
/**
@@ -595,8 +606,8 @@ int main(int argc, char *argv[])
if (ret < 0)
goto out;
sot.btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = "stdout", .parent = ct->btrn));
- register_task(&sched, &svt);
+ EMBRACE(.name = "stdout", .parent = ct->btrn[0]));
+ register_task(&sched, &supervisor_task.task);
ret = schedule(&sched);
if (ret >= 0 && ct->task.error < 0) {
switch(ct->task.error) {
diff --git a/client.h b/client.h
index 92e14b15..6e438f7e 100644
--- a/client.h
+++ b/client.h
@@ -20,12 +20,10 @@ enum {
CL_SENT_CH_RESPONSE,
/** Server accepts this authentication. */
CL_RECEIVED_PROCEED,
- /** Client sends the command. */
- CL_SENT_COMMAND,
- /** Server expects data. */
+ /** Command is executing. */
+ CL_EXECUTING,
+ /** Server is expecting data (addblob commands only). */
CL_SENDING,
- /** Client expects data. */
- CL_RECEIVING,
};
/** Data specific to a client task. */
@@ -34,10 +32,10 @@ struct client_task {
int status;
/** The file descriptor and the session keys. */
struct stream_cipher_context scc;
- /** True if this connections uses the sideband API. */
- bool use_sideband;
- /** The sideband context, ignored if \a use_sideband is false. */
- struct sb_context *sbc;
+ /** The sideband contexts for receiving/sending. */
+ struct sb_context *sbc[2];
+ /** The buffer tree nodes for receiving/sending. */
+ struct btr_node *btrn[2];
/** The hash value of the decrypted challenge. */
unsigned char *challenge_hash;
/** The configuration (including the command). */
@@ -50,8 +48,6 @@ struct client_task {
char *user;
/** The client task structure. */
struct task task;
- /** The buffer tree node of the client task. */
- struct btr_node *btrn;
/** List of features supported by the server. */
char **features;
};
diff --git a/client_common.c b/client_common.c
index 1ecba730..c19b7121 100644
--- a/client_common.c
+++ b/client_common.c
@@ -49,7 +49,8 @@ void client_disconnect(struct client_task *ct)
ct->scc.recv = NULL;
sc_free(ct->scc.send);
ct->scc.send = NULL;
- btr_remove_node(&ct->btrn);
+ btr_remove_node(&ct->btrn[0]);
+ btr_remove_node(&ct->btrn[1]);
}
/**
@@ -69,7 +70,8 @@ void client_close(struct client_task *ct)
free(ct->key_file);
client_cmdline_parser_free(&ct->conf);
free(ct->challenge_hash);
- sb_free(ct->sbc);
+ sb_free(ct->sbc[0]);
+ sb_free(ct->sbc[1]);
free(ct);
}
@@ -91,7 +93,6 @@ static void client_pre_select(struct sched *s, struct task *t)
{
int ret;
struct client_task *ct = container_of(t, struct client_task, task);
- struct btr_node *btrn = ct->btrn;
if (ct->scc.fd < 0)
return;
@@ -99,7 +100,6 @@ static void client_pre_select(struct sched *s, struct task *t)
case CL_CONNECTED:
case CL_SENT_AUTH:
case CL_SENT_CH_RESPONSE:
- case CL_SENT_COMMAND:
para_fd_set(ct->scc.fd, &s->rfds, &s->max_fileno);
return;
@@ -109,76 +109,49 @@ static void client_pre_select(struct sched *s, struct task *t)
para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
return;
- case CL_RECEIVING:
- ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
- if (ret != 0) {
+ case CL_SENDING:
+ if (ct->btrn[1]) {
+ ret = btr_node_status(ct->btrn[1], 0, BTR_NT_LEAF);
if (ret < 0)
sched_min_delay(s);
- else
- para_fd_set(ct->scc.fd, &s->rfds,
- &s->max_fileno);
+ else if (ret > 0)
+ para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
}
- return;
- case CL_SENDING:
- ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
- if (ret != 0) {
+ /* fall though */
+ case CL_EXECUTING:
+ if (ct->btrn[0]) {
+ ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
if (ret < 0)
sched_min_delay(s);
- else
- para_fd_set(ct->scc.fd, &s->wfds,
- &s->max_fileno);
+ else if (ret > 0)
+ para_fd_set(ct->scc.fd, &s->rfds, &s->max_fileno);
}
return;
}
}
-static int client_recv_buffer(struct client_task *ct, fd_set *rfds,
- char *buf, size_t sz, size_t *n)
-{
- int ret;
-
- if (ct->status < CL_SENT_CH_RESPONSE)
- return read_nonblock(ct->scc.fd, buf, sz, rfds, n);
-
- *n = 0;
- ret = sc_recv_buffer(&ct->scc, buf, sz);
- /*
- * sc_recv_buffer is used with blocking fds elsewhere, so it
- * does not use the nonblock-API. Therefore we need to
- * check for EOF and EAGAIN.
- */
- if (ret == 0)
- return -E_SERVER_EOF;
- if (ret == -ERRNO_TO_PARA_ERROR(EAGAIN))
- return 0;
- if (ret < 0)
- return ret;
- *n = ret;
- return 0;
-}
-
-static int send_sb(struct client_task *ct, void *buf, size_t numbytes,
+static int send_sb(struct client_task *ct, int channel, void *buf, size_t numbytes,
enum sb_designator band, bool dont_free)
{
int ret, fd = ct->scc.fd;
struct iovec iov[2];
- if (!ct->sbc) {
+ if (!ct->sbc[channel]) {
struct sb_buffer sbb;
sb_transformation trafo = ct->status < CL_RECEIVED_PROCEED?
NULL : sc_trafo;
sbb = (typeof(sbb))SBB_INIT(band, buf, numbytes);
- ct->sbc = sb_new_send(&sbb, dont_free, trafo, ct->scc.send);
+ ct->sbc[channel] = sb_new_send(&sbb, dont_free, trafo, ct->scc.send);
}
- ret = sb_get_send_buffers(ct->sbc, iov);
+ ret = sb_get_send_buffers(ct->sbc[channel], iov);
ret = xwritev(fd, iov, ret);
if (ret < 0) {
- sb_free(ct->sbc);
- ct->sbc = NULL;
+ sb_free(ct->sbc[channel]);
+ ct->sbc[channel] = NULL;
return ret;
}
- if (sb_sent(ct->sbc, ret)) {
- ct->sbc = NULL;
+ if (sb_sent(ct->sbc[channel], ret)) {
+ ct->sbc[channel] = NULL;
return 1;
}
return 0;
@@ -201,21 +174,21 @@ static int recv_sb(struct client_task *ct, fd_set *rfds,
trafo = sc_trafo;
trafo_context = ct->scc.recv;
}
- if (!ct->sbc)
- ct->sbc = sb_new_recv(0, trafo, trafo_context);
+ if (!ct->sbc[0])
+ ct->sbc[0] = sb_new_recv(0, trafo, trafo_context);
again:
- sb_get_recv_buffer(ct->sbc, &iov);
+ sb_get_recv_buffer(ct->sbc[0], &iov);
ret = read_nonblock(ct->scc.fd, iov.iov_base, iov.iov_len, rfds, &n);
if (ret < 0) {
- sb_free(ct->sbc);
- ct->sbc = NULL;
+ sb_free(ct->sbc[0]);
+ ct->sbc[0] = NULL;
return ret;
}
if (n == 0)
return 0;
- if (!sb_received(ct->sbc, n, result))
+ if (!sb_received(ct->sbc[0], n, result))
goto again;
- ct->sbc = NULL;
+ ct->sbc[0] = NULL;
return 1;
}
@@ -251,10 +224,14 @@ static int dispatch_sbb(struct client_task *ct, struct sb_buffer *sbb)
PARA_DEBUG_LOG("band: %s\n", designator[sbb->band]);
switch (sbb->band) {
+ case SBD_AWAITING_DATA:
+ ct->status = CL_SENDING;
+ ret = 1;
+ goto out;
case SBD_OUTPUT:
if (iov_valid(&sbb->iov))
btr_add_output(sbb->iov.iov_base, sbb->iov.iov_len,
- ct->btrn);
+ ct->btrn[0]);
ret = 1;
goto out;
case SBD_DEBUG_LOG:
@@ -299,8 +276,8 @@ static int send_sb_command(struct client_task *ct)
char *command, *p;
size_t len = 0;
- if (ct->sbc)
- return send_sb(ct, NULL, 0, 0, false);
+ if (ct->sbc[1])
+ return send_sb(ct, 0, NULL, 0, 0, false);
for (i = 0; i < ct->conf.inputs_num; i++)
len += strlen(ct->conf.inputs[i]) + 1;
@@ -310,7 +287,7 @@ static int send_sb_command(struct client_task *ct)
p += strlen(ct->conf.inputs[i]) + 1;
}
PARA_DEBUG_LOG("--> %s\n", command);
- return send_sb(ct, command, len, SBD_COMMAND, false);
+ return send_sb(ct, 0, command, len, SBD_COMMAND, false);
}
/**
@@ -329,7 +306,6 @@ static int send_sb_command(struct client_task *ct)
static int client_post_select(struct sched *s, struct task *t)
{
struct client_task *ct = container_of(t, struct client_task, task);
- struct btr_node *btrn = ct->btrn;
int ret = 0;
size_t n;
char buf[CLIENT_BUFSIZE];
@@ -341,20 +317,21 @@ static int client_post_select(struct sched *s, struct task *t)
return 0;
switch (ct->status) {
case CL_CONNECTED: /* receive welcome message */
- ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
+ ret = read_nonblock(ct->scc.fd, buf, sizeof(buf), &s->rfds, &n);
if (ret < 0 || n == 0)
goto out;
ct->features = parse_features(buf);
+ if (!has_feature("sideband", ct)) {
+ PARA_ERROR_LOG("server has no sideband support\n");
+ ret = -E_INCOMPAT_FEAT;
+ goto out;
+ }
ct->status = CL_RECEIVED_WELCOME;
return 0;
case CL_RECEIVED_WELCOME: /* send auth command */
if (!FD_ISSET(ct->scc.fd, &s->wfds))
return 0;
- if (has_feature("sideband", ct)) {
- ct->use_sideband = true;
- sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
- } else
- sprintf(buf, AUTH_REQUEST_MSG "%s", ct->user);
+ sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
PARA_INFO_LOG("--> %s\n", buf);
ret = write_buffer(ct->scc.fd, buf);
if (ret < 0)
@@ -369,35 +346,23 @@ static int client_post_select(struct sched *s, struct task *t)
{
/* decrypted challenge/session key buffer */
unsigned char crypt_buf[1024];
- /* the SHA1 of the decrypted challenge */
+ struct sb_buffer sbb;
- if (ct->use_sideband) {
- struct sb_buffer sbb;
- ret = recv_sb(ct, &s->rfds, &sbb);
- if (ret <= 0)
- goto out;
- if (sbb.band != SBD_CHALLENGE) {
- ret = -E_BAD_BAND;
- free(sbb.iov.iov_base);
- goto out;
- }
- n = sbb.iov.iov_len;
- PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
- ret = priv_decrypt(ct->key_file, crypt_buf,
- sbb.iov.iov_base, n);
+ ret = recv_sb(ct, &s->rfds, &sbb);
+ if (ret <= 0)
+ goto out;
+ if (sbb.band != SBD_CHALLENGE) {
+ ret = -E_BAD_BAND;
free(sbb.iov.iov_base);
- if (ret < 0)
- goto out;
- } else {
- ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
- if (ret < 0 || n == 0)
- goto out;
- PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
- ret = priv_decrypt(ct->key_file, crypt_buf,
- (unsigned char *)buf, n);
- if (ret < 0)
goto out;
}
+ n = sbb.iov.iov_len;
+ PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
+ ret = priv_decrypt(ct->key_file, crypt_buf,
+ sbb.iov.iov_base, n);
+ free(sbb.iov.iov_base);
+ if (ret < 0)
+ goto out;
ct->challenge_hash = para_malloc(HASH_SIZE);
hash_function((char *)crypt_buf, CHALLENGE_SIZE, ct->challenge_hash);
ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
@@ -409,162 +374,100 @@ static int client_post_select(struct sched *s, struct task *t)
return 0;
}
case CL_RECEIVED_CHALLENGE:
- if (ct->use_sideband) {
- ret = send_sb(ct, ct->challenge_hash, HASH_SIZE,
- SBD_CHALLENGE_RESPONSE, false);
- if (ret != 0)
- ct->challenge_hash = NULL;
- if (ret <= 0)
- goto out;
- } else {
- ret = write_all(ct->scc.fd, (char *)ct->challenge_hash, HASH_SIZE);
- if (ret < 0)
- goto out;
- }
+ ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
+ SBD_CHALLENGE_RESPONSE, false);
+ if (ret != 0)
+ ct->challenge_hash = NULL;
+ if (ret <= 0)
+ goto out;
ct->status = CL_SENT_CH_RESPONSE;
goto out;
case CL_SENT_CH_RESPONSE: /* read server response */
{
- if (ct->use_sideband) {
- struct sb_buffer sbb;
- ret = recv_sb(ct, &s->rfds, &sbb);
- if (ret <= 0)
- goto out;
- free(sbb.iov.iov_base);
- if (sbb.band != SBD_PROCEED)
- ret = -E_BAD_BAND;
- else
- ct->status = CL_RECEIVED_PROCEED;
- goto out;
- }
- ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
- if (ret < 0 || n == 0)
- goto out;
- /* check if server has sent "Proceed" message */
- ret = -E_CLIENT_AUTH;
- if (n < PROCEED_MSG_LEN)
- goto out;
- if (!strstr(buf, PROCEED_MSG))
+ struct sb_buffer sbb;
+ ret = recv_sb(ct, &s->rfds, &sbb);
+ if (ret <= 0)
goto out;
- ct->status = CL_RECEIVED_PROCEED;
- return 0;
+ free(sbb.iov.iov_base);
+ if (sbb.band != SBD_PROCEED)
+ ret = -E_BAD_BAND;
+ else
+ ct->status = CL_RECEIVED_PROCEED;
+ goto out;
}
case CL_RECEIVED_PROCEED: /* concat args and send command */
{
- int i;
- char *command = NULL;
if (!FD_ISSET(ct->scc.fd, &s->wfds))
return 0;
- if (ct->use_sideband) {
- ret = send_sb_command(ct);
- if (ret <= 0)
- goto out;
- ct->status = CL_SENT_COMMAND;
- return 0;
- }
- for (i = 0; i < ct->conf.inputs_num; i++) {
- char *tmp = command;
- command = make_message("%s\n%s", command?
- command : "", ct->conf.inputs[i]);
- free(tmp);
- }
- command = para_strcat(command, EOC_MSG "\n");
- PARA_DEBUG_LOG("--> %s\n", command);
- ret = sc_send_buffer(&ct->scc, command);
- free(command);
- if (ret < 0)
+ ret = send_sb_command(ct);
+ if (ret <= 0)
goto out;
- ct->status = CL_SENT_COMMAND;
+ ct->status = CL_EXECUTING;
return 0;
}
- case CL_SENT_COMMAND:
- {
- char *buf2;
- if (ct->use_sideband) {
- struct sb_buffer sbb;
- ret = recv_sb(ct, &s->rfds, &sbb);
- if (ret <= 0)
- goto out;
- if (sbb.band == SBD_AWAITING_DATA) {
- ct->status = CL_SENDING;
- free(sbb.iov.iov_base);
- goto out;
+ case CL_SENDING:
+ if (ct->btrn[1]) {
+ char *buf2;
+ size_t sz;
+ ret = btr_node_status(ct->btrn[1], 0, BTR_NT_LEAF);
+ if (ret == -E_BTR_EOF) {
+ /* empty blob data packet indicates EOF */
+ PARA_INFO_LOG("blob sent\n");
+ ret = send_sb(ct, 1, NULL, 0, SBD_BLOB_DATA, true);
+ if (ret >= 0)
+ ret = -E_BTR_EOF;
}
- ct->status = CL_RECEIVING;
- ret = dispatch_sbb(ct, &sbb);
- goto out;
- }
- /* can not use "buf" here because we need a malloced buffer */
- buf2 = para_malloc(CLIENT_BUFSIZE);
- ret = client_recv_buffer(ct, &s->rfds, buf2, CLIENT_BUFSIZE, &n);
- if (n > 0) {
- if (strstr(buf2, AWAITING_DATA_MSG)) {
- free(buf2);
- ct->status = CL_SENDING;
- return 0;
+ if (ret < 0)
+ goto close1;
+ if (ret > 0 && FD_ISSET(ct->scc.fd, &s->wfds)) {
+ sz = btr_next_buffer(ct->btrn[1], &buf2);
+ assert(sz);
+ ret = send_sb(ct, 1, buf2, sz, SBD_BLOB_DATA, true);
+ if (ret < 0)
+ goto close1;
+ if (ret > 0)
+ btr_consume(ct->btrn[1], sz);
}
- ct->status = CL_RECEIVING;
- btr_add_output(buf2, n, btrn);
- } else
- free(buf2);
- goto out;
}
- case CL_SENDING:
- {
- char *buf2;
- size_t sz;
- ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
- if (ret < 0)
- goto out;
- if (ret == 0)
- return 0;
- if (!FD_ISSET(ct->scc.fd, &s->wfds))
- return 0;
- sz = btr_next_buffer(btrn, &buf2);
- ret = sc_send_bin_buffer(&ct->scc, buf2, sz);
- if (ret < 0)
- goto out;
- btr_consume(btrn, sz);
- return 0;
- }
- case CL_RECEIVING:
- {
- char *buf2;
- ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
- if (ret < 0)
- goto out;
- if (ret == 0)
- return 0;
- /*
- * The FD_ISSET() is not strictly necessary, but is allows us
- * to skip the malloc below if there is nothing to read anyway.
- */
- if (!FD_ISSET(ct->scc.fd, &s->rfds))
- return 0;
- if (ct->use_sideband) {
- struct sb_buffer sbb;
- ret = recv_sb(ct, &s->rfds, &sbb);
- if (ret > 0)
- ret = dispatch_sbb(ct, &sbb);
- goto out;
+ /* fall though */
+ case CL_EXECUTING:
+ if (ct->btrn[0]) {
+ ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
+ if (ret < 0)
+ goto close0;
+ if (ret > 0 && FD_ISSET(ct->scc.fd, &s->rfds)) {
+ struct sb_buffer sbb;
+ ret = recv_sb(ct, &s->rfds, &sbb);
+ if (ret < 0)
+ goto close0;
+ if (ret > 0) {
+ ret = dispatch_sbb(ct, &sbb);
+ if (ret < 0)
+ goto close0;
+ }
+ }
}
- buf2 = para_malloc(CLIENT_BUFSIZE);
- ret = client_recv_buffer(ct, &s->rfds, buf2, CLIENT_BUFSIZE, &n);
- if (n > 0) {
- buf2 = para_realloc(buf2, n);
- btr_add_output(buf2, n, btrn);
- } else
- free(buf2);
+ ret = 0;
goto out;
- }
}
+close1:
+ PARA_INFO_LOG("channel 1: %s\n", para_strerror(-ret));
+ btr_remove_node(&ct->btrn[1]);
+ if (ct->btrn[0])
+ return 0;
+ goto out;
+close0:
+ PARA_INFO_LOG("channel 0: %s\n", para_strerror(-ret));
+ btr_remove_node(&ct->btrn[0]);
+ if (ct->btrn[1] && ct->status == CL_SENDING)
+ return 0;
out:
- if (ret < 0) {
- if (!ct->use_sideband && ret != -E_SERVER_EOF &&
- ret != -E_BTR_EOF && ret != -E_EOF)
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
- btr_remove_node(&ct->btrn);
- }
+ if (ret >= 0)
+ return 0;
+ btr_remove_node(&ct->btrn[0]);
+ btr_remove_node(&ct->btrn[1]);
+ if (ret != -E_SERVER_CMD_SUCCESS && ret != -E_SERVER_CMD_FAILURE)
+ PARA_ERROR_LOG("%s\n", para_strerror(-ret));
return ret;
}
@@ -598,8 +501,10 @@ int client_connect(struct client_task *ct, struct sched *s,
if (ret < 0)
goto err_out;
ct->status = CL_CONNECTED;
- ct->btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = "client", .parent = parent, .child = child));
+ ct->btrn[0] = btr_new_node(&(struct btr_node_description)
+ EMBRACE(.name = "client recv", .parent = NULL, .child = child));
+ ct->btrn[1] = btr_new_node(&(struct btr_node_description)
+ EMBRACE(.name = "client send", .parent = parent, .child = NULL));
ct->task.pre_select = client_pre_select;
ct->task.post_select = client_post_select;
ct->task.error = 0;
diff --git a/command.c b/command.c
index 41a58eac..3d40023f 100644
--- a/command.c
+++ b/command.c
@@ -35,8 +35,8 @@
#include "signal.h"
#include "version.h"
-struct server_command afs_cmds[] = {DEFINE_AFS_CMD_ARRAY};
-struct server_command server_cmds[] = {DEFINE_SERVER_CMD_ARRAY};
+static struct server_command afs_cmds[] = {DEFINE_AFS_CMD_ARRAY};
+static struct server_command server_cmds[] = {DEFINE_SERVER_CMD_ARRAY};
/** Commands including options must be shorter than this. */
#define MAX_COMMAND_LEN 32768
@@ -220,8 +220,8 @@ int send_sb(struct stream_cipher_context *scc, void *buf, size_t numbytes,
int ret;
struct sb_context *sbc;
struct iovec iov[2];
- struct sb_buffer sbb = SBB_INIT(band, buf, numbytes);
sb_transformation trafo = band < SBD_PROCEED? NULL : sc_trafo;
+ struct sb_buffer sbb = SBB_INIT(band, buf, numbytes);
sbc = sb_new_send(&sbb, dont_free, trafo, scc->send);
do {
@@ -268,10 +268,7 @@ __printf_3_4 int send_sb_va(struct stream_cipher_context *scc, int band,
*/
int send_strerror(struct command_context *cc, int err)
{
- return cc->use_sideband?
- send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s\n", para_strerror(err))
- :
- sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(err));
+ return send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s\n", para_strerror(err));
}
/**
@@ -338,23 +335,14 @@ static int com_sender(struct command_context *cc)
free(msg);
msg = tmp;
}
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
- ret = sc_send_buffer(&cc->scc, msg);
- free(msg);
- return ret;
+ return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
}
ret = check_sender_args(cc->argc, cc->argv, &scd);
if (ret < 0) {
if (scd.sender_num < 0)
return ret;
msg = senders[scd.sender_num].help();
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT,
- false);
- ret = sc_send_buffer(&cc->scc, msg);
- free(msg);
- return ret;
+ return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
}
switch (scd.cmd_num) {
@@ -418,11 +406,7 @@ static int com_si(struct command_context *cc)
mutex_unlock(mmd_mutex);
free(ut);
free(sender_info);
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
- ret = sc_send_bin_buffer(&cc->scc, msg, ret);
- free(msg);
- return ret;
+ return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
}
/* version */
@@ -434,9 +418,7 @@ static int com_version(struct command_context *cc)
if (cc->argc != 1)
return -E_COMMAND_SYNTAX;
len = xasprintf(&msg, "%s", version_text("server"));
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, len, SBD_OUTPUT, false);
- return sc_send_bin_buffer(&cc->scc, msg, len);
+ return send_sb(&cc->scc, msg, len, SBD_OUTPUT, false);
}
#define EMPTY_STATUS_ITEMS \
@@ -536,24 +518,13 @@ static int com_stat(struct command_context *cc)
for (;;) {
mmd_dup(nmmd);
ret = get_status(nmmd, parser_friendly, &s);
- if (cc->use_sideband)
- ret = send_sb(&cc->scc, s, ret, SBD_OUTPUT, false);
- else {
- ret = sc_send_bin_buffer(&cc->scc, s, ret);
- free(s);
- }
+ ret = send_sb(&cc->scc, s, ret, SBD_OUTPUT, false);
if (ret < 0)
goto out;
if (nmmd->vss_status_flags & VSS_NEXT) {
char *esi;
ret = empty_status_items(parser_friendly, &esi);
- if (cc->use_sideband)
- ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT,
- false);
- else {
- ret = sc_send_bin_buffer(&cc->scc, esi, ret);
- free(esi);
- }
+ ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT, false);
if (ret < 0)
goto out;
} else
@@ -573,7 +544,6 @@ out:
static int send_list_of_commands(struct command_context *cc, struct server_command *cmd,
const char *handler)
{
- int ret;
char *msg = NULL;
for (; cmd->name; cmd++) {
@@ -584,11 +554,7 @@ static int send_list_of_commands(struct command_context *cc, struct server_comma
msg = para_strcat(msg, tmp);
free(tmp);
}
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
- ret = sc_send_buffer(&cc->scc, msg);
- free(msg);
- return ret;
+ return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
}
/* returns string that must be freed by the caller */
@@ -644,11 +610,7 @@ static int com_help(struct command_context *cc)
);
free(perms);
free(handler);
- if (cc->use_sideband)
- return send_sb(&cc->scc, buf, ret, SBD_OUTPUT, false);
- ret = sc_send_buffer(&cc->scc, buf);
- free(buf);
- return ret;
+ return send_sb(&cc->scc, buf, ret, SBD_OUTPUT, false);
}
/* hup */
@@ -810,58 +772,6 @@ static int check_perms(unsigned int perms, struct server_command *cmd_ptr)
return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
}
-/*
- * Parse first string from *cmd and lookup in table of valid commands.
- * On error, NULL is returned.
- */
-static struct server_command *parse_cmd(const char *cmdstr)
-{
- char buf[255];
- int n = 0;
-
- sscanf(cmdstr, "%200s%n", buf, &n);
- if (!n)
- return NULL;
- buf[n] = '\0';
- return get_cmd_ptr(buf, NULL);
-}
-
-static int read_command(struct stream_cipher_context *scc, char **result)
-{
- int ret;
- char buf[4096];
- char *command = NULL;
-
- for (;;) {
- size_t numbytes;
- char *p;
-
- ret = sc_recv_buffer(scc, buf, sizeof(buf));
- if (ret < 0)
- goto out;
- if (!ret)
- break;
- numbytes = ret;
- ret = -E_COMMAND_SYNTAX;
- if (command && numbytes + strlen(command) > MAX_COMMAND_LEN) /* DOS */
- goto out;
- command = para_strcat(command, buf);
- p = strstr(command, EOC_MSG);
- if (p) {
- *p = '\0';
- break;
- }
- }
- ret = command? 1 : -E_COMMAND_SYNTAX;
-out:
- if (ret < 0)
- free(command);
- else
- *result = command;
- return ret;
-
-}
-
static void reset_signals(void)
{
para_sigaction(SIGCHLD, SIG_IGN);
@@ -870,15 +780,14 @@ static void reset_signals(void)
para_sigaction(SIGHUP, SIG_DFL);
}
-static int parse_auth_request(char *buf, int len, struct user **u,
- bool *use_sideband)
+static int parse_auth_request(char *buf, int len, struct user **u)
{
int ret;
char *p, *username, **features = NULL;
size_t auth_rq_len = strlen(AUTH_REQUEST_MSG);
+ bool sideband_requested = false;
*u = NULL;
- *use_sideband = false;
if (len < auth_rq_len + 2)
return -E_AUTH_REQUEST;
if (strncmp(buf, AUTH_REQUEST_MSG, auth_rq_len) != 0)
@@ -894,15 +803,19 @@ static int parse_auth_request(char *buf, int len, struct user **u,
create_argv(p, ",", &features);
for (i = 0; features[i]; i++) {
if (strcmp(features[i], "sideband") == 0)
- *use_sideband = true;
+ sideband_requested = true;
else {
ret = -E_BAD_FEATURE;
goto out;
}
}
}
- PARA_DEBUG_LOG("received auth request for user %s (sideband = %s)\n",
- username, *use_sideband? "true" : "false");
+ if (sideband_requested == false) { /* sideband is mandatory */
+ PARA_ERROR_LOG("client did not request sideband\n");
+ ret = -E_BAD_FEATURE;
+ goto out;
+ }
+ PARA_DEBUG_LOG("received auth request for user %s\n", username);
*u = lookup_user(username);
ret = 1;
out:
@@ -929,7 +842,7 @@ static int parse_sb_command(struct command_context *cc, struct iovec *iov)
if (ret < 0)
goto out;
end = iov->iov_base + iov->iov_len;
- for (i = 0, p = iov->iov_base; p < end; i++)
+ for (i = 0; p < end; i++)
p += strlen(p) + 1;
cc->argc = i;
cc->argv = para_malloc((cc->argc + 1) * sizeof(char *));
@@ -979,6 +892,7 @@ __noreturn void handle_connect(int fd, const char *peername)
char *p, *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
size_t numbytes;
struct command_context cc_struct = {.peer = peername}, *cc = &cc_struct;
+ struct iovec iov;
cc->scc.fd = fd;
reset_signals();
@@ -997,7 +911,7 @@ __noreturn void handle_connect(int fd, const char *peername)
ret = recv_buffer(fd, buf, HANDSHAKE_BUFSIZE);
if (ret < 0)
goto net_err;
- ret = parse_auth_request(buf, ret, &cc->u, &cc->use_sideband);
+ ret = parse_auth_request(buf, ret, &cc->u);
if (ret < 0)
goto net_err;
p = buf + strlen(AUTH_REQUEST_MSG);
@@ -1021,28 +935,16 @@ __noreturn void handle_connect(int fd, const char *peername)
}
PARA_DEBUG_LOG("sending %u byte challenge + rc4 keys (%zu bytes)\n",
CHALLENGE_SIZE, numbytes);
- if (cc->use_sideband) {
- struct iovec iov;
- ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
- buf = NULL;
- if (ret < 0)
- goto net_err;
- ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE,
- HANDSHAKE_BUFSIZE, &iov);
- if (ret < 0)
- goto net_err;
- buf = iov.iov_base;
- numbytes = iov.iov_len;
- } else {
- ret = write_all(fd, buf, numbytes);
- if (ret < 0)
- goto net_err;
- /* recv challenge response */
- ret = recv_bin_buffer(fd, buf, HASH_SIZE);
- if (ret < 0)
- goto net_err;
- numbytes = ret;
- }
+ ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
+ buf = NULL;
+ if (ret < 0)
+ goto net_err;
+ ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE,
+ HANDSHAKE_BUFSIZE, &iov);
+ if (ret < 0)
+ goto net_err;
+ buf = iov.iov_base;
+ numbytes = iov.iov_len;
PARA_DEBUG_LOG("received %zu bytes challenge response\n", numbytes);
ret = -E_BAD_USER;
if (!cc->u)
@@ -1063,41 +965,16 @@ __noreturn void handle_connect(int fd, const char *peername)
/* init stream cipher keys with the second part of the random buffer */
cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
cc->scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN);
- if (cc->use_sideband)
- ret = send_sb(&cc->scc, NULL, 0, SBD_PROCEED, false);
- else
- ret = sc_send_buffer(&cc->scc, PROCEED_MSG);
+ ret = send_sb(&cc->scc, NULL, 0, SBD_PROCEED, false);
if (ret < 0)
goto net_err;
- if (cc->use_sideband) {
- struct iovec iov;
- ret = recv_sb(&cc->scc, SBD_COMMAND, MAX_COMMAND_LEN, &iov);
- if (ret < 0)
- goto net_err;
- ret = parse_sb_command(cc, &iov);
- if (ret < 0)
- goto err_out;
- cc->argc = ret;
- } else {
- ret = read_command(&cc->scc, &command);
- if (ret == -E_COMMAND_SYNTAX)
- goto err_out;
- if (ret < 0)
- goto net_err;
- ret = -E_BAD_CMD;
- cc->cmd = parse_cmd(command);
- if (!cc->cmd)
- goto err_out;
- /* valid command, check permissions */
- ret = check_perms(cc->u->perms, cc->cmd);
- if (ret < 0)
- goto err_out;
- /* valid command and sufficient perms */
- ret = create_argv(command, "\n", &cc->argv);
- if (ret < 0)
- goto err_out;
- cc->argc = ret;
- }
+ ret = recv_sb(&cc->scc, SBD_COMMAND, MAX_COMMAND_LEN, &iov);
+ if (ret < 0)
+ goto net_err;
+ ret = parse_sb_command(cc, &iov);
+ if (ret < 0)
+ goto err_out;
+ cc->argc = ret;
PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cc->cmd->name,
cc->u->name, peername);
ret = cc->cmd->handler(cc);
@@ -1108,7 +985,7 @@ __noreturn void handle_connect(int fd, const char *peername)
if (ret >= 0)
goto out;
err_out:
- if (send_strerror(cc, -ret) >= 0 && cc->use_sideband)
+ if (send_strerror(cc, -ret) >= 0)
send_sb(&cc->scc, NULL, 0, SBD_EXIT__FAILURE, true);
net_err:
PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
@@ -1120,7 +997,7 @@ out:
mmd->events++;
mmd->active_connections--;
mutex_unlock(mmd_mutex);
- if (ret >= 0 && cc->use_sideband) {
+ if (ret >= 0) {
ret = send_sb(&cc->scc, NULL, 0, SBD_EXIT__SUCCESS, true);
if (ret < 0)
PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
diff --git a/command.h b/command.h
index e4159e6b..6d220207 100644
--- a/command.h
+++ b/command.h
@@ -14,8 +14,6 @@ struct command_context {
struct server_command *cmd;
/** File descriptor and crypto keys. */
struct stream_cipher_context scc;
- /** Whether to use the sideband API for this command. */
- bool use_sideband;
};
/**
diff --git a/configure.ac b/configure.ac
index 55b38e54..85d30886 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,13 +3,11 @@
AC_PREREQ([2.61])
-
AC_INIT([paraslash],[git],[maan@systemlinux.org])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile])
AC_DEFUN([add_dot_o],[$(for i in $@; do printf "$i.o "; done)])
-AC_DEFUN([add_para],[$(for i in $@; do printf "para_$i "; done)])
AC_DEFUN([objlist_to_errlist],[$(for i in $@; do printf "DEFINE_ERRLIST($(echo $i| tr 'a-z' 'A-Z'));"; done) [const char **para_errlist[[]]] = {$(for i in $@; do printf "PARA_ERRLIST($(echo $i | tr 'a-z' 'A-Z')), "; done) }])
AC_PATH_PROG(UNAMEPATH, uname, no)
if test "$UNAMEPATH" = "no"; then
@@ -1325,7 +1323,7 @@ AC_DEFINE_UNQUOTED(STATUS_ITEM_ARRAY, [$result],
AC_DEFINE_UNQUOTED(AUDIO_FORMAT_HANDLERS, "$audio_format_handlers",
[formats supported by para_server and para_afh])
-AC_SUBST(executables, add_para($executables))
+AC_SUBST(executables)
recv_objs="$recv_cmdline_objs $recv_errlist_objs"
filter_objs="$filter_cmdline_objs $filter_errlist_objs"
diff --git a/crypt.c b/crypt.c
index 5c5333a9..5445138d 100644
--- a/crypt.c
+++ b/crypt.c
@@ -147,8 +147,7 @@ static int read_rsa_bignums(const unsigned char *blob, int blen, RSA **result)
*result = rsa;
return 1;
fail:
- if (rsa)
- RSA_free(rsa);
+ RSA_free(rsa);
return ret;
}
@@ -283,40 +282,6 @@ void sc_free(struct stream_cipher *sc)
*/
#define RC4_ALIGN 8
-int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t len)
-{
- int ret;
- unsigned char *tmp;
- static unsigned char remainder[RC4_ALIGN];
- size_t l1 = ROUND_DOWN(len, RC4_ALIGN), l2 = ROUND_UP(len, RC4_ALIGN);
-
- assert(len);
- tmp = para_malloc(l2);
- RC4(&scc->send->key, l1, (const unsigned char *)buf, tmp);
- if (len > l1) {
- memcpy(remainder, buf + l1, len - l1);
- RC4(&scc->send->key, len - l1, remainder, tmp + l1);
- }
- ret = xwrite(scc->fd, (char *)tmp, len);
- free(tmp);
- return ret;
-}
-
-int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t size)
-{
- unsigned char *tmp = para_malloc(ROUND_UP(size, RC4_ALIGN));
- ssize_t ret = recv(scc->fd, tmp, size, 0);
-
- if (ret > 0)
- RC4(&scc->recv->key, ret, tmp, (unsigned char *)buf);
- else if (ret < 0)
- ret = -ERRNO_TO_PARA_ERROR(errno);
- free(tmp);
- return ret;
-}
-
void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
{
size_t len = src->iov_len, l1, l2;
diff --git a/crypt.h b/crypt.h
index 77806af6..1406197d 100644
--- a/crypt.h
+++ b/crypt.h
@@ -165,75 +165,9 @@ _static_inline_ void sc_trafo(struct iovec *src, struct iovec *dst,
*/
void sc_free(struct stream_cipher *sc);
-/**
- * Encrypt and send a buffer.
- *
- * \param scc The context.
- * \param buf The buffer to send.
- * \param len The size of \a buf in bytes.
- *
- * \return The return value of the underyling call to write_all().
- *
- * \sa \ref write_all(), RC4(3).
- */
-int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t len);
-
-/**
- * Encrypt and send a \p NULL-terminated buffer.
- *
- * \param scc The context.
- * \param buf The buffer to send.
- *
- * \return The return value of the underyling call to sc_send_bin_buffer().
- */
-int sc_send_buffer(struct stream_cipher_context *scc, char *buf);
-
-/**
- * Format, encrypt and send a buffer.
- *
- * \param scc The context.
- * \param fmt A format string.
- *
- * \return The return value of the underyling call to sc_send_buffer().
- */
-__printf_2_3 int sc_send_va_buffer(struct stream_cipher_context *scc,
- const char *fmt, ...);
-
-/**
- * Receive a buffer and decrypt it.
- *
- * \param scc The context.
- * \param buf The buffer to write the decrypted data to.
- * \param size The size of \a buf.
- *
- * \return The number of bytes received on success, negative on errors, zero if
- * the peer has performed an orderly shutdown.
- *
- * \sa recv(2), RC4(3).
- */
-int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t size);
-
-/**
- * Receive a buffer, decrypt it and write terminating NULL byte.
- *
- * \param scc The context.
- * \param buf The buffer to write the decrypted data to.
- * \param size The size of \a buf.
- *
- * Read at most \a size - 1 bytes from file descriptor given by \a scc, decrypt
- * the received data and write a NULL byte at the end of the decrypted data.
- *
- * \return The return value of the underlying call to \ref
- * sc_recv_bin_buffer().
- */
-int sc_recv_buffer(struct stream_cipher_context *scc, char *buf, size_t size);
-
/** Size of the hash value in bytes. */
#define HASH_SIZE 20
-
/**
* Compute the hash of the given input data.
*
diff --git a/crypt_common.c b/crypt_common.c
index cd9500ab..6c71d7e3 100644
--- a/crypt_common.c
+++ b/crypt_common.c
@@ -321,41 +321,3 @@ int hash_compare(unsigned char *h1, unsigned char *h2)
}
return 0;
}
-
-int sc_recv_buffer(struct stream_cipher_context *scc, char *buf, size_t size)
-{
- int n;
-
- assert(size);
- n = sc_recv_bin_buffer(scc, buf, size - 1);
- if (n >= 0)
- buf[n] = '\0';
- else
- *buf = '\0';
- return n;
-}
-
-int sc_send_buffer(struct stream_cipher_context *scc, char *buf)
-{
- size_t len = strlen(buf);
- int ret = sc_send_bin_buffer(scc, buf, len);
-
- if (ret < 0 || ret == len)
- return ret;
- return -E_SHORT_WRITE;
-}
-
-__printf_2_3 int sc_send_va_buffer(struct stream_cipher_context *scc,
- const char *fmt, ...)
-{
- char *msg;
- int ret;
- va_list ap;
-
- va_start(ap, fmt);
- ret = xvasprintf(&msg, fmt, ap);
- va_end(ap);
- ret = sc_send_bin_buffer(scc, msg, ret);
- free(msg);
- return ret;
-}
diff --git a/error.h b/error.h
index ef54ef27..82df5ca9 100644
--- a/error.h
+++ b/error.h
@@ -301,6 +301,7 @@ extern const char **para_errlist[];
PARA_ERROR(SERVER_EOF, "connection closed by para_server"), \
PARA_ERROR(SERVER_CMD_SUCCESS, "command terminated successfully"), \
PARA_ERROR(SERVER_CMD_FAILURE, "command failed"), \
+ PARA_ERROR(INCOMPAT_FEAT, "client/server incompatibility"), \
#define NET_ERRORS \
@@ -337,6 +338,7 @@ extern const char **para_errlist[];
PARA_ERROR(UNSUPPORTED_AUDIO_FORMAT, "given audio format not supported"), \
PARA_ERROR(NOT_PLAYING, "not playing"), \
PARA_ERROR(AUDIOD_OFF, "audiod switched off"), \
+ PARA_ERROR(STATUS_TIMEOUT, "status item timeout"), \
#define AUDIOD_COMMAND_ERRORS \
@@ -464,7 +466,7 @@ extern const char **para_errlist[];
PARA_ERROR(SENDER_CMD, "command not supported by this sender"), \
PARA_ERROR(SERVER_CRASH, "para_server crashed -- can not live without it"), \
PARA_ERROR(BAD_USER, "auth request for invalid user"), \
- PARA_ERROR(BAD_FEATURE, "request for unknown or invalid feature"), \
+ PARA_ERROR(BAD_FEATURE, "invalid feature request"), \
PARA_ERROR(BAD_AUTH, "authentication failure"), \
@@ -607,7 +609,7 @@ _static_inline_ const char *para_strerror(int num)
*
* This should be used for all calls to osl functions that return an osl error
* code. It changes the return value appropriately so that it can be used for
- * printing the correct error message vi para_strerror().
+ * printing the correct error message with para_strerror().
*
* \return \a ret if \a ret >= 0, a paraslash error code otherwise.
*/
diff --git a/fade.c b/fade.c
index 878b83a1..a8424d67 100644
--- a/fade.c
+++ b/fade.c
@@ -27,7 +27,7 @@ static struct mixer supported_mixer[] = {MIXER_ARRAY};
#define FOR_EACH_MIXER(i) for ((i) = 0; (i) < NUM_SUPPORTED_MIXERS; (i)++)
static int loglevel;
-__printf_2_3 void date_log(int ll, const char *fmt, ...)
+static __printf_2_3 void date_log(int ll, const char *fmt, ...)
{
va_list argp;
time_t t1;
diff --git a/fd.c b/fd.c
index 3ab5cad0..4d4a859b 100644
--- a/fd.c
+++ b/fd.c
@@ -526,6 +526,7 @@ static int para_opendir(const char *dirname, DIR **dir, int *cwd)
{
int ret;
+ *dir = NULL;
if (cwd) {
ret = para_open(".", O_RDONLY, 0);
if (ret < 0)
diff --git a/gcrypt.c b/gcrypt.c
index b4718ec0..2736a6c7 100644
--- a/gcrypt.c
+++ b/gcrypt.c
@@ -937,39 +937,6 @@ void sc_free(struct stream_cipher *sc)
free(sc);
}
-int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t size)
-{
- gcry_error_t gret;
- int ret;
- unsigned char *tmp = para_malloc(size);
-
- assert(size);
- gret = gcry_cipher_encrypt(scc->send->handle, tmp, size,
- (unsigned char *)buf, size);
- assert(gret == 0);
- ret = xwrite(scc->fd, (char *)tmp, size);
- free(tmp);
- return ret;
-}
-
-int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t size)
-{
- gcry_error_t gret;
- ssize_t ret = recv(scc->fd, buf, size, 0);
-
- if (ret < 0)
- ret = -ERRNO_TO_PARA_ERROR(errno);
- if (ret <= 0)
- return ret;
- /* perform in-place encryption */
- gret = gcry_cipher_encrypt(scc->recv->handle, (unsigned char *)buf, ret,
- NULL, 0);
- assert(gret == 0);
- return ret;
-}
-
void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
{
gcry_cipher_hd_t handle = sc->handle;
diff --git a/gui.c b/gui.c
index baab0bd9..54fc9db9 100644
--- a/gui.c
+++ b/gui.c
@@ -526,7 +526,7 @@ static int add_output_line(char *line, void *data)
static int loglevel;
-__printf_2_3 void curses_log(int ll, const char *fmt,...)
+static __printf_2_3 void curses_log(int ll, const char *fmt,...)
{
int color;
char *msg;
diff --git a/ipc.c b/ipc.c
index 1ec53c30..89bbe535 100644
--- a/ipc.c
+++ b/ipc.c
@@ -209,6 +209,7 @@ size_t shm_get_shmmax(void)
buf[ret] = '\0';
shmmax = strtoul(buf, NULL, 10);
}
+ close(fd);
}
}
#elif defined SYSCTL_SHMMAX_VARIABLE
diff --git a/m4/gengetopt/afh.m4 b/m4/gengetopt/afh.m4
index f8e29fea..ebc1d1cf 100644
--- a/m4/gengetopt/afh.m4
+++ b/m4/gengetopt/afh.m4
@@ -6,7 +6,7 @@ include(header.m4)
include(loglevel.m4)
-option "chunk_table" c
+option "chunk-table" c
#~~~~~~~~~~~~~~~~~~~~~
"print also the chunk table"
flag off
@@ -27,7 +27,7 @@ option "parser-friendly" p
flag off
details = "
Currently this option only affects the format of the chunk table,
- so it has no effect if --chunk_table is not given.
+ so it has no effect if --chunk-table is not given.
The human-readable output (the default) consists of one output
line per chunk and the output contains also the chunk number,
diff --git a/m4/gengetopt/afh_recv.m4 b/m4/gengetopt/afh_recv.m4
index f4da9d99..6fdef59e 100644
--- a/m4/gengetopt/afh_recv.m4
+++ b/m4/gengetopt/afh_recv.m4
@@ -31,7 +31,7 @@ details = "
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
+ 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.
@@ -43,7 +43,7 @@ option "end-chunk" e
int typestr = "chunk_num"
optional
details = "
- For the chunk_num argument the same rules as for --begin_chunk
+ For the chunk_num argument the same rules as for --begin-chunk
apply. The default is to write up to the last chunk.
"
diff --git a/m4/gengetopt/audiod.m4 b/m4/gengetopt/audiod.m4
index 7bae3435..5fc15893 100644
--- a/m4/gengetopt/audiod.m4
+++ b/m4/gengetopt/audiod.m4
@@ -80,7 +80,7 @@ details="
instructed to use also \"filename\" for connecting para_audiod.
"
-option "user_allow" -
+option "user-allow" -
#~~~~~~~~~~~~~~~~~~~~
"allow this uid"
int typestr="uid"
@@ -98,7 +98,7 @@ details="
to connect to para_audiod.
"
-option "clock_diff_count" -
+option "clock-diff-count" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~
"sync clock on startup"
int typestr="count"
@@ -195,7 +195,7 @@ details="
"
-option "stream_delay" -
+option "stream-delay" -
#~~~~~~~~~~~~~~~~~~~~~~
"time for client sync"
int typestr="milliseconds"
diff --git a/m4/gengetopt/client.m4 b/m4/gengetopt/client.m4
index f0bbc0bd..5b4c8ec8 100644
--- a/m4/gengetopt/client.m4
+++ b/m4/gengetopt/client.m4
@@ -9,8 +9,8 @@ define(DEFAULT_HISTORY_FILE,~/.paraslash/client.history)
option "hostname" i "ip or host to connect" string typestr="host" default="localhost" optional
option "user" u "paraslash username" string typestr="username" default="" optional
-option "server_port" p "port to connect" int typestr="port" default="2990" optional
-option "key_file" k "(default='~/.paraslash/key.')" string typestr="filename" optional
+option "server-port" p "port to connect" int typestr="port" default="2990" optional
+option "key-file" k "(default='~/.paraslash/key.')" string typestr="filename" optional
include(loglevel.m4)
diff --git a/m4/gengetopt/color.m4 b/m4/gengetopt/color.m4
index 63e996f3..eb081786 100644
--- a/m4/gengetopt/color.m4
+++ b/m4/gengetopt/color.m4
@@ -8,7 +8,7 @@ values = "yes","no","auto"
default = "auto"
optional
-option "log_color" -
+option "log-color" -
#~~~~~~~~~~~~~~~~~~~
"select a color for one type of log message"
string typestr="color_spec"
@@ -26,9 +26,9 @@ details="
Examples:
- --log_color \"debug:green\"
- --log_color \"info:yellow bold\"
- --log_color \"notice:white red bold\"
+ --log-color \"debug:green\"
+ --log-color \"info:yellow bold\"
+ --log-color \"notice:white red bold\"
"
diff --git a/m4/gengetopt/compress_filter.m4 b/m4/gengetopt/compress_filter.m4
index 8c701a03..772bdb2e 100644
--- a/m4/gengetopt/compress_filter.m4
+++ b/m4/gengetopt/compress_filter.m4
@@ -26,7 +26,7 @@ option "inertia" i
default="6"
optional
-option "target_level" t
+option "target-level" t
#~~~~~~~~~~~~~~~~~~~~~~
"target signal level (0-32768)"
int typestr="number"
diff --git a/m4/gengetopt/config_file.m4 b/m4/gengetopt/config_file.m4
index 318ba7a6..29f66b44 100644
--- a/m4/gengetopt/config_file.m4
+++ b/m4/gengetopt/config_file.m4
@@ -1,5 +1,5 @@
-option "config_file" c
+option "config-file" c
#~~~~~~~~~~~~~~~~~~~~~
"(default='DEFAULT_CONFIG_FILE')"
string typestr="filename"
diff --git a/m4/gengetopt/gui.m4 b/m4/gengetopt/gui.m4
index 1f5cf6e4..5b44efa6 100644
--- a/m4/gengetopt/gui.m4
+++ b/m4/gengetopt/gui.m4
@@ -34,7 +34,7 @@ details = "
available themes is printed and the program terminates.
"
-option "stat_cmd" s
+option "stat-cmd" s
#~~~~~~~~~~~~~~~~~~
"command to read status items from"
string typestr = "command"
@@ -56,7 +56,7 @@ details = "
section "Mapping keys to commands"
#---------------------------------
-option "key_map" k
+option "key-map" k
#~~~~~~~~~~~~~~~~~
"Map key k to command c using mode m."
diff --git a/m4/gengetopt/history_file.m4 b/m4/gengetopt/history_file.m4
index 932d88bf..73e98a78 100644
--- a/m4/gengetopt/history_file.m4
+++ b/m4/gengetopt/history_file.m4
@@ -1,5 +1,5 @@
-option "history_file" -
+option "history-file" -
#~~~~~~~~~~~~~~~~~~~~~~
"(default='DEFAULT_HISTORY_FILE')"
string typestr = "filename"
diff --git a/m4/gengetopt/makefile b/m4/gengetopt/makefile
index 548a3d5d..79e101a3 100644
--- a/m4/gengetopt/makefile
+++ b/m4/gengetopt/makefile
@@ -1,6 +1,6 @@
define ggo_opts
--output-dir=$(cmdline_dir) \
- --set-version="$(GIT_VERSION) ($(codename))" \
+ --set-version="$(GIT_VERSION)" \
--arg-struct-name=$(*F)_args_info \
--file-name=$(*F).cmdline \
--func-name=$(*F)_cmdline_parser \
@@ -16,37 +16,11 @@ ifeq ($(ggo_descriptions_declared),no)
echo 'extern const char *$(*F)_args_info_description;' >> $(cmdline_dir)/$(*F).cmdline.h
endif
-$(ggo_dir)/server.ggo $(ggo_dir)/audiod.ggo: \
- $(m4_ggo_dir)/loglevel.m4 $(m4_ggo_dir)/color.m4 \
- $(m4_ggo_dir)/config_file.m4 $(m4_ggo_dir)/logfile.m4 \
- $(m4_ggo_dir)/daemon.m4 $(m4_ggo_dir)/user.m4 \
- $(m4_ggo_dir)/group.m4 $(m4_ggo_dir)/log_timing.m4 \
- $(m4_ggo_dir)/config_file.m4
-
-$(ggo_dir)/afh.ggo: $(m4_ggo_dir)/loglevel.m4
-$(ggo_dir)/audioc.ggo: \
- $(m4_ggo_dir)/loglevel.m4 \
- $(m4_ggo_dir)/history_file.m4 \
- $(m4_ggo_dir)/complete.m4
-$(ggo_dir)/filter.ggo: $(m4_ggo_dir)/loglevel.m4
-$(ggo_dir)/fsck.ggo: $(m4_ggo_dir)/loglevel.m4
-$(ggo_dir)/gui.ggo: $(m4_ggo_dir)/loglevel.m4 $(m4_ggo_dir)/config_file.m4
-$(ggo_dir)/recv.ggo: $(m4_ggo_dir)/loglevel.m4
-$(ggo_dir)/write.ggo: $(m4_ggo_dir)/loglevel.m4 \
- $(m4_ggo_dir)/channels.m4 \
- $(m4_ggo_dir)/sample_rate.m4 \
- $(m4_ggo_dir)/sample_format.m4
-$(ggo_dir)/client.ggo: \
- $(m4_ggo_dir)/loglevel.m4 \
- $(m4_ggo_dir)/config_file.m4 \
- $(m4_ggo_dir)/history_file.m4 \
- $(m4_ggo_dir)/complete.m4
-$(ggo_dir)/fade.ggo: $(m4_ggo_dir)/loglevel.m4 $(m4_ggo_dir)/config_file.m4
-$(ggo_dir)/resample_filter.ggo: \
- $(m4_ggo_dir)/channels.m4 \
- $(m4_ggo_dir)/sample_rate.m4 \
- $(m4_ggo_dir)/sample_format.m4
-$(ggo_dir)/play.ggo: $(m4_ggo_dir)/loglevel.m4 $(m4_ggo_dir)/config_file.m4
+$(m4depdir)/%.m4d: $(m4_ggo_dir)/%.m4 | $(m4depdir)
+ @[ -z "$(Q)" ] || echo 'M4D $<'
+ $(Q) m4 -I $(m4_ggo_dir) --debug=i $< 3>&1 1>/dev/null 2>&3 \
+ | awk '{if ($$0 ~ "^m4debug: input read from ") \
+ print "$(ggo_dir)/$(*F).ggo: " $$NF}' > $@
$(ggo_dir)/%.ggo: $(m4_ggo_dir)/%.m4 $(m4_ggo_dir)/header.m4 | $(ggo_dir)
@[ -z "$(Q)" ] || echo 'M4 $<'
diff --git a/m4/gengetopt/play.m4 b/m4/gengetopt/play.m4
index ea41f562..cb406bec 100644
--- a/m4/gengetopt/play.m4
+++ b/m4/gengetopt/play.m4
@@ -33,7 +33,7 @@ option "randomize" z
"randomize playlist at startup."
flag off
-option "key_map" k
+option "key-map" k
#~~~~~~~~~~~~~~~~~
"Map key k to a command."
diff --git a/m4/gengetopt/server.m4 b/m4/gengetopt/server.m4
index 8707554f..4c52d2c2 100644
--- a/m4/gengetopt/server.m4
+++ b/m4/gengetopt/server.m4
@@ -42,7 +42,7 @@ include(logfile.m4)
include(config_file.m4)
-option "user_list" -
+option "user-list" -
#~~~~~~~~~~~~~~~~~~~
"(default='~/.paraslash/server.users')"
@@ -60,7 +60,7 @@ option "autoplay" a
"start playing on startup"
flag off
-option "autoplay_delay" -
+option "autoplay-delay" -
#~~~~~~~~~~~~~~~~~~~~~~~~
"time to wait before streaming"
int typestr="ms"
@@ -76,7 +76,7 @@ details="
already up when para_server starts to stream. Of course, this
option depends on the autoplay option.
"
-option "announce_time" A
+option "announce-time" A
#~~~~~~~~~~~~~~~~~~~~~~~
"grace time for clients"
@@ -95,7 +95,7 @@ details="
section "audio file selector"
#############################
-option "afs_database_dir" D
+option "afs-database-dir" D
#~~~~~~~~~~~~~~~~~~~~~~~~~~
"location of the database"
string typestr="path"
@@ -105,7 +105,7 @@ details="
file selector. The default is '~/.paraslash/afs_database-0.4'.
"
-option "afs_socket" s
+option "afs-socket" s
#~~~~~~~~~~~~~~~~~~~~
"Command socket for afs"
string typestr="path"
@@ -117,7 +117,7 @@ details="
audio file selector via a local socket. This option specifies
the location of that socket in the file system.
"
-option "afs_initial_mode" i
+option "afs-initial-mode" i
#~~~~~~~~~~~~~~~~~~~~~~~~~~
"Mood or playlist to load on startup."
@@ -128,7 +128,7 @@ details="
The argument of this option must be prefixed with either 'p/'
or 'm/' to indicate whether a playlist or a mood should be
loaded. Example:
- --afs_initial_mode p/foo
+ --afs-initial-mode p/foo
loads the playlist named 'foo'.
"
@@ -137,7 +137,7 @@ section "http sender"
#####################
-option "http_port" -
+option "http-port" -
#~~~~~~~~~~~~~~~~~~~
"tcp port for http streaming"
int typestr="portnumber"
@@ -149,20 +149,20 @@ details="
http request message such as 'GET / HTTP/'.
"
-option "http_default_deny" -
+option "http-default-deny" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~~
"make the http ACL a whitelist"
flag off
details="
The default is to use blacklists instead, i.e. connections
to the http sender are allowed unless the connecting host
- matches a pattern given by a http_access option. This allows
+ matches a pattern given by a http-access option. This allows
to use access control the other way round: Connections are
denied from hosts which are not explicitly allowed by one or
- more http_access options.
+ more http-access options.
"
-option "http_access" -
+option "http-access" -
#~~~~~~~~~~~~~~~~~~~~~
"add an entry to the http ACL"
string typestr="a.b.c.d/n"
@@ -170,13 +170,13 @@ optional
multiple
details="
Add given host/network to access control list (whitelist if
- http_default_deny was given, blacklist otherwise) before
+ http-default-deny was given, blacklist otherwise) before
opening the tcp port. This option can be given multiple
times. Example: '192.168.0.0/24' whitelists/blacklists the
256 hosts 192.168.0.x
"
-option "http_no_autostart" -
+option "http-no-autostart" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~~
"do not open tcp port on startup"
flag off
@@ -186,7 +186,7 @@ details="
later time by using the sender command.
"
-option "http_max_clients" -
+option "http-max-clients" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~
"maximal number of connections"
int typestr="number"
@@ -204,45 +204,45 @@ section "dccp sender"
#####################
-option "dccp_port" -
+option "dccp-port" -
#~~~~~~~~~~~~~~~~~~~
"port for dccp streaming"
int typestr="portnumber"
default="8000"
optional
details="
- See http_port for details.
+ See http-port for details.
"
-option "dccp_default_deny" -
+option "dccp-default-deny" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~~
"make the dccp ACL a whitelist"
flag off
details="
- See http_default_deny for details.
+ See http-default-deny for details.
"
-option "dccp_access" -
+option "dccp-access" -
#~~~~~~~~~~~~~~~~~~~~~
"add an entry to the dccp ACL"
string typestr="a.b.c.d/n"
optional
multiple
details="
- See http_access for details.
+ See http-access for details.
"
-option "dccp_max_clients" -
+option "dccp-max-clients" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~
"maximal number of connections"
int typestr="number"
default="-1"
optional
details="
- See http_max_clients for details.
+ See http-max-clients for details.
"
-option "dccp_max_slice_size" -
+option "dccp-max-slice-size" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"Upper bound for the FEC slice size"
int typestr = "size"
@@ -261,7 +261,7 @@ details = "
the MPS of an incoming connection can not be set.
"
-option "dccp_data_slices_per_group" -
+option "dccp-data-slices-per-group" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"The number of non-redundant slices per FEC group"
int typestr = "num"
@@ -270,13 +270,13 @@ default = "3"
details = "
This determines the number of slices in each FEC group that are
necessary to decode the group. The given number must be smaller
- than the value of the dccp_slices_per_group option below.
+ than the value of the dccp-slices-per-group option below.
Note that the duration of a FEC group is proportional to the
- product dccp_max_slice_size * dccp_data_slices_per_group.
+ product dccp-max-slice-size * dccp-data-slices-per-group.
"
-option "dccp_slices_per_group" -
+option "dccp-slices-per-group" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"The total number of slices per FEC group"
int typestr = "num"
@@ -284,7 +284,7 @@ optional
default = "4"
details = "
This value must be larger than the value given for above
- dccp_data_slices_per_group above. The difference being the
+ dccp-data-slices-per-group above. The difference being the
number of redundant slices per group, i.e. the number of
data packets that may be lost without causing interruptions
of the resulting audio stream.
@@ -296,7 +296,7 @@ details = "
section "udp sender"
####################
-option "udp_target" -
+option "udp-target" -
#~~~~~~~~~~~~~~~~~~~~
"add udp target with optional port"
string typestr="host[:port]"
@@ -306,7 +306,7 @@ details="
Add given host/port to the list of targets. The 'host' argument
can be either an IPv4/v6 address or hostname (RFC 3986 syntax).
The 'port' argument is an optional port number. If the 'port'
- part is absent, the 'udp_default_port' value is used.
+ part is absent, the 'udp-default-port' value is used.
The following examples are possible targets:
'10.10.1.2:8000' (host:port); '10.10.1.2' (with default port);
@@ -317,7 +317,7 @@ details="
This option can be given multiple times, for multiple targets.
"
-option "udp_no_autostart" -
+option "udp-no-autostart" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~
"do not start sending"
flag off
@@ -326,20 +326,20 @@ details="
a later time by using the sender command.
"
-option "udp_default_port" -
+option "udp-default-port" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~
"udp port to send to"
int typestr="port"
default="8000"
optional
-option "udp_mcast_iface" -
+option "udp-mcast-iface" -
#~~~~~~~~~~~~~~~~~~~~~~~~~~
"outgoing udp multicast interface"
string
optional
-option "udp_header_interval" H
+option "udp-header-interval" H
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"duration for sending header"
int typestr = "ms"
@@ -357,7 +357,7 @@ details = "
audio formats, including mp3, don't need an audio file header.
"
-option "udp_ttl" t
+option "udp-ttl" t
#~~~~~~~~~~~~~~~~~
"set time to live value"
int typestr="num"
diff --git a/net.c b/net.c
index 2ec3f03e..4a31f013 100644
--- a/net.c
+++ b/net.c
@@ -672,19 +672,19 @@ char *remote_name(int sockfd)
/**
* Extract IPv4 or IPv6-mapped-IPv4 address from sockaddr_storage.
- * \param ss Container of IPv4/6 address
- * \return Extracted IPv4 address (different from 0) or 0 if unsuccessful.
*
- * \sa RFC 3493
+ * \param ss Container of IPv4/6 address.
+ * \param ia Extracted IPv4 address (different from 0) or 0 if unsuccessful.
+ *
+ * \sa RFC 3493.
*/
-struct in_addr extract_v4_addr(const struct sockaddr_storage *ss)
+void extract_v4_addr(const struct sockaddr_storage *ss, struct in_addr *ia)
{
- struct in_addr ia = {.s_addr = 0};
const struct sockaddr *sa = normalize_ip_address(ss);
+ memset(ia, 0, sizeof(*ia));
if (sa->sa_family == AF_INET)
- ia = ((struct sockaddr_in *)sa)->sin_addr;
- return ia;
+ *ia = ((struct sockaddr_in *)sa)->sin_addr;
}
/**
diff --git a/net.h b/net.h
index ae5e8015..0003fa9d 100644
--- a/net.h
+++ b/net.h
@@ -114,7 +114,7 @@ static inline int para_connect_simple(unsigned l4type,
return makesock(l4type, 0, host, port, NULL);
}
-extern struct in_addr extract_v4_addr(const struct sockaddr_storage *ss);
+void extract_v4_addr(const struct sockaddr_storage *ss, struct in_addr *ia);
/**
* Functions to support listening sockets.
diff --git a/para.h b/para.h
index 4de4af4a..29658f47 100644
--- a/para.h
+++ b/para.h
@@ -62,7 +62,7 @@ extern __printf_2_3 void (*para_log)(int, const char*, ...);
*
*/
#define DEFINE_STDERR_LOGGER(funcname, loglevel_barrier) \
- __printf_2_3 void funcname(int ll, const char* fmt,...) \
+ static __printf_2_3 void funcname(int ll, const char* fmt,...) \
{ \
va_list argp; \
if (ll < loglevel_barrier) \
@@ -82,14 +82,6 @@ extern __printf_2_3 void (*para_log)(int, const char*, ...);
/** Sent by para_client to initiate the authentication procedure. */
#define AUTH_REQUEST_MSG "auth rsa "
-/** Sent by para_server for commands that expect a data file. */
-#define AWAITING_DATA_MSG "\nAwaiting Data."
-/** Sent by para_server if authentication was successful. */
-#define PROCEED_MSG "Proceed."
-/** Length of the \p PROCEED_MSG string. */
-#define PROCEED_MSG_LEN strlen(PROCEED_MSG)
-/** Sent by para_client to indicate the end of the command line. */
-#define EOC_MSG "\nEnd of Command."
/* exec */
int para_exec_cmdline_pid(pid_t *pid, const char *cmdline, int *fds);
diff --git a/prebuffer_filter.c b/prebuffer_filter.c
index 655c981b..f4ef76e2 100644
--- a/prebuffer_filter.c
+++ b/prebuffer_filter.c
@@ -70,7 +70,7 @@ static int prebuffer_post_select(__a_unused struct sched *s, struct task *t)
return 0;
if (iqs < conf->size_arg)
return 0;
- btr_splice_out_node(fn->btrn);
+ btr_splice_out_node(&fn->btrn);
return -E_PREBUFFER_SUCCESS;
}
diff --git a/score.c b/score.c
index ca94e8de..37f4c550 100644
--- a/score.c
+++ b/score.c
@@ -168,13 +168,11 @@ static int get_nth_score(unsigned n, long *score)
* \param aft_row Determines the audio file to change.
* \param percent The position to re-insert the audio file.
*
- * The percent parameter must be between \p 0 and 100 and. A value of zero
- * means to re-insert the audio file into the score table with a score lower
- * than any other admissible file.
+ * The percent parameter must be between 0 and 100. A value of zero means to
+ * re-insert the audio file into the score table with a score lower than any
+ * other admissible file.
*
- * \return Positive on success, negative on errors. Possible errors: Errors
- * returned by osl_get_row(), get_num_admissible_files(), osl_get_nth_row(),
- * osl_get_object(), osl_update_object().
+ * \return Positive on success, negative on errors.
*/
int score_update(const struct osl_row *aft_row, long percent)
{
diff --git a/server.c b/server.c
index f26abef5..70d9137e 100644
--- a/server.c
+++ b/server.c
@@ -8,10 +8,7 @@
/**
- * \mainpage Paraslash API Reference
- *
- * Starting points for getting an overview:
- *
+ * \mainpage Starting points for getting an overview:
*
* - The main programs: \ref server.c, \ref audiod.c, \ref client.c,
* \ref audioc.c, \ref afh.c, \ref play.c,
@@ -391,6 +388,9 @@ static int command_post_select(struct sched *s, struct task *t)
goto out;
}
if (child_pid) {
+ /* avoid problems with non-fork-safe PRNGs */
+ unsigned char buf[16];
+ get_random_bytes_or_die(buf, sizeof(buf));
close(new_fd);
/* parent keeps accepting connections */
return 0;
diff --git a/sideband.h b/sideband.h
index 50daaa60..20e195b3 100644
--- a/sideband.h
+++ b/sideband.h
@@ -58,6 +58,8 @@
DESIGNATOR(EXIT__SUCCESS), \
/* Command failed. */ \
DESIGNATOR(EXIT__FAILURE), \
+ /* The next chunk of the blob (addblob commands only) */ \
+ DESIGNATOR(BLOB_DATA), \
/** Just prefix with \p SBD_. */
#define DESIGNATOR(x) SBD_ ## x
diff --git a/skencil/overview.sk b/skencil/overview.sk
deleted file mode 100644
index 5ab648c8..00000000
--- a/skencil/overview.sk
+++ /dev/null
@@ -1,474 +0,0 @@
-##Sketch 1 2
-document()
-layout('A4',0)
-layer('Layer 1',1,1,0,0,(0,0,0))
-lw(1)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(184.297,654.341,0)
-bs(184.297,732.403,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('open file',(1.19433e-15,1,-1,1.19433e-15,181.259,668.683))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('mp3 data',(-1.83691e-16,-1,1,-1.83691e-16,193.585,717.172))
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(190.547,726.853,0)
-bs(190.547,655.774,0)
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(145.824,181.165,0)
-bs(228.568,181.165,0)
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(228.568,161.165,0)
-bs(145.824,161.165,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('connect local socket',(1.19433e-15,1,-1,1.19433e-15,272.988,207.639))
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(307.4,339.815,0)
-bs(307.4,200,0)
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(280,200,0)
-bs(280,339.815,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('server & audiod status',(-1.83691e-16,-1,1,-1.83691e-16,310.438,332.705))
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(99.2303,144.289,0)
-bs(99.2303,73.1918,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('s&a status',(-1.83691e-16,-1,1,-1.83691e-16,102.268,137.713))
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(61.1648,150.482,0)
-bs(61.1647,71.2323,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('cmd output',(-1.83691e-16,-1,1,-1.83691e-16,64.2028,142.553))
-lw(0.992126)
-ld((0.10000000000000001, 1.0))
-b()
-bs(24.7094,792.443,0)
-bs(310.724,792.443,0)
-bs(310.421,640.011,0)
-bs(561.98,639.817,0)
-bs(561.98,538.528,0)
-bs(24.7094,538.528,0)
-bs(24.7094,792.443,0)
-bC()
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Italic')
-txt('server host',(252.845,779.314))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Italic')
-txt('client host',(512.93,400.509))
-G()
-lw(1)
-r(119.09,0,0,-28.2587,39.0214,375.322)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('para_client',(45.2504,355.601))
-G_()
-G()
-lw(1)
-r(143.312,0,0,-28.2587,408.597,189.57)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('sound_device',(414.265,169.849))
-G_()
-G()
-lw(1)
-r(94.8684,0,0,-28.2587,34.9844,58.6731)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('terminal',(42.4226,38.9517))
-G_()
-G()
-lw(1)
-r(131.201,0,0,-28.2587,237.937,189.4)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('para_audioc',(244.894,169.678))
-G_()
-G()
-lw(1)
-r(94.8684,0,0,-28.2587,34.9844,189.4)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('para_gui',(40.4306,169.678))
-G_()
-fp((0.9,0.9,0.9))
-lw(1)
-r(177.037,0,0,-89.6831,384.699,788.574)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Bold')
-Fs(36)
-txt('paraslash',(399.201,755.055))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Bold')
-Fs(36)
-txt('0.4.0',(437.217,712.433))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('fork & exec',(153.764,182.009))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('s&a status',(158.223,162.009))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('fork & exec',(1.19433e-15,1,-1,1.19433e-15,70.3615,232.519))
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(73.3994,201.263,0)
-bs(73.3995,330.639,0)
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(103.54,330.639,0)
-bs(103.539,201.263,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('cmd output',(-1.83691e-16,-1,1,-1.83691e-16,106.577,297.647))
-lw(0.992126)
-ld((0.10000000000000001, 1.0))
-b()
-bs(29.1803,415.392,0)
-bs(570.132,415.357,0)
-bs(570.132,26.3198,0)
-bs(27.1619,26.3198,0)
-bs(27.1619,413.359,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt(' server cmd',(2.57235e-15,1,-1,2.57235e-15,359.444,441.487))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('result',(-1.83691e-16,-1,1,-1.83691e-16,380.89,496.536))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('connect tcp',(1.19433e-15,1,-1,1.19433e-15,420.523,446.644))
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(426.278,433.194,0)
-bs(426.278,524.243,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('server status',(-1.83691e-16,-1,1,-1.83691e-16,438.254,513.515))
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(431.433,522.224,0)
-bs(431.433,434.203,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('mp3 data ',(-1.83691e-16,-1,1,-1.83691e-16,513.965,505.064))
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(506.551,520.71,0)
-bs(506.551,433.193,0)
-G()
-lw(1)
-r(301.847,0,0,-28.2587,220.095,375.322)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('para_audiod',(311.703,355.601))
-G_()
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(144.486,419.683,0)
-bs(144.486,431.685,0)
-bs(368.033,431.685,0)
-bs(368.033,531.257,0)
-lw(1)
-la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(151.551,419.179,0)
-bs(151.551,424.722,0)
-bs(374.601,424.722,0)
-bs(374.601,529.224,0)
-lw(1)
-ld((4, 4))
-r(156.432,0,0,-101.428,50.1221,646.762)
-G()
-lw(1)
-r(41.883,0,0,-28.2587,160.634,643.23)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('afh',(166.229,623.509))
-G_()
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Italic')
-txt('afs process',(106.135,651.24))
-lw(1)
-r(0,0,0,-0.504639,125.815,629.1)
-lw(1)
-ld((5, 5))
-r(272.999,0,0,-67.6189,281.238,614.467)
-lw(1)
-r(78.2156,0,0,-28.2587,289.816,609.925)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('vss',(313.588,590.204))
-lw(1)
-r(73.674,0,0,-59.5452,470.974,609.925)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('sender',(477.579,574.056))
-lw(1)
-r(167.533,0,0,-28.2587,289.816,577.629)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('cmd',(0.886791,0,0,1,355.258,557.908))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Italic')
-txt('server process',(286.284,618.44))
-G()
-lw(1)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(216.351,599.242,0)
-bs(272.871,599.242,0)
-lw(1)
-la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(216.351,603.697,0)
-bs(272.87,603.697,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('open fd',(223.502,588.236))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('request fd',(217.951,607.917))
-G_()
-G()
-lw(1)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(216.688,555.341,0)
-bs(273.208,555.341,0)
-lw(1)
-la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(216.688,559.796,0)
-bs(273.207,559.796,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('result',(228.885,545.344))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('afs cmd',(222.83,563.006))
-G_()
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(79.9931,735.431,0)
-bs(79.9931,652.573,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('osl result',(-1.83691e-16,-1,1,-1.83691e-16,83.0311,719.475))
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('osl query',(3.06152e-16,1,-1,3.06152e-16,68.1098,669.658))
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(73.6709,653.078,0)
-bs(73.6709,735.936,0)
-G()
-lw(1)
-r(119.595,0,0,-46.425,75.8576,784.523)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-txt('file system',(108.732,771.908))
-G()
-G()
-lw(1)
-r(48.4434,0,0,-21.1941,81.9131,764.929)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-txt('osl table',(85.9688,750.758))
-G_()
-G()
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-txt('mp3 file',(143.495,750.295))
-lw(1)
-r(48.4434,0,0,-21.1941,139.44,764.929)
-G_()
-G_()
-G_()
-lw(1)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(379.134,590.245,0)
-bs(461.495,590.245,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-txt('mp3 data',(397.646,596.3))
-G()
-lw(1)
-r(120.099,0,0,-53.4896,68.2886,608.411)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('afs',(0.886791,0,0,1,115.93,576.074))
-G_()
-G()
-lw(1)
-r(75.1101,0,0,-28.2587,56.6797,643.23)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(24)
-txt('libosl',(67.5587,620.179))
-G_()
-G()
-lw(0.992126)
-la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
-b()
-bs(466.036,335.949,0)
-bs(466.036,203.05,0)
-fp((0,0,0))
-le()
-lw(1)
-Fn('Times-Roman')
-Fs(14)
-txt('pcm data',(-1.83691e-16,-1,1,-1.83691e-16,476.076,294.966))
-G_()
-guidelayer('Guide Lines',1,0,0,1,(0,0,1))
-guide(-307.905,0)
-grid((0,0,20,20),0,(0,0,1),'Grid')
diff --git a/t/t0004-server.sh b/t/t0004-server.sh
index 3c878eb7..04d6cd60 100755
--- a/t/t0004-server.sh
+++ b/t/t0004-server.sh
@@ -74,15 +74,15 @@ EOF
$PARA_SERVER \
--logfile "$serverlog" \
- --config_file /dev/null \
+ --config-file /dev/null \
--daemon \
--loglevel $loglevel \
--port $port \
- --afs_database_dir "$db" \
- --afs_socket "$sock" \
- --user_list "$user_list" \
- --http_port "$stream_port" \
- --dccp_port "$stream_port"
+ --afs-database-dir "$db" \
+ --afs-socket "$sock" \
+ --user-list "$user_list" \
+ --http-port "$stream_port" \
+ --dccp-port "$stream_port"
fi
for ((i=0; i < ${#commands[@]}; i++)); do
@@ -114,9 +114,9 @@ for ((i=0; i < ${#commands[@]}; i++)); do
test_expect_success "$command" "
$PARA_CLIENT \
--loglevel $loglevel \
- --server_port $port \
- --key_file $privkey \
- --config_file /dev/null \
+ --server-port $port \
+ --key-file $privkey \
+ --config-file /dev/null \
-- \
${cmdline[$i]} > $command.out &&
{ [[ -z \"${good[$i]}\" ]] || grep \"${good[$i]}\"; } < $command.out &&
diff --git a/wav_filter.c b/wav_filter.c
index 83b81fb2..eaef1f5c 100644
--- a/wav_filter.c
+++ b/wav_filter.c
@@ -113,7 +113,7 @@ static int wav_post_select(__a_unused struct sched *s, struct task *t)
ret = -E_WAV_SUCCESS;
err:
if (ret == -E_WAV_SUCCESS)
- btr_splice_out_node(btrn);
+ btr_splice_out_node(&fn->btrn);
else {
btr_remove_node(&fn->btrn);
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
diff --git a/web/dia/overview.dia b/web/dia/overview.dia
new file mode 100644
index 00000000..f9e01586
--- /dev/null
+++ b/web/dia/overview.dia
@@ -0,0 +1,3817 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ #A4#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Overview#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_server#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Incoming connections arrive via TCP at the dispatcher which creates a
+command handler process for each connection.
+
+After the connecting client has been authenticated, the command
+handler propagates the incoming request either to the audio file
+selector (afs) or to the virtual streaming system (vss). Results are sent
+back to the client.
+
+afs maintans the audio file database and is responsible for selecting
+and loading audio files while vss controls the paraslash senders. When
+vss needs to stream an audio file it requests an open file descriptor from
+afs and feeds small chunks of data (e.g. mp3 frames) to the senders
+which send the chunks to all connected clients.#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #dispatcher#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #senders#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #vss#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #command
+handler#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #afs#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_server#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_audiod#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_audioc#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_gui#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_client#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #The two main applications of the paraslash suite (shaded green) are
+para_server and para_audiod. Both run in the background usually.
+para_server maintains the audio file database and acts as the streaming
+source, while para_audiod is the streaming client.
+
+The two client programs, para_client and para_audioc communicate
+with para_server and para_audiod, respectively.
+
+para_gui controls para_server/audiod by executing paraslash commands.
+Command output is shown in a curses window. para_gui automatically
+executes para_audioc to obtain the state of para_audiod and para_server
+and the metadata of the current audio file.
+
+Network connections are shaded grey, local connections black.#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_audiod#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #The purpose of para_audiod is to download, decode and play an audio
+stream received from para_server. It fetches the para_server status and
+starts a suitable buffer tree (shaded blue) if an audio stream is available.
+
+The buffer tree usually consists of a receiver, any number of filters and
+a writer. The receiver downloads the audio stream from para_server and
+the filters decode or modify the received data. The writer plays the
+decoded stream.
+
+The dispatcher acts on (local) requests from para_audioc, for example to
+dump information about the current audio file.#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #The audio file selector (afs) accepts two different kinds of incoming
+connections: A bidirectional pipe shared with para_server is used for
+passing the file descriptor of the current audio file to the server
+process. The local socket is used by command handlers which query
+or update the database.
+
+To add a new file to the database, afs opens the file and locates an
+audio format handler (afh) that recognizes the file. A new database
+entry with metadata obtained from the afh is then added to the
+database.#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #The audio file selector#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #audio files#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_server#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #afh#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #osl db#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #command handler#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #afs#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #The OSL database#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Metadata about all known audio files is stored in serveral tables of a
+database which is driven by libosl, the object storage layer library.
+
+The "audio files" table is the main table of the database. It contains
+path, hash and metadata of each known file.
+
+The "attributes" table maps each of the 64 possible attributes to a
+string. The attribute value of the file's metadata is translated through
+this table.
+
+The tables shown shaded are blob tables which support add, rm, mv,
+cat, ls commands. All of these are optional.
+
+The "score" table describes the subset of admissible files for the
+current playlist or mood. This table is created on demand, resides
+only in memory and is discarded on exit.
+
+When the next audio file is to be streamed, the audio file selector gets
+the entry with the highest score from the "score" table, obtains path,
+hash, and metadata for this entry from the "audio files" table, opens
+the path and verifies the hash.#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #audio files#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #playlists#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #images#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #attributes#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #lyrics#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #moods#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #score#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #dispatcher#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #status fetcher#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_server#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #receiver#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #filter1#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #filter 2#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #writer#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #para_audioc#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/documentation.in.html b/web/documentation.in.html
index 4d63a08f..f292af25 100644
--- a/web/documentation.in.html
+++ b/web/documentation.in.html
@@ -30,6 +30,7 @@
[para_write]
[para_gui]
[para_fade]
+ [para_play]
Source code documentation
diff --git a/web/gitweb.css b/web/gitweb.css
deleted file mode 100644
index 08110a6e..00000000
--- a/web/gitweb.css
+++ /dev/null
@@ -1,506 +0,0 @@
-body {
- font-family: sans-serif;
- font-size: small;
- /*border: solid #d9d8d1;*/
- border-width: 1px;
- margin: 0px;
- padding: 10px;
- background-color: black;
- color: #cccccc;
- height: 100%;
-}
-
-a {
- color: #BA3708;
-}
-
-a:hover {
- color: #BA3708;
- background-color: #ffff00;
-}
-
-span.cntrl {
- border: dashed #aaaaaa;
- border-width: 1px;
- padding: 0px 2px 0px 2px;
- margin: 0px 2px 0px 2px;
-}
-
-img.logo {
- float: right;
- border-width: 0px;
-}
-
-div.page_header {
- /*height: 10px;*/
- padding: 8px;
- font-size: 150%;
- font-weight: bold;
- background-color: #151515;
-}
-
-div.page_header a:visited, a.header {
- color: #BA3708;
-}
-
-div.page_header a:hover {
- color: #880000;
-}
-
-div.page_nav {
- padding: 8px;
-}
-
-div.page_nav a:visited {
- color: #BA3708;
-}
-
-div.page_path {
- padding: 8px;
- font-weight: bold;
- border: solid #d9d8d1;
- border-width: 0px 0px 1px;
-}
-
-div.page_footer {
- height: 17px;
- padding: 4px 8px;
- background-color: #d9d8d1;
-}
-
-div.page_footer_text {
- float: left;
- color: #555555;
- font-style: italic;
-}
-
-div.page_body {
- padding: 8px;
- font-family: monospace;
-}
-
-div.title, a.title {
- display: block;
- padding: 6px 8px;
- font-weight: bold;
- background-color: #555555;
- text-decoration: none;
- color: white;
-}
-
-a.title:hover {
- background-color: #AA3100;
-}
-
-div.title_text {
- padding: 6px 0px;
- border: solid #d9d8d1;
- border-width: 0px 0px 1px;
- font-family: monospace;
-}
-
-div.log_body {
- padding: 8px 8px 8px 150px;
-}
-
-span.age {
- position: relative;
- float: left;
- width: 142px;
- font-style: italic;
-}
-
-span.signoff {
- color: #888888;
-}
-
-div.log_link {
- padding: 0px 8px;
- font-size: 70%;
- font-family: sans-serif;
- font-style: normal;
- position: relative;
- float: left;
- width: 136px;
-}
-
-div.list_head {
- padding: 6px 8px 4px;
- border: solid #d9d8d1;
- border-width: 1px 0px 0px;
- font-style: italic;
-}
-
-div.author_date {
- padding: 8px;
- border: solid #d9d8d1;
- border-width: 0px 0px 1px 0px;
- font-style: italic;
-}
-
-a.list {
- text-decoration: none;
- color: #BA3708;
-}
-
-a.subject, a.name {
- font-weight: bold;
-}
-
-table.tags a.subject {
- font-weight: normal;
-}
-
-a.list:hover {
- text-decoration: underline;
- color: #880000;
-}
-
-a.text {
- text-decoration: none;
- color: #0000cc;
-}
-
-a.text:visited {
- text-decoration: none;
- color: #880000;
-}
-
-a.text:hover {
- text-decoration: underline;
- color: #880000;
-}
-
-table {
- padding: 8px 4px;
-}
-
-table.project_list {
- border-spacing: 0;
-}
-
-table.diff_tree {
- border-spacing: 0;
- font-family: monospace;
-}
-
-table.combined.diff_tree th {
- text-align: center;
-}
-
-table.combined.diff_tree td {
- padding-right: 24px;
-}
-
-table.combined.diff_tree th.link,
-table.combined.diff_tree td.link {
- padding: 0px 2px;
-}
-
-table.combined.diff_tree td.nochange a {
- color: #6666ff;
-}
-
-table.combined.diff_tree td.nochange a:hover,
-table.combined.diff_tree td.nochange a:visited {
- color: #d06666;
-}
-
-table.blame {
- border-collapse: collapse;
-}
-
-table.blame td {
- padding: 0px 5px;
- font-size: 100%;
- vertical-align: top;
-}
-
-th {
- padding: 2px 5px;
- font-size: 100%;
- text-align: left;
-}
-
-tr.light:hover {
- background-color: yellow;
- color: #BA3708;
-}
-
-tr.dark {
- background-color: #333333;
-}
-
-tr.dark2 {
- background-color: #333333;
-}
-
-tr.dark:hover {
- background-color: yellow;
- color: #BA3708;
-}
-
-td {
- padding: 2px 5px;
- font-size: 100%;
- vertical-align: top;
-}
-
-td.link, td.selflink {
- padding: 2px 5px;
- font-family: sans-serif;
- font-size: 70%;
-}
-
-td.selflink {
- padding-right: 0px;
-}
-
-td.sha1 {
- font-family: monospace;
-}
-
-td.error {
- color: red;
- background-color: yellow;
-}
-
-td.current_head {
- text-decoration: underline;
-}
-
-table.diff_tree span.file_status.new {
- color: #008000;
-}
-
-table.diff_tree span.file_status.deleted {
- color: #c00000;
-}
-
-table.diff_tree span.file_status.moved,
-table.diff_tree span.file_status.mode_chnge {
- color: #777777;
-}
-
-table.diff_tree span.file_status.copied {
- color: #70a070;
-}
-
-/* noage: "No commits" */
-table.project_list td.noage {
- color: #808080;
- font-style: italic;
-}
-
-/* age2: 60*60*24*2 <= age */
-table.project_list td.age2, table.blame td.age2 {
- font-style: italic;
-}
-
-/* age1: 60*60*2 <= age < 60*60*24*2 */
-table.project_list td.age1 {
- color: #009900;
- font-style: italic;
-}
-
-table.blame td.age1 {
- color: #009900;
- background: transparent;
-}
-
-/* age0: age < 60*60*2 */
-table.project_list td.age0 {
- color: #009900;
- font-style: italic;
- font-weight: bold;
-}
-
-table.blame td.age0 {
- color: #009900;
- background: transparent;
- font-weight: bold;
-}
-
-td.pre, div.pre, div.diff {
- font-family: monospace;
- font-size: 12px;
- white-space: pre;
-}
-
-td.mode {
- font-family: monospace;
-}
-
-/* styling of diffs (patchsets): commitdiff and blobdiff views */
-div.diff.header,
-div.diff.extended_header {
- white-space: normal;
-}
-
-div.diff.header {
- font-weight: bold;
-
- background-color: #333333;
-
- margin-top: 4px;
- padding: 4px 0px 2px 0px;
- border: solid #d9d8d1;
- border-width: 1px 0px 1px 0px;
-}
-
-div.diff.header a.path {
- text-decoration: underline;
-}
-
-div.diff.extended_header,
-div.diff.extended_header a.path,
-div.diff.extended_header a.hash {
- color: #cccccc;
-}
-
-div.diff.extended_header .info {
- color: #b0b0b0;
-}
-
-div.diff.extended_header {
- background-color: #333333;
- padding: 2px 0px 2px 0px;
-}
-
-div.diff a.list,
-div.diff a.path,
-div.diff a.hash {
- text-decoration: none;
-}
-
-div.diff a.list:hover,
-div.diff a.path:hover,
-div.diff a.hash:hover {
- text-decoration: underline;
-}
-
-div.diff.to_file a.path,
-div.diff.to_file {
- color: #007000;
-}
-
-div.diff.add {
- color: #008800;
-}
-
-div.diff.from_file a.path,
-div.diff.from_file {
- color: #ff0000;
-}
-
-div.diff.rem {
- color: #cc0000;
-}
-
-div.diff.chunk_header a,
-div.diff.chunk_header {
- color: #990099;
-}
-
-div.diff.chunk_header {
- border: dotted #ffe0ff;
- border-width: 1px 0px 0px 0px;
- margin-top: 2px;
-}
-
-div.diff.chunk_header span.chunk_info {
- background-color: #000000;
-}
-
-div.diff.chunk_header span.section {
- color: #aa22aa;
-}
-
-div.diff.incomplete {
- color: #cccccc;
-}
-
-div.diff.nodifferences {
- font-weight: bold;
- color: #600000;
-}
-
-div.index_include {
- border: solid #d9d8d1;
- border-width: 0px 0px 1px;
- padding: 12px 8px;
-}
-
-div.search {
- font-size: 100%;
- font-weight: normal;
- margin: 4px 8px;
- float: right;
- top: 56px;
- right: 12px
-}
-
-td.linenr {
- text-align: right;
-}
-
-a.linenr {
- color: #999999;
- text-decoration: none
-}
-
-a.rss_logo {
- float: right;
- padding: 3px 0px;
- width: 35px;
- line-height: 10px;
- border: 1px solid;
- border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
- color: #ffffff;
- background-color: #ff6600;
- font-weight: bold;
- font-family: sans-serif;
- font-size: 70%;
- text-align: center;
- text-decoration: none;
-}
-
-a.rss_logo:hover {
- background-color: #ee5500;
-}
-
-span.refs span {
- padding: 0px 4px;
- font-size: 70%;
- font-weight: normal;
- border: 1px solid;
- background-color: #222222;
- border-color: #ffccff #ff00ee #ff00ee #ffccff;
-}
-
-span.refs span.ref {
- background-color: #aaaaff;
- border-color: #ccccff #0033cc #0033cc #ccccff;
-}
-
-span.refs span.tag {
- background-color: #ffffaa;
- border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
-}
-
-span.refs span.head {
- background-color: #222222;
- border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
-}
-
-span.atnight {
- color: #cc0000;
-}
-
-span.match {
- color: #e00000;
-}
-
-div.binary {
- font-style: italic;
-}
diff --git a/web/gitweb_header.html.in b/web/gitweb_header.html.in
index d1338276..f7b40714 100644
--- a/web/gitweb_header.html.in
+++ b/web/gitweb_header.html.in
@@ -1,29 +1,28 @@
-
-
-
+
+
+
-
+
- |
-
- Paraslash: Play, archive, rate and stream
- large audio sets happily
-
- A set of tools for doing just what its name
- suggests.
- |
-
+
+
+ Paraslash network audio streaming tools
+ |
+
-
- Home
- News
- Features
- Download
- Screenshots
- Changes
- Documentation
- License
- Contact
- Credits
+ |
+
+ Home
+ Features
+ Screenshots
+ Download
+ Documentation
+ Changes
+ Development
+ License
+ Contact
+ Credits
|
-
+ |
+ Changes
+
diff --git a/web/header.html b/web/header.html
index f7cb2776..475079ba 100644
--- a/web/header.html
+++ b/web/header.html
@@ -8,32 +8,29 @@
-
-
+
-
+
+
+
|
- Paraslash: Play, archive, rate and stream
- large audio sets happily
-
- A set of tools for doing just what its name
- suggests.
+ Paraslash network audio streaming tools
|
-
- Home
- News
- Features
- Download
- Screenshots
- Changes
- Documentation
- License
- Contact
- Credits
+ |
+
+ Home
+ Features
+ Screenshots
+ Download
+ Documentation
+ Changes
+ Development
+ License
+ Contact
+ Credits
|
-
-
+ |
diff --git a/web/header2.html b/web/header2.html
index 94fbcad2..cf919d0d 100644
--- a/web/header2.html
+++ b/web/header2.html
@@ -8,32 +8,32 @@
-
-
+
-
+
+
+
|
- Paraslash: Play, archive, rate and stream
- large audio sets happily
-
- A set of tools for doing just what its name
- suggests.
+ Paraslash network audio streaming tools
|
-
- Home
- News
- Features
- Download
- Screenshots
- Changes
- Documentation
- License
- Contact
- Credits
+ |
+
+ Home
+ Features
+ Screenshots
+ Download
+ Documentation
+ Changes
+ Development
+ License
+ Contact
+ Credits
|
-
-
+ |
+ API Reference
+
+
diff --git a/web/images/paraslash.ico b/web/images/paraslash.ico
index 860c5abd..fd17a649 100644
Binary files a/web/images/paraslash.ico and b/web/images/paraslash.ico differ
diff --git a/web/images/paraslash.png b/web/images/paraslash.png
index d4a1bd9a..a06d6a1a 100644
Binary files a/web/images/paraslash.png and b/web/images/paraslash.png differ
diff --git a/web/index.in.html b/web/index.in.html
deleted file mode 100644
index c9a82a87..00000000
--- a/web/index.in.html
+++ /dev/null
@@ -1,143 +0,0 @@
-Events
-
-
diff --git a/web/manual.m4 b/web/manual.m4
index 3f5f148f..55bb49a6 100644
--- a/web/manual.m4
+++ b/web/manual.m4
@@ -406,7 +406,7 @@ the directory /var/paraslash that has been created during installation:
sudo chown $LOGNAME /var/paraslash
-Alternatively, use the --afs_socket Option to specify a different
+Alternatively, use the --afs-socket Option to specify a different
location for the AFS command socket.
For this first try, we'll use the info loglevel to make the output
@@ -592,7 +592,7 @@ The user_list file
At startup para_server reads the user list file which contains one
line per user. The default location of the user list file may be
-changed with the --user_list option.
+changed with the --user-list option.
There should be at least one user in this file. Each user must have
an RSA key pair. The public part of the key is needed by para_server
@@ -639,7 +639,7 @@ restricted on platforms that support UNIX socket credentials which
allow para_audiod to obtain the Unix credentials of the connecting
process.
-Use para_audiod's --user_allow option to allow connections only for
+Use para_audiod's --user-allow option to allow connections only for
a limited set of users.
-----------------------
@@ -1770,7 +1770,7 @@ a curses window. By default the command
para_audioc -- stat -p
-is executed, but this can be customized via the --stat_cmd option. In
+is executed, but this can be customized via the --stat-cmd option. In
particular it possible to use
para_client -- stat -p
diff --git a/web/para.css b/web/para.css
index f103abd3..422f454e 100644
--- a/web/para.css
+++ b/web/para.css
@@ -1,29 +1,50 @@
-BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+body,h1,h2,h3,h4,h5,h6,p,center,td,th,ul,dl,div {
font-family: sans-serif;
- font-size: small;
}
-/*
-BODY,TD {
- font-size: 90%;
+body {
+ background-color: black;
+ color: #bbbbbb;
+ margin: 0px;
}
-H1 {
- text-align: center;
- font-size: 160%;
+
+table {
+ padding: 8px 4px;
}
-H2 {
- font-size: 120%;
+
+th {
+ padding: 2px 5px;
+ font-size: 100%;
+ text-align: left;
}
-H3 {
+
+td {
+ padding: 2px 5px;
font-size: 100%;
+ vertical-align: top;
+}
+
+a {
+ color: #cc3322;
+}
+
+hr {
+ height: 1px;
+ border: none;
+ border-top: 1px solid yellow;
+}
+
+img {
+ float: right;
+ border-width: 0px;
}
-*/
-CAPTION { font-weight: bold }
+
+caption { font-weight: bold }
/* doxgen */
/* Data structure index. Box with clickable letters */
-DIV.qindex {
+div.qindex {
width: 100%;
background-color: #000055;
border: 1px solid #ffff00;
@@ -32,78 +53,61 @@ DIV.qindex {
padding: 2px;
line-height: 140%;
}
-/*
-DIV.nav {
- width: 100%;
- background-color: #48ee02;
- border: 1px solid #ffff00;
- text-align: center;
- margin: 2px;
- padding: 2px;
- line-height: 140%;
-}
-DIV.navtab {
- background-color: #48ee02;
- border: 1px solid #ffff00;
- text-align: center;
- margin: 2px;
- margin-right: 15px;
- padding: 2px;
-}
-TD.navtab {
- font-size: 70%;
-}
-*/
/* Data structure index, clickable letters */
-A.qindex {
+a.qindex {
text-decoration: none;
font-weight: bold;
color: #cc3322;
}
-A.qindex:visited {
+
+a.qindex:visited {
text-decoration: none;
font-weight: bold;
color: #cc3322
}
-A.qindex:hover {
+
+a.qindex:hover {
text-decoration: none;
background-color: #ffff00;
}
-/*
-A.qindexHL {
+a.el {
text-decoration: none;
- font-weight: bold;
- background-color: #cccc00;
- color: #000000;
- border: 1px double #929502;
+ font-weight: bold
}
-A.qindexHL:hover {
+
+a.elRef { font-weight: bold }
+
+a.code:link {
text-decoration: none;
- background-color: #ffff00;
- color: #000000;
+ font-weight: normal;
+ color: #BA3708
}
-A.qindexHL:visited {
+
+a.code:visited {
text-decoration: none;
- background-color: #e6c60c;
- color: #000000
-}
-*/
-
-A.el { text-decoration: none; font-weight: bold }
-A.elRef { font-weight: bold }
-A.code:link { text-decoration: none; font-weight: normal; color: #BA3708}
-A.code:visited { text-decoration: none; font-weight: normal; color: #BA3708}
-A.codeRef:link { font-weight: normal; color: #BA3708}
-A.codeRef:visited { font-weight: normal; color: #BA3708}
-A:hover { text-decoration: none; background-color: #ffff00 }
-DL.el { margin-left: -1cm }
+ font-weight: normal;
+ color: #BA3708
+}
+
+a.codeRef:link {
+ font-weight: normal;
+ color: #BA3708
+}
+
+a.codeRef:visited {
+ font-weight: normal;
+ color: #BA3708
+}
+
+dl.el { margin-left: -1cm }
.fragment {
font-family: Fixed, monospace;
font-size: 95%;
}
-PRE.fragment {
+
+pre.fragment {
border: 1px solid #CCCCCC;
background-color: #351505;
margin-top: 4px;
@@ -117,49 +121,29 @@ PRE.fragment {
}
/* data structures non-clickable letters */
-DIV.ah {
+div.ah {
background-color: black;
font-weight: bold;
color: #cccccc;
margin-bottom: 3px;
margin-top: 3px
}
-/*
-TD.md { background-color: #ff0000; font-weight: bold; }
-TD.mdPrefix {
- background-color: #ffff00;
- color: #606060;
- font-size: 80%;
-}
-TD.mdname1 {
- background-color: #000055;
- font-weight: bold;
- color: #ff0000;
-}
-TD.mdname {
- background-color: #000055;
- font-weight: bold;
- color: #00CC00;
- width: 600px;
-}
-*/
-DIV.groupHeader {
+div.groupHeader {
margin-left: 16px;
margin-top: 12px;
margin-bottom: 6px;
font-weight: bold;
}
-DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
-BODY {
- background: black;
- color: #bbbbbb;
- margin-right: 20px;
- margin-left: 20px;
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+ font-size: 90%
}
/* File list */
-TD.indexkey {
+td.indexkey {
background-color: #000055;
font-weight: bold;
padding-right : 10px;
@@ -173,7 +157,7 @@ TD.indexkey {
border: 1px solid #ffff00;
}
-TD.indexvalue {
+td.indexvalue {
background-color: #000055;
font-style: italic;
padding-right : 10px;
@@ -187,22 +171,12 @@ TD.indexvalue {
border: 1px solid #ffff00;
}
-TR.memlist {
- background-color: #112244;
+tr.memlist {
+ background-color: #112244;
}
-P.formulaDsp { text-align: center; }
-IMG.formulaDsp { }
-IMG.formulaInl { vertical-align: middle; }
-/*
-SPAN.keyword { color: #ffff00 }
-SPAN.keywordtype { color: #ffff00 }
-SPAN.keywordflow { color: #108000 }
-SPAN.comment { color: #00CCCC }
-SPAN.preprocessor { color: #CC00CC }
-SPAN.stringliteral { color: #e0e020 }
-SPAN.charliteral { color: #0000ff }
-*/
-
+p.formulaDsp { text-align: center; }
+img.formulaDsp { }
+img.formulaInl { vertical-align: middle; }
/* Overwiew on top of page for *.c file */
@@ -210,12 +184,14 @@ SPAN.charliteral { color: #0000ff }
padding: 0px 8px 4px 8px;
margin: 0px;
}
+
.mdescRight { /* Short description */
padding: 0px 8px 4px 8px;
font-size: 100%;
font-style: italic;
margin: 0px;
}
+
.memItemLeft { /* return value */
color: #ffffff;
border-top-color: #ffff00;
@@ -228,6 +204,7 @@ SPAN.charliteral { color: #0000ff }
border-left-style: none;
font-size: 100%;
}
+
.memItemRight { /* function declaration */
color: #ffffff;
border-top-color: #ffff00;
@@ -241,154 +218,545 @@ SPAN.charliteral { color: #0000ff }
font-size: 100%;
}
-/*
-.memTemplItemLeft {
- padding: 1px 0px 0px 8px;
- margin: 4px;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- border-top-color: #E0E000;
- border-right-color: #E0E000;
- border-bottom-color: #E0E000;
- border-left-color: #E0E000;
- border-top-style: none;
- border-right-style: none;
- border-bottom-style: none;
- border-left-style: none;
- background-color: #000000;
- font-size: 80%;
-}
-.memTemplItemRight {
- padding: 1px 8px 0px 8px;
- margin: 4px;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- border-top-color: #E0E000;
- border-right-color: #E0E000;
- border-bottom-color: #E0E000;
- border-left-color: #E0E000;
- border-top-style: none;
- border-right-style: none;
- border-bottom-style: none;
- border-left-style: none;
- background-color: #000000;
- font-size: 80%;
-}
-.memTemplParams {
- padding: 1px 0px 0px 8px;
- margin: 4px;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- border-top-color: #E0E000;
- border-right-color: #E0E000;
- border-bottom-color: #E0E000;
- border-left-color: #E0E000;
- border-top-style: solid;
- border-right-style: none;
- border-bottom-style: none;
- border-left-style: none;
- color: #606060;
- background-color: #3A3A1A;
- font-size: 80%;
-}
-*/
-.search { color: #f03309;
- font-weight: bold;
-}
-FORM.search {
- margin-bottom: 0px;
- margin-top: 0px;
-}
-INPUT.search { font-size: 75%;
- color: #800000;
- font-weight: normal;
- background-color: #000000;
-}
-TD.tiny {
- font-size: 75%;
+.search {
+ color: #f03309;
+ font-weight: bold;
}
-/* links */
-a {
- color: #cc3322;
-/* color: #BA4108; */
+form.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
}
-a:visited {
-/* color: #BA3708; */
- color: #cc3322;
+input.search {
+ font-size: 75%;
+ color: #800000;
+ font-weight: normal;
+ background-color: #000000;
+}
+
+td.tiny {
+ font-size: 75%;
}
+
.dirtab { padding: 4px;
border-collapse: collapse;
border: 1px solid #84b007;
}
-TH.dirtab { background: #080e02;
- font-weight: bold;
-}
-HR { height: 1px;
- border: none;
- border-top: 1px solid yellow;
+
+th.dirtab {
+ background: #080e02;
+ font-weight: bold;
}
/* Style for detailed member documentation */
.memtemplate {
- font-size: 100%;
- color: #cccccc;
- font-weight: normal;
-}
-/*
-.memnav {
- border: 5px solid #845047;
- text-align: center;
- margin: 2px;
- margin-right: 15px;
- padding: 2px;
-}
-*/
+ font-size: 100%;
+ color: #cccccc;
+ font-weight: normal;
+}
+
.memitem { /* outer border around function */
- padding: 6px;
- background-color: #000000;
- border-width: 2px;
- border-style: solid;
- border-color: #ffff00;
-/* -moz-border-radius: 8px 8px 8px 8px; */
+ padding: 6px;
+ background-color: #000000;
+ border-width: 2px;
+ border-style: solid;
+ border-color: #ffff00;
}
+
.memname {
- color: #ffffff; /* name of the function */
- white-space: nowrap;
- font-weight: bold;
+ color: #ffffff; /* name of the function */
+ white-space: nowrap;
+ font-weight: bold;
}
+
.memdoc{
- padding-left: 10px;
+ padding-left: 10px;
}
/* inner box containing function definition */
.memproto {
- background-color: #000055;
- width: 100%;
- border-width: 2px;
- border-style: solid;
- border-color: #ffff00;
- font-weight: bold;
-/* -moz-border-radius: 8px 8px 8px 8px;*/
+ background-color: #000055;
+ width: 100%;
+ border-width: 2px;
+ border-style: solid;
+ border-color: #ffff00;
+ font-weight: bold;
}
.paramkey {
- color: #ff0000;
- text-align: right;
+ color: #ff0000;
+ text-align: right;
}
+
.paramtype { /* type of function parameter, e.g. "int" */
- color: #00ff00;
- white-space: nowrap;
+ color: #00ff00;
+ white-space: nowrap;
}
+
.paramname { /* name of function parameter */
- color: #ffff00;
- font-style: italic;
+ color: #ffff00;
+ font-style: italic;
+}
+
+span.cntrl {
+ border: dashed #aaaaaa;
+ border-width: 1px;
+ padding: 0px 2px 0px 2px;
+ margin: 0px 2px 0px 2px;
+}
+
+div.page_header {
+ padding: 8px;
+ font-size: 120%;
+ font-weight: bold;
+ background-color: #151515;
+}
+
+div.page_header a:visited, a.header {
+ color: #cc3322;
+}
+
+div.page_header a:hover {
+ color: #880000;
+}
+
+div.page_nav {
+ padding: 8px;
+}
+
+div.page_nav a:visited {
+ color: #cc3322;
+}
+
+div.page_path {
+ padding: 8px;
+ font-weight: bold;
+ border: solid #d9d8d1;
+ border-width: 0px 0px 1px;
+}
+
+div.page_footer {
+ height: 17px;
+ padding: 4px 8px;
+ background-color: #d9d8d1;
+}
+
+div.page_footer_text {
+ float: left;
+ color: #555555;
+ font-style: italic;
+}
+
+div.page_body {
+ padding: 8px;
+ font-family: monospace;
+ font-size: 120%;
+}
+
+a.title:hover {
+ background-color: #AA3100;
}
+div.title_text {
+ padding: 6px 0px;
+ border: solid #d9d8d1;
+ border-width: 0px 0px 1px;
+ font-family: monospace;
+}
+
+div.log_body {
+ padding: 8px 8px 8px 150px;
+ font-family: monospace;
+ font-size: 120%;
+}
+
+div.log {
+ font-family: monospace;
+ font-size: 120%;
+}
+
+span.age {
+ position: relative;
+ float: left;
+ width: 142px;
+ font-style: italic;
+}
+
+span.signoff {
+ color: #888888;
+}
+
+div.log_link {
+ padding: 0px 8px;
+ font-size: 70%;
+ font-family: sans-serif;
+ font-style: normal;
+ position: relative;
+ float: left;
+ width: 136px;
+}
+
+div.list_head {
+ padding: 6px 8px 4px;
+ border: solid #d9d8d1;
+ border-width: 1px 0px 0px;
+ font-style: italic;
+}
+
+div.author_date {
+ padding: 8px;
+ border: solid #d9d8d1;
+ border-width: 0px 0px 1px 0px;
+ font-style: italic;
+}
+
+a.list {
+ text-decoration: none;
+ color: #cc3322;
+}
+
+a.subject, a.name {
+ font-weight: bold;
+}
+
+table.tags a.subject {
+ font-weight: normal;
+}
+
+a.list:hover {
+ text-decoration: underline;
+ color: #880000;
+}
+
+a.text {
+ text-decoration: none;
+ color: #0000cc;
+}
+
+a.text:visited {
+ text-decoration: none;
+ color: #880000;
+}
+
+a.text:hover {
+ text-decoration: underline;
+ color: #880000;
+}
+
+table.project_list {
+ border-spacing: 0;
+}
+
+table.diff_tree {
+ border-spacing: 0;
+ font-family: monospace;
+}
+
+table.combined.diff_tree th {
+ text-align: center;
+}
+
+table.combined.diff_tree td {
+ padding-right: 24px;
+}
+
+table.combined.diff_tree th.link,
+table.combined.diff_tree td.link {
+ padding: 0px 2px;
+}
+
+table.combined.diff_tree td.nochange a {
+ color: #6666ff;
+}
+
+table.combined.diff_tree td.nochange a:hover,
+table.combined.diff_tree td.nochange a:visited {
+ color: #d06666;
+}
+
+table.blame {
+ border-collapse: collapse;
+}
+
+table.blame td {
+ padding: 0px 5px;
+ font-size: 100%;
+ vertical-align: top;
+}
+
+tr.light:hover {
+ background-color: yellow;
+ color: #cc3322;
+}
+
+tr.dark {
+ background-color: #333333;
+}
+
+tr.dark2 {
+ background-color: #333333;
+}
+
+tr.dark:hover {
+ background-color: yellow;
+ color: #cc3322;
+}
+
+td.link, td.selflink {
+ padding: 2px 5px;
+ font-family: sans-serif;
+ font-size: 70%;
+}
+
+td.selflink {
+ padding-right: 0px;
+}
+
+td.sha1 {
+ font-family: monospace;
+}
+
+td.error {
+ color: red;
+ background-color: yellow;
+}
+
+td.current_head {
+ text-decoration: underline;
+}
+
+table.diff_tree span.file_status.new {
+ color: #008000;
+}
+
+table.diff_tree span.file_status.deleted {
+ color: #c00000;
+}
+
+table.diff_tree span.file_status.moved,
+table.diff_tree span.file_status.mode_chnge {
+ color: #777777;
+}
+
+table.diff_tree span.file_status.copied {
+ color: #70a070;
+}
+
+/* noage: "No commits" */
+table.project_list td.noage {
+ color: #808080;
+ font-style: italic;
+}
+
+/* age2: 60*60*24*2 <= age */
+table.project_list td.age2, table.blame td.age2 {
+ font-style: italic;
+}
+
+/* age1: 60*60*2 <= age < 60*60*24*2 */
+table.project_list td.age1 {
+ color: #009900;
+ font-style: italic;
+}
+
+table.blame td.age1 {
+ color: #009900;
+ background: transparent;
+}
+
+/* age0: age < 60*60*2 */
+table.project_list td.age0 {
+ color: #009900;
+ font-style: italic;
+ font-weight: bold;
+}
+
+table.blame td.age0 {
+ color: #009900;
+ background: transparent;
+ font-weight: bold;
+}
+
+td.pre, div.pre, div.diff {
+ white-space: pre;
+}
+
+td.mode {
+ font-family: monospace;
+}
+
+/* styling of diffs (patchsets): commitdiff and blobdiff views */
+
+div.diff.header,
+div.diff.extended_header {
+ white-space: normal;
+}
+
+div.diff.header {
+ font-weight: bold;
+
+ background-color: #333333;
+
+ margin-top: 4px;
+ padding: 4px 0px 2px 0px;
+ border: solid #d9d8d1;
+ border-width: 1px 0px 1px 0px;
+}
+
+div.diff.header a.path {
+ text-decoration: underline;
+}
+
+div.diff.extended_header,
+div.diff.extended_header a.path,
+div.diff.extended_header a.hash {
+ color: #cccccc;
+}
+
+div.diff.extended_header .info {
+ color: #b0b0b0;
+}
+
+div.diff.extended_header {
+ background-color: #333333;
+ padding: 2px 0px 2px 0px;
+}
+
+div.diff a.list,
+div.diff a.path,
+div.diff a.hash {
+ text-decoration: none;
+}
+
+div.diff a.list:hover,
+div.diff a.path:hover,
+div.diff a.hash:hover {
+ text-decoration: underline;
+}
+
+div.diff.to_file a.path,
+div.diff.to_file {
+ color: #007000;
+}
+
+div.diff.add {
+ color: #008800;
+}
+
+div.diff.from_file a.path,
+div.diff.from_file {
+ color: #ff0000;
+}
+
+div.diff.rem {
+ color: #cc0000;
+}
+
+div.diff.chunk_header a,
+div.diff.chunk_header {
+ color: #990099;
+}
+
+div.diff.chunk_header {
+ border: dotted #ffe0ff;
+ border-width: 1px 0px 0px 0px;
+ margin-top: 2px;
+}
+
+div.diff.chunk_header span.chunk_info {
+ background-color: #000000;
+}
+
+div.diff.chunk_header span.section {
+ color: #aa22aa;
+}
+
+div.diff.incomplete {
+ color: #cccccc;
+}
+
+div.diff.nodifferences {
+ font-weight: bold;
+ color: #600000;
+}
+
+div.index_include {
+ border: solid #d9d8d1;
+ border-width: 0px 0px 1px;
+ padding: 12px 8px;
+}
+
+div.search {
+ font-size: 100%;
+ font-weight: normal;
+ margin: 4px 8px;
+ float: right;
+ top: 56px;
+ right: 12px
+}
+
+td.linenr {
+ text-align: right;
+}
+
+a.linenr {
+ color: #999999;
+ text-decoration: none
+}
+
+a.rss_logo {
+ float: right;
+ padding: 3px 0px;
+ width: 35px;
+ line-height: 10px;
+ border: 1px solid;
+ border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
+ color: #ffffff;
+ background-color: #ff6600;
+ font-weight: bold;
+ font-family: sans-serif;
+ font-size: 70%;
+ text-align: center;
+ text-decoration: none;
+}
+
+a.rss_logo:hover {
+ background-color: #ee5500;
+}
+
+span.refs span {
+ padding: 0px 4px;
+ font-size: 70%;
+ font-weight: normal;
+ border: 1px solid;
+ background-color: #222222;
+ border-color: #ffccff #ff00ee #ff00ee #ffccff;
+}
+
+span.refs span.ref {
+ background-color: #aaaaff;
+ border-color: #ccccff #0033cc #0033cc #ccccff;
+}
+
+span.refs span.tag {
+ background-color: #ffffaa;
+ border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
+}
+
+span.refs span.head {
+ background-color: #222222;
+ border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
+}
+
+span.atnight {
+ color: #cc0000;
+}
+
+span.match {
+ color: #e00000;
+}
+
+div.binary {
+ font-style: italic;
+}
| | | |