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 + paraslash - -

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
+ + paraslash +
-

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
+ + paraslash +
-

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; +}