]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge topic branch t/sf_float into pu pu
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 26 May 2024 16:37:34 +0000 (18:37 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 26 May 2024 16:37:34 +0000 (18:37 +0200)
A single patch which adds two new sample formats for 32 bit IEEE
float waveform data.

<!--

- The alsa writer also supports 32 bit float sample formats.

-->

* refs/heads/t/sf_float:
  New audio formats: 32 bit float (little and big endian).

54 files changed:
INSTALL
Makefile.in
Makefile.real
README
aacdec_filter.c
afh_recv.c
afs.c
aft.c
audioc.c
audiod.c
audiod.h
buffer_tree.c
buffer_tree.h
check_wav.c
client.c
client_common.c
command.c
configure.ac
crypt.h
error.h
exec.c
file_write.c
filter.c
filter_common.c
flacdec_filter.c
gcrypt.c
gui.c
interactive.c
ipc.c
list.h
lsu.c
m4/lls/server_cmd.suite.m4
mixer.c
mp3dec_filter.c
mp4.c
oggdec_filter.c
openssl.c
opusdec_filter.c
play.c
resample_filter.c
server.c
spxdec_filter.c
string.c
string.h
t/makefile.test
t/t0005-man.sh
upgrade_db.c
web/about.in.html
web/download.in.html
web/images/signature.png
web/images/tar-icon.png
web/manual.md
web/para.css
wmadec_filter.c

diff --git a/INSTALL b/INSTALL
index 45676b7ea44d0bb5cfc854272bdcbd5cf7a2e3a0..cabeb10ff0976c007003eb46222c883ce1b7b4b5 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -2,15 +2,15 @@ Any knowledge of how to work with mouse and icons is not required.
 
 Installing lopsub
 ~~~~~~~~~~~~~~~~~
-       git clone git://git.tuebingen.mpg.de/lopsub
+       git clone https://git.tuebingen.mpg.de/lopsub
        cd lopsub && make && sudo make install
-       (see http://people.tuebingen.mpg.de/maan/lopsub/)
+       (see https://people.tuebingen.mpg.de/maan/lopsub/)
 
 Installing osl
 ~~~~~~~~~~~~~~
-       git clone git://git.tuebingen.mpg.de/osl
+       git clone https://git.tuebingen.mpg.de/osl
        cd osl && make && sudo make install
-       (see http://people.tuebingen.mpg.de/maan/osl/)
+       (see https://people.tuebingen.mpg.de/maan/osl/)
 
 Installing paraslash from tarball
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -37,4 +37,4 @@ Example for cross-compiling
 
 For details see the user manual:
 
-       http://people.tuebingen.mpg.de/maan/paraslash/manual.html
+       https://people.tuebingen.mpg.de/maan/paraslash/manual.html
index c618561d4dfeb18ebeb31f93a90ac69e32f84c63..396c8de6b98acbf0fdd9b9d42fe63a72316f2352 100644 (file)
@@ -12,21 +12,26 @@ FLEX := @FLEX@
 BISON := @BISON@
 M4 := @M4@
 LOPSUBGEN := @LOPSUBGEN@
+CRYPTOLIB := @CRYPTOLIB@
 
-executables := @executables@
+NEED_OGG_OBJECTS := @NEED_OGG_OBJECTS@
+NEED_VORBIS_OBJECTS := @NEED_VORBIS_OBJECTS@
+NEED_SPEEX_OBJECTS := @NEED_SPEEX_OBJECTS@
+NEED_OPUS_OBJECTS := @NEED_OPUS_OBJECTS@
+NEED_FLAC_OBJECTS := @NEED_FLAC_OBJECTS@
+NEED_AO_OBJECTS := @NEED_AO_OBJECTS@
 
-recv_objs := @recv_objs@
-filter_objs := @filter_objs@
-client_objs := @client_objs@
-gui_objs := @gui_objs@
-audiod_objs := @audiod_objs@
-audioc_objs := @audioc_objs@
-mixer_objs := @mixer_objs@
-server_objs := @server_objs@
-upgrade_db_objs := @upgrade_db_objs@
-write_objs := @write_objs@
-afh_objs := @afh_objs@
-play_objs := @play_objs@
+HAVE_OSL := @HAVE_OSL@
+HAVE_FAAD := @HAVE_FAAD@
+HAVE_READLINE := @HAVE_READLINE@
+HAVE_FLAC := @HAVE_FLAC@
+HAVE_MAD := @HAVE_MAD@
+HAVE_SAMPLERATE := @HAVE_SAMPLERATE@
+HAVE_AO := @HAVE_AO@
+HAVE_PTHREAD := @HAVE_PTHREAD@
+HAVE_OSS := @HAVE_OSS@
+HAVE_ALSA := @HAVE_ALSA@
+HAVE_CURSES := @HAVE_CURSES@
 
 speex_cppflags := @speex_cppflags@
 opus_cppflags := @opus_cppflags@
index bd2bd9d95fe8356f09e756268340f2f4cad52706..fec328a6adbe8be0e8d2d18ae9d0bc3740a10499 100644 (file)
@@ -14,7 +14,6 @@ SEVERITIES := \"debug\",\"info\",\"notice\",\"warning\",\"error\",\"crit\",\"eme
 vardir := /var/paraslash
 mandir := $(datarootdir)/man/man1
 MKDIR_P := mkdir -p
-prefixed_executables := $(addprefix para_, $(executables))
 
 build_date := $(shell date)
 uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS")
@@ -35,15 +34,263 @@ m4depdir := $(build_dir)/m4deps
 lls_suite_dir := $(build_dir)/lls
 lls_m4_dir := m4/lls
 test_dir := t
-yy_src_dir = yy
-yy_build_dir = $(build_dir)/yy
+yy_src_dir := yy
+yy_build_dir := $(build_dir)/yy
+
+executables := recv filter audioc write afh
+ifneq ($(CRYPTOLIB),)
+       ifeq ($(HAVE_OSL),yes)
+       executables += server upgrade_db
+               server_objs := $(addsuffix .o, \
+                       server afh_common mp3_afh vss command net string \
+                       signal time daemon http_send close_on_fork \
+                       crypt_common base64 ipc dccp_send fd user_list \
+                       chunk_queue afs aft mood mp score attribute blob \
+                       playlist sched acl send_common udp_send color fec \
+                       wma_afh wma_common sideband version lsu \
+               )
+               ifeq ($(CRYPTOLIB),openssl)
+                       server_objs += openssl.o
+               else
+                       server_objs += gcrypt.o
+               endif
+               ifeq ($(NEED_OGG_OBJECTS),yes)
+                       server_objs += ogg_afh_common.o
+               endif
+               ifeq ($(NEED_VORBIS_OBJECTS),yes)
+                       server_objs += ogg_afh.o
+               endif
+               ifeq ($(NEED_SPEEX_OBJECTS),yes)
+                       server_objs += spx_afh.o spx_common.o
+               endif
+               ifeq ($(NEED_OPUS_OBJECTS),yes)
+                       server_objs += opus_afh.o opus_common.o
+               endif
+               ifeq ($(NEED_FLAC_OBJECTS),yes)
+                       server_objs += flac_afh.o
+               endif
+               ifeq ($(HAVE_FAAD),yes)
+                       server_objs += aac_afh.o mp4.o
+               endif
+               upgrade_db_objs := $(addsuffix .o, crypt_common exec fd string \
+                       upgrade_db version base64)
+       endif
+endif
+ifneq ($(CRYPTOLIB),)
+       executables += client audiod
+       client_objs := $(addsuffix .o, \
+               client net string fd lsu sched stdin stdout time sideband client_common \
+               buffer_tree crypt_common base64 version $(CRYPTOLIB) \
+       )
+       ifeq ($(HAVE_READLINE),yes)
+               client_objs += interactive.o
+       endif
+       audiod_objs := $(addsuffix .o, \
+               audiod signal string daemon stat net crypt_common base64 sideband \
+               time grab_client filter_common wav_filter compress_filter amp_filter \
+               http_recv dccp_recv recv_common fd sched write_common file_write \
+               audiod_command fecdec_filter client_common udp_recv color fec \
+               prebuffer_filter version bitstream imdct wma_common wmadec_filter \
+               buffer_tree sync_filter lsu $(CRYPTOLIB) \
+       )
+       audiod_audio_formats := "wma"
+       ifeq ($(NEED_VORBIS_OBJECTS),yes)
+               audiod_objs += oggdec_filter.o
+               audiod_audio_formats += ,"ogg"
+       endif
+       ifeq ($(NEED_SPEEX_OBJECTS),yes)
+               audiod_objs += spxdec_filter.o spx_common.o
+               audiod_audio_formats += ,"spx"
+       endif
+       ifeq ($(NEED_OPUS_OBJECTS),yes)
+               audiod_objs += opusdec_filter.o opus_common.o
+               audiod_audio_formats += ,"opus"
+       endif
+       ifeq ($(NEED_FLAC_OBJECTS),yes)
+               audiod_objs += flacdec_filter.o
+               audiod_audio_formats += ,"flac"
+       endif
+       ifeq ($(HAVE_FAAD),yes)
+               audiod_objs += aacdec_filter.o
+               audiod_audio_formats += ,"aac"
+       endif
+       ifeq ($(HAVE_MAD),yes)
+               audiod_objs += mp3dec_filter.o
+               audiod_audio_formats += ,"mp3"
+       endif
+       ifeq ($(HAVE_OSS),yes)
+               audiod_objs += oss_write.o
+       endif
+       ifeq ($(HAVE_ALSA),yes)
+               audiod_objs += alsa_write.o
+       endif
+       ifeq ($(NEED_AO_OBJECTS),yes)
+               audiod_objs += ao_write.o
+       endif
+       ifeq ($(HAVE_SAMPLERATE),yes)
+               audiod_objs += resample_filter.o check_wav.o
+       endif
+endif
+ifneq ($(HAVE_OSS)-$(HAVE_ALSA),no-no)
+       executables += mixer
+       mixer_objs := $(addsuffix .o, mixer exec string fd time lsu version)
+       ifeq ($(HAVE_OSS),yes)
+               mixer_objs += oss_mix.o
+       endif
+       ifeq ($(HAVE_ALSA),yes)
+               mixer_objs += alsa_mix.o
+       endif
+endif
+ifeq ($(HAVE_CURSES),yes)
+       executables += gui
+       gui_objs := $(addsuffix .o, exec signal string stat ringbuffer fd \
+               gui gui_theme lsu time sched version)
+endif
+filter_objs := $(addsuffix .o, \
+       filter_common wav_filter compress_filter filter string stdin stdout \
+       sched fd amp_filter fecdec_filter fec lsu version prebuffer_filter \
+       time bitstream imdct wma_common wmadec_filter buffer_tree net \
+       sync_filter \
+)
+ifeq ($(NEED_VORBIS_OBJECTS),yes)
+       filter_objs += oggdec_filter.o
+endif
+ifeq ($(NEED_SPEEX_OBJECTS),yes)
+       filter_objs += spxdec_filter.o spx_common.o
+endif
+ifeq ($(NEED_OPUS_OBJECTS),yes)
+       filter_objs += opusdec_filter.o opus_common.o
+endif
+ifeq ($(NEED_FLAC_OBJECTS),yes)
+       filter_objs += flacdec_filter.o
+endif
+ifeq ($(HAVE_FAAD),yes)
+       filter_objs += aacdec_filter.o
+endif
+ifeq ($(HAVE_MAD),yes)
+       filter_objs += mp3dec_filter.o
+endif
+ifeq ($(HAVE_SAMPLERATE),yes)
+       filter_objs += resample_filter.o check_wav.o
+endif
+
+recv_objs := $(addsuffix .o, \
+       http_recv recv_common recv time string net dccp_recv fd sched stdout \
+       udp_recv buffer_tree afh_recv afh_common wma_afh wma_common mp3_afh \
+       version \
+)
+ifeq ($(NEED_OGG_OBJECTS),yes)
+       recv_objs += ogg_afh_common.o
+endif
+ifeq ($(NEED_VORBIS_OBJECTS),yes)
+       recv_objs += ogg_afh.o
+endif
+ifeq ($(NEED_SPEEX_OBJECTS),yes)
+       recv_objs += spx_afh.o spx_common.o
+endif
+ifeq ($(NEED_OPUS_OBJECTS),yes)
+       recv_objs += opus_afh.o opus_common.o
+endif
+ifeq ($(NEED_FLAC_OBJECTS),yes)
+       recv_objs += flac_afh.o
+endif
+ifeq ($(HAVE_FAAD),yes)
+       recv_objs += aac_afh.o mp4.o
+endif
+
+audio_format_handlers := mp3 wma
+afh_objs := $(addsuffix .o, afh string fd mp3_afh afh_common time wma_afh \
+       wma_common version)
+ifeq ($(NEED_OGG_OBJECTS),yes)
+       afh_objs += ogg_afh_common.o
+endif
+ifeq ($(NEED_VORBIS_OBJECTS),yes)
+       afh_objs += ogg_afh.o
+       audio_format_handlers += ogg
+endif
+ifeq ($(NEED_SPEEX_OBJECTS),yes)
+       afh_objs += spx_common.o
+       audio_format_handlers += spx
+endif
+ifeq ($(NEED_OPUS_OBJECTS),yes)
+       afh_objs += opus_afh.o opus_common.o
+       audio_format_handlers += opus
+endif
+ifeq ($(NEED_FLAC_OBJECTS),yes)
+       afh_objs += flac_afh.o
+       audio_format_handlers += flac
+endif
+ifeq ($(HAVE_FAAD),yes)
+       afh_objs += aac_afh.o mp4.o
+       audio_format_handlers += aac
+endif
+
+ifeq ($(HAVE_READLINE),yes)
+       executables += play
+       play_objs := $(addsuffix .o, \
+               play fd sched buffer_tree time string net afh_recv afh_common \
+               wma_afh wma_common mp3_afh recv_common udp_recv http_recv dccp_recv \
+               filter_common fec bitstream imdct wav_filter compress_filter \
+               amp_filter prebuffer_filter fecdec_filter wmadec_filter write_common \
+               file_write version sync_filter lsu interactive \
+       )
+       ifeq ($(NEED_OGG_OBJECTS),yes)
+               play_objs += ogg_afh_common.o
+       endif
+       ifeq ($(NEED_VORBIS_OBJECTS),yes)
+               play_objs += oggdec_filter.o ogg_afh.o
+       endif
+       ifeq ($(NEED_SPEEX_OBJECTS),yes)
+               play_objs += spxdec_filter.o spx_afh.o spx_common.o
+       endif
+       ifeq ($(NEED_OPUS_OBJECTS),yes)
+               play_objs += opusdec_filter.o opus_afh.o opus_common.o
+       endif
+       ifeq ($(NEED_FLAC_OBJECTS),yes)
+               play_objs += flacdec_filter.o flac_afh.o
+       endif
+       ifeq ($(HAVE_FAAD),yes)
+               play_objs += aac_afh.o aacdec_filter.o mp4.o
+       endif
+       ifeq ($(HAVE_MAD),yes)
+               play_objs += mp3dec_filter.o
+       endif
+       ifeq ($(HAVE_OSS),yes)
+               play_objs += oss_write.o
+       endif
+       ifeq ($(HAVE_ALSA),yes)
+               play_objs += alsa_write.o
+       endif
+       ifeq ($(NEED_AO_OBJECTS),yes)
+               play_objs += ao_write.o
+       endif
+       ifeq ($(HAVE_SAMPLERATE),yes)
+               play_objs += resample_filter.o check_wav.o
+       endif
+endif
+
+write_objs := $(addsuffix .o, write write_common file_write time fd \
+       string sched stdin buffer_tree check_wav version)
+ifeq ($(NEED_AO_OBJECTS),yes)
+       write_objs += ao_write.o
+endif
+ifeq ($(HAVE_OSS),yes)
+       write_objs += oss_write.o
+endif
+ifeq ($(HAVE_ALSA),yes)
+       write_objs += alsa_write.o
+endif
+
+audioc_objs := $(addsuffix .o, audioc string lsu net fd time version)
+ifeq ($(HAVE_READLINE),yes)
+       audioc_objs += buffer_tree.o interactive.o sched.o
+endif
 
 # sort removes duplicate words, which is all we need here
-all_objs := $(sort $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \
+dep_objs := $(sort $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \
        $(audiod_objs) $(audioc_objs) $(mixer_objs) $(server_objs) \
-       $(write_objs) $(afh_objs) $(play_objs))
-deps := $(addprefix $(dep_dir)/, $(all_objs:.o=.d))
-deps += $(addprefix $(dep_dir)/, mp.bison.d mp.flex.d)
+       $(write_objs) $(afh_objs) $(play_objs) mp.bison mp.flex)
+deps := $(addprefix $(dep_dir)/, $(dep_objs:.o=.d))
 
 afh_objs += afh.lsg.o
 audioc_objs += audioc.lsg.o
@@ -84,6 +331,7 @@ write_objs := $(addprefix $(object_dir)/, $(write_objs))
 afh_objs := $(addprefix $(object_dir)/, $(afh_objs))
 play_objs := $(addprefix $(object_dir)/, $(play_objs))
 
+prefixed_executables := $(addprefix para_, $(executables))
 man_pages := $(patsubst %, $(man_dir)/%.1, $(prefixed_executables))
 
 autocrap := config.h.in configure
@@ -200,6 +448,10 @@ $(object_dir)/%.o: %.c | $(object_dir)
 OD = $(addsuffix .d, $(addprefix $(dep_dir)/, $(1))) \
        $(addsuffix .o, $(addprefix $(object_dir)/, $(1)))
 
+$(call OD, audiod): \
+       CPPFLAGS += -DAUDIOD_AUDIO_FORMAT_ARRAY='$(audiod_audio_formats)'
+$(call OD, afh command): \
+       CPPFLAGS += -DAUDIO_FORMAT_HANDLERS='"$(audio_format_handlers)"'
 $(call OD, opus%): CPPFLAGS += $(opus_cppflags)
 $(call OD, gui gui%): CPPFLAGS += $(curses_cppflags)
 $(call OD, spx%): CPPFLAGS += $(speex_cppflags)
@@ -223,7 +475,6 @@ $(call OD, afs aft attribute blob mood playlist score server vss command \
        CPPFLAGS += $(osl_cppflags)
 
 $(call OD, compress_filter): CFLAGS += -O3
-$(call OD, openssl): CFLAGS += -Wno-deprecated-declarations
 
 $(object_dir)/%.o: %.c | $(object_dir) $(dep_dir) $(lsg_h) $(yy_h)
 define CC_CMD
diff --git a/README b/README
index d8a545fc7abd744e6df57c51638dee607574e69e..510c7e1fd033e6898aa6ca7b96a673797e3d6bff 100644 (file)
--- a/README
+++ b/README
@@ -5,9 +5,9 @@ audio files. See the user manual for details.
 Distribution of paraslash is covered by the GNU GPL, version 2 unless
 otherwise stated. See file COPYING.
 
-Web page:             http://people.tuebingen.mpg.de/maan/paraslash/
-Gitweb:               http://git.tuebingen.mpg.de/paraslash.git/
-Git URL:              git://git.tuebingen.mpg.de/paraslash.git
+Web page:             https://people.tuebingen.mpg.de/maan/paraslash/
+Gitweb:               https://git.tuebingen.mpg.de/paraslash.git/
+Git URL:              https://git.tuebingen.mpg.de/paraslash.git
 Email:                Andre Noll <maan@tuebingen.mpg.de>
 
 Comments and bug reports are welcome.
index 87a7900af3ee9b43e1a661d66cdd54d1625b0952..ab07be8f18f2377f17cddf1668ca02f02cb407c2 100644 (file)
@@ -41,7 +41,8 @@ struct private_aacdec_data {
        unsigned int sample_rate;
 };
 
-static int aacdec_execute(struct btr_node *btrn, const char *cmd, char **result)
+static int aacdec_execute(const struct btr_node *btrn, const char *cmd,
+               char **result)
 {
        struct filter_node *fn = btr_context(btrn);
        struct private_aacdec_data *padd = fn->private_data;
index 8449e787f96fa24b60c2c3af9ec5218eb264ff53..687b77d9ecc385aa433cd90d8e027ffb110c135d 100644 (file)
@@ -30,7 +30,7 @@ struct private_afh_recv_data {
        void *afh_context;
 };
 
-static int afh_execute(struct btr_node *btrn, const char *cmd, char **result)
+static int afh_execute(const struct btr_node *btrn, const char *cmd, char **result)
 {
        struct receiver_node *rn = btr_context(btrn);
        struct private_afh_recv_data *pard = rn->private_data;
diff --git a/afs.c b/afs.c
index 445d5871097b79cdcd14170c2a1f59998354dc98..b41d00b6b5b2e1cb290ab45af74a6cf46923d5a6 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -568,14 +568,9 @@ static void close_afs_tables(void)
 static void get_database_dir(void)
 {
        if (!database_dir) {
-               if (OPT_GIVEN(AFS_DATABASE_DIR))
-                       database_dir = para_strdup(OPT_STRING_VAL(AFS_DATABASE_DIR));
-               else {
-                       char *home = para_homedir();
-                       database_dir = make_message(
-                               "%s/.paraslash/afs_database-0.7", home);
-                       free(home);
-               }
+               database_dir = OPT_GIVEN(AFS_DATABASE_DIR)?
+                       para_strdup(OPT_STRING_VAL(AFS_DATABASE_DIR)) :
+                       make_message("%s/afs_database-0.7", get_confdir());
        }
        PARA_INFO_LOG("afs_database dir %s\n", database_dir);
 }
diff --git a/aft.c b/aft.c
index f1aca7fb8ccc3e31575303a4762d6a7ea35a054f..2fab49b5c627b65635a02259df144e7ac9ade0c6 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -1475,11 +1475,15 @@ static int com_ls(struct command_context *cc, struct lls_parse_result *lpr)
                        opts->mode = LS_MODE_SHORT;
                else if (!strcmp(val, "v") || !strcmp(val, "verbose"))
                        opts->mode = LS_MODE_VERBOSE;
-               else if (!strcmp(val, "m") || !strcmp(val, "mbox"))
+               else if (!strcmp(val, "m") || !strcmp(val, "mbox")) {
+                       send_sb_va(&cc->scc, SBD_WARNING_LOG,
+                               "Warning: mbox listing mode is deprecated\n");
                        opts->mode = LS_MODE_MBOX;
-               else if (!strcmp(val, "c") || !strcmp(val, "chunk-table"))
+               } else if (!strcmp(val, "c") || !strcmp(val, "chunk-table")) {
+                       send_sb_va(&cc->scc, SBD_WARNING_LOG,
+                               "Warning: chunk table listing mode is deprecated\n");
                        opts->mode = LS_MODE_CHUNKS;
-               else if (!strcmp(val, "p") || !strcmp(val, "parser-friendly"))
+               else if (!strcmp(val, "p") || !strcmp(val, "parser-friendly"))
                        opts->mode = LS_MODE_PARSER;
                else {
                        ret = -ERRNO_TO_PARA_ERROR(EINVAL);
index f2e4cb91de228dcd78cae534e08d76e8514b6d88..83b1930c732ef1fbecfefb6441672eee5fafad80 100644 (file)
--- a/audioc.c
+++ b/audioc.c
@@ -231,7 +231,6 @@ close:
 __noreturn static void interactive_session(void)
 {
        int ret;
-       char *history_file;
        struct sigaction act;
        struct i9e_client_info ici = {
                .fds = {0, 1, 2},
@@ -242,16 +241,9 @@ __noreturn static void interactive_session(void)
        };
 
        PARA_NOTICE_LOG("\n%s\n", version_text("audioc"));
-       if (OPT_GIVEN(HISTORY_FILE))
-               history_file = para_strdup(OPT_STRING_VAL(HISTORY_FILE));
-       else {
-               char *home = para_homedir();
-               history_file = make_message("%s/.paraslash/audioc.history",
-                       home);
-               free(home);
-       }
-       ici.history_file = history_file;
-
+       ici.history_file = OPT_GIVEN(HISTORY_FILE)?
+               para_strdup(OPT_STRING_VAL(HISTORY_FILE)) :
+               make_message("%s/audioc.history", get_confdir());
        act.sa_handler = i9e_signal_dispatch;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
@@ -268,7 +260,7 @@ __noreturn static void interactive_session(void)
        i9e_close();
        para_log = stderr_log;
 out:
-       free(history_file);
+       free(ici.history_file);
        free(socket_name);
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
index 7c223995a9a29cec3c8e8ae5497c3be58655f63c..a03a4bda9c9b06ebd9202be7e01948600e15d36a 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -46,8 +46,9 @@ static struct lls_parse_result *lpr;
 #define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name)))
 
 __printf_2_3 void (*para_log)(int, const char*, ...) = daemon_log;
-/** define the array containing all supported audio formats */
-const char *audio_formats[] = {AUDIOD_AUDIO_FORMAT_ARRAY NULL};
+/* Audio formats supported by audiod */
+static const char *audio_formats[] = {AUDIOD_AUDIO_FORMAT_ARRAY};
+#define NUM_AUDIO_FORMATS ARRAY_SIZE(audio_formats)
 
 /** Defines how audiod handles one supported audio format. */
 struct audio_format_info {
@@ -828,11 +829,14 @@ static int parse_stream_command(const char *txt, const char **cmd)
 static int add_filter(int format, const char *cmdline)
 {
        struct audio_format_info *a = &afi[format];
-       int filter_num, nf = a->num_filters;
+       int ret, filter_num, nf = a->num_filters;
        void *cfg;
        struct lls_parse_result *flpr;
 
-       filter_num = filter_setup(cmdline, &cfg, &flpr);
+       ret = filter_setup(cmdline, &cfg, &flpr);
+       if (ret < 0)
+               return ret;
+       filter_num = ret;
        a->filter_lpr = arr_realloc(a->filter_lpr, nf + 1, sizeof(flpr));
        a->filter_conf = arr_realloc(a->filter_conf, nf + 1, sizeof(void *));
        a->filter_nums = arr_realloc(a->filter_nums, nf + 1, sizeof(unsigned));
@@ -1517,5 +1521,6 @@ out:
                PARA_ERROR_LOG("%s\n", errctx);
        if (ret < 0)
                PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+       free(get_confdir());
        return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 39beda1bd4223d145fb327f07be4c5e5d4845d94..d5a9da65fde12fb303ddf55958f46a8cff124f12 100644 (file)
--- a/audiod.h
+++ b/audiod.h
@@ -2,13 +2,6 @@
 
 /** \file audiod.h Symbols exported from audiod.c. */
 
-
-/** enum of audio formats supported by para_audiod */
-enum {AUDIOD_AUDIO_FORMATS_ENUM};
-
-/** array of audio format names supported by para_audiod */
-extern const char *audio_formats[];
-
 extern int audiod_status;
 
 /* defined in audiod.c */
index 35353f56c9f69cb99be6bb6a319f680876d4a9cc..255dc47531e9d94ebe32046ea85a0ece5be3b888 100644 (file)
@@ -103,12 +103,12 @@ void btr_pool_free(struct btr_pool *btrp)
  * \return The same value which was passed during creation time to
  * btr_pool_new().
  */
-size_t btr_pool_size(struct btr_pool *btrp)
+size_t btr_pool_size(const struct btr_pool *btrp)
 {
        return btrp->area_end - btrp->area_start;
 }
 
-static size_t btr_pool_filled(struct btr_pool *btrp)
+static size_t btr_pool_filled(const struct btr_pool *btrp)
 {
        if (!btrp->whead)
                return btr_pool_size(btrp);
@@ -129,7 +129,7 @@ static size_t btr_pool_filled(struct btr_pool *btrp)
  * the largest contiguous buffer that can currently be allocated from the
  * buffer pool.
  */
-size_t btr_pool_unused(struct btr_pool *btrp)
+size_t btr_pool_unused(const struct btr_pool *btrp)
 {
        return btr_pool_size(btrp) - btr_pool_filled(btrp);
 }
@@ -138,7 +138,7 @@ size_t btr_pool_unused(struct btr_pool *btrp)
  * Return maximal size available for one read. This is
  * smaller than the value returned by btr_pool_unused().
  */
-static size_t btr_pool_available(struct btr_pool *btrp)
+static size_t btr_pool_available(const struct btr_pool *btrp)
 {
        if (!btrp->whead)
                return 0;
@@ -156,7 +156,7 @@ static size_t btr_pool_available(struct btr_pool *btrp)
  * \return The maximal amount of bytes that may be written to the returned
  * buffer.
  */
-size_t btr_pool_get_buffer(struct btr_pool *btrp, char **result)
+size_t btr_pool_get_buffer(const struct btr_pool *btrp, char **result)
 {
        if (result)
                *result = btrp->whead;
@@ -174,7 +174,7 @@ size_t btr_pool_get_buffer(struct btr_pool *btrp, char **result)
  * consists of two buffers. If this function returns the value n, then n
  * elements of \a iov are initialized.
  */
-int btr_pool_get_buffers(struct btr_pool *btrp, struct iovec iov[2])
+int btr_pool_get_buffers(const struct btr_pool *btrp, struct iovec iov[2])
 {
        size_t sz, unused;
        char *buf;
@@ -322,7 +322,7 @@ static void dealloc_buffer(struct btr_buffer *btrb)
                free(btrb->buf);
 }
 
-static struct btr_buffer_reference *get_first_input_br(struct btr_node *btrn)
+static struct btr_buffer_reference *get_first_input_br(const struct btr_node *btrn)
 {
        if (list_empty(&btrn->input_queue))
                return NULL;
@@ -330,6 +330,14 @@ static struct btr_buffer_reference *get_first_input_br(struct btr_node *btrn)
                struct btr_buffer_reference, node);
 }
 
+static struct btr_buffer_reference *get_last_input_br(const struct btr_node *btrn)
+{
+       if (list_empty(&btrn->input_queue))
+               return NULL;
+       return list_last_entry(&btrn->input_queue,
+               struct btr_buffer_reference, node);
+}
+
 /*
  * Deallocate the reference, release the resources if refcount drops to zero.
  */
@@ -346,6 +354,20 @@ static void btr_drop_buffer_reference(struct btr_buffer_reference *br)
        }
 }
 
+static bool may_merge_btrb(const struct btr_buffer *btrb,
+               const struct btr_buffer_reference *br)
+{
+       if (!br)
+               return false;
+       if (br->consumed > 0)
+               return false;
+       if (br->btrb->buf + br->btrb->size != btrb->buf)
+               return false;
+       if (!br->btrb->pool)
+               return true;
+       return br->btrb->size + btrb->size < btr_pool_size(br->btrb->pool) / 3;
+}
+
 static void add_btrb_to_children(struct btr_buffer *btrb,
                struct btr_node *btrn, size_t consumed)
 {
@@ -354,11 +376,17 @@ static void add_btrb_to_children(struct btr_buffer *btrb,
        if (btrn->start.tv_sec == 0)
                btrn->start = *now;
        FOR_EACH_CHILD(ch, btrn) {
-               struct btr_buffer_reference *br = zalloc(sizeof(*br));
-               br->btrb = btrb;
-               br->consumed = consumed;
-               list_add_tail(&br->node, &ch->input_queue);
-               btrb->refcount++;
+               struct btr_buffer_reference *br = get_last_input_br(ch);
+               if (may_merge_btrb(btrb, br)) {
+                       br->btrb->size += btrb->size;
+                       free(btrb);
+               } else {
+                       br = zalloc(sizeof(*br));
+                       br->btrb = btrb;
+                       br->consumed = consumed;
+                       list_add_tail(&br->node, &ch->input_queue);
+                       btrb->refcount++;
+               }
                if (ch->start.tv_sec == 0)
                        ch->start = *now;
        }
@@ -534,7 +562,7 @@ void btr_pushdown_one(struct btr_node *btrn)
  *
  * \return True if this node has no children. False otherwise.
  */
-static bool btr_no_children(struct btr_node *btrn)
+static bool btr_no_children(const struct btr_node *btrn)
 {
        return list_empty(&btrn->children);
 }
@@ -551,7 +579,7 @@ static bool btr_no_children(struct btr_node *btrn)
  * 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)
+bool btr_no_parent(const struct btr_node *btrn)
 {
        return !btrn->parent;
 }
@@ -574,7 +602,7 @@ bool btr_no_parent(struct btr_node *btrn)
  *
  * \return True if \a btrn has no siblings.
  */
-bool btr_inplace_ok(struct btr_node *btrn)
+bool btr_inplace_ok(const struct btr_node *btrn)
 {
        struct btr_buffer_reference *br;
        FOR_EACH_BUFFER_REF(br, btrn) {
@@ -587,12 +615,13 @@ bool btr_inplace_ok(struct btr_node *btrn)
        return true;
 }
 
-static inline size_t br_available_bytes(struct btr_buffer_reference *br)
+static inline size_t br_available_bytes(const struct btr_buffer_reference *br)
 {
        return br->btrb->size - br->consumed;
 }
 
-static size_t btr_get_buffer_by_reference(struct btr_buffer_reference *br, char **buf)
+static size_t btr_get_buffer_by_reference(const struct btr_buffer_reference *br,
+               char **buf)
 {
        if (buf)
                *buf = br->btrb->buf + br->consumed;
@@ -619,7 +648,8 @@ static size_t btr_get_buffer_by_reference(struct btr_buffer_reference *br, char
  * to by \a btrn, the function returns zero and the value of \a bufp is
  * undefined.
  */
-size_t btr_next_buffer_omit(struct btr_node *btrn, size_t omit, char **bufp)
+size_t btr_next_buffer_omit(const struct btr_node *btrn, size_t omit,
+               char **bufp)
 {
        struct btr_buffer_reference *br;
        size_t wrap_count, sz, rv = 0;
@@ -684,7 +714,7 @@ out:
  * The call of this function is is equivalent to calling \ref
  * btr_next_buffer_omit() with an \a omit value of zero.
  */
-size_t btr_next_buffer(struct btr_node *btrn, char **bufp)
+size_t btr_next_buffer(const struct btr_node *btrn, char **bufp)
 {
        return btr_next_buffer_omit(btrn, 0, bufp);
 }
@@ -816,7 +846,7 @@ out:
  * This simply iterates over all buffer references in the input queue and
  * returns the sum of the sizes of all references.
  */
-size_t btr_get_input_queue_size(struct btr_node *btrn)
+size_t btr_get_input_queue_size(const struct btr_node *btrn)
 {
        struct btr_buffer_reference *br;
        size_t size = 0, wrap_consumed = 0;
@@ -833,6 +863,22 @@ size_t btr_get_input_queue_size(struct btr_node *btrn)
        return size;
 }
 
+static bool min_iqs_available(size_t min_iqs, const struct btr_node *btrn)
+{
+       struct btr_buffer_reference *br;
+       size_t have = 0, wrap_consumed = 0;
+
+       FOR_EACH_BUFFER_REF(br, btrn) {
+               if (br->wrap_count != 0) {
+                       wrap_consumed = br->consumed;
+                       continue;
+               }
+               have += br_available_bytes(br);
+               if (have > wrap_consumed + min_iqs)
+                       return true;
+       }
+       return false;
+}
 /**
  * Remove a node from the buffer tree, reconnecting parent and children.
  *
@@ -875,7 +921,7 @@ void btr_splice_out_node(struct btr_node **btrnp)
  * \return This function iterates over all children of the given node and
  * returns the size of the largest input queue.
  */
-size_t btr_get_output_queue_size(struct btr_node *btrn)
+size_t btr_get_output_queue_size(const struct btr_node *btrn)
 {
        size_t max_size = 0;
        struct btr_node *ch;
@@ -903,7 +949,7 @@ size_t btr_get_output_queue_size(struct btr_node *btrn)
  *
  * \sa \ref receiver::execute, \ref filter::execute, \ref writer::execute.
  */
-int btr_exec_up(struct btr_node *btrn, const char *command, char **value_result)
+int btr_exec_up(const struct btr_node *btrn, const char *command, char **value_result)
 {
        int ret;
 
@@ -933,12 +979,12 @@ int btr_exec_up(struct btr_node *btrn, const char *command, char **value_result)
  *
  * \sa \ref btr_new_node(), struct \ref btr_node_description.
  */
-void *btr_context(struct btr_node *btrn)
+void *btr_context(const struct btr_node *btrn)
 {
        return btrn->context;
 }
 
-static bool need_buffer_pool_merge(struct btr_node *btrn)
+static bool need_buffer_pool_merge(const struct btr_node *btrn)
 {
        struct btr_buffer_reference *br = get_first_input_br(btrn);
 
@@ -1113,7 +1159,7 @@ void btr_merge(struct btr_node *btrn, size_t dest_size)
        }
 }
 
-static bool btr_eof(struct btr_node *btrn)
+static bool btr_eof(const struct btr_node *btrn)
 {
        char *buf;
        size_t len = btr_next_buffer(btrn, &buf);
@@ -1121,7 +1167,7 @@ static bool btr_eof(struct btr_node *btrn)
        return (len == 0 && btr_no_parent(btrn));
 }
 
-static void log_tree_recursively(struct btr_node *btrn, int loglevel, int depth)
+static void log_tree_recursively(const struct btr_node *btrn, int loglevel, int depth)
 {
        struct btr_node *ch;
        const char spaces[] = "                 ", *space = spaces + 16 - depth;
@@ -1139,7 +1185,7 @@ static void log_tree_recursively(struct btr_node *btrn, int loglevel, int depth)
  * \param btrn Start logging at this node.
  * \param loglevel Set severity with which the tree should be logged.
  */
-void btr_log_tree(struct btr_node *btrn, int loglevel)
+void btr_log_tree(const struct btr_node *btrn, int loglevel)
 {
        return log_tree_recursively(btrn, loglevel, 0);
 }
@@ -1199,12 +1245,9 @@ struct btr_node *btr_search_node(const char *name, struct btr_node *root)
  * btrn, the function also returns zero in order to bound the memory usage of
  * the buffer tree.
  */
-int btr_node_status(struct btr_node *btrn, size_t min_iqs,
+int btr_node_status(const struct btr_node *btrn, size_t min_iqs,
        enum btr_node_type type)
 {
-       size_t iqs;
-
-       assert(btrn);
        if (type != BTR_NT_LEAF && btr_no_children(btrn))
                return -E_BTR_NO_CHILD;
        if (type != BTR_NT_ROOT && btr_eof(btrn))
@@ -1214,12 +1257,9 @@ int btr_node_status(struct btr_node *btrn, size_t min_iqs,
                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;
+       if (min_iqs_available(min_iqs, btrn))
+               return 1;
+       return btr_no_parent(btrn);
 }
 
 /**
@@ -1230,7 +1270,7 @@ int btr_node_status(struct btr_node *btrn, size_t min_iqs,
  *
  * Mainly useful for the time display of para_audiod.
  */
-void btr_get_node_start(struct btr_node *btrn, struct timeval *tv)
+void btr_get_node_start(const struct btr_node *btrn, struct timeval *tv)
 {
        *tv = btrn->start;
 }
@@ -1245,7 +1285,7 @@ void btr_get_node_start(struct btr_node *btrn, struct timeval *tv)
  * \return The parent of \a btrn, or \p NULL if \a btrn is the
  * root node of the buffer tree.
  */
-struct btr_node *btr_parent(struct btr_node *btrn)
+struct btr_node *btr_parent(const struct btr_node *btrn)
 {
        return btrn->parent;
 }
index 34535219364a6cdc2ce32efcc04ca2d44c2c20c2..70fb3055699d3cbf6fd663b9425484f1d29d80f6 100644 (file)
@@ -3,45 +3,43 @@
 /**
  * \file buffer_tree.h Buffer tree management.
  *
- * \par Buffer trees and buffer tree nodes.
- * The buffer tree API offers a more powerful method than standard unix pipes
- * for managing the data flow from the producer of the data (e.g. the network
- * receiver) to its consumer(s) (e.g. a sound card).
+ * Buffer trees and buffer tree nodes.
  *
- * A buffer tree consists of buffer tree nodes linked via certain parent/child
- * relationships.
+ * The buffer tree API offers an efficient method for managing the data flow
+ * from a producer (e.g. the network receiver) to the consumer(s) (e.g. a sound
+ * card).
+ *
+ * A buffer tree consists of buffer tree nodes which are linked together via
+ * parent/child relationships. Data buffers are propagated down without copying.
  *
  * Each data buffer starts its way from the root of the buffer tree. At each
  * node the data is investigated and possibly changed. New data is then fed to
- * each child.  Everything happens within one single-treaded process. There are
- * no file descriptors and no calls to read() or write().
+ * each child. There are no file descriptors, no processes/threads and no calls
+ * to read() or write().
  *
  * Whenever a node in the buffer tree creates output, either by creating a new
  * buffer or by pushing down buffers received from its parent, references to
- * that buffer are created for all children of the node. The buffer tree code
- * tries hard to avoid to copy buffer contents, but is forced to do so in case
- * there are alignment constraints.
+ * that buffer are created for all children of the node. The code avoids to
+ * copy buffer contents when possible.
  *
- * Communication between nodes is possible via the btr_exec_up() function.
- * For example, in para_audiod the alsa writer asks all parent nodes
- * for for the number of channels and the sample rate of the current
- * audio file.
+ * Communication between nodes is possible via the btr_exec_up() function. For
+ * example, in para_audiod the alsa writer asks all parent nodes for the number
+ * of channels and the sample rate of the current audio file.
  *
  * Buffer pools - An alternative to malloc/free buffer management.
  *
- * Non-leaf nodes usually create output to be processed by their children.  The
- * data must be fed through the output channel(s) of the node in order to make
- * that data available to each child.
+ * Non-leaf nodes usually create output to be processed by their child nodes.
+ * The data must be fed through the output channel(s) of the node in order to
+ * make that data available to each child.
  *
  * The easiest way to do so is to malloc() a buffer, fill it, and then call
  * btr_add_output(). This adds references to that buffer to all children. The
  * buffer is automatically freed if no buffer tree node is using it any more.
  *
- * This approach, while being simple, has some drawbacks, especially affecting
- * the root nodes of the buffer tree. Often the data source which is
- * represented by a root node does not know in advance how much data will be
- * available.  Therefore the allocated buffer is either larger than what can
- * currently be read, or is too small so that multiple buffers have to be used.
+ * This approach is simple but has some drawbacks. For example the data source
+ * represented by the root node does not know in advance how much data will be
+ * available. Therefore the allocated buffer will either be larger than
+ * necessary or too small so that multiple buffers have to be used.
  *
  * While this could be worked around by using a large buffer and calling
  * realloc() afterwards to shrink the buffer according to how much has been
@@ -131,7 +129,7 @@ enum btr_node_type {
  * know the sample rate of its input known to e.g. the mp3dec node further up
  * in the buffer tree.
  */
-typedef int (*btr_command_handler)(struct btr_node *btrn,
+typedef int (*btr_command_handler)(const struct btr_node *btrn,
                const char *command, char **result);
 
 /**
@@ -166,38 +164,38 @@ struct btr_node_description {
        void *context;
 };
 
-size_t btr_pool_size(struct btr_pool *btrp);
+size_t btr_pool_size(const struct btr_pool *btrp);
 struct btr_pool *btr_pool_new(const char *name, size_t area_size);
 void btr_pool_free(struct btr_pool *btrp);
-size_t btr_pool_get_buffer(struct btr_pool *btrp, char **result);
-int btr_pool_get_buffers(struct btr_pool *btrp, struct iovec iov[2]);
+size_t btr_pool_get_buffer(const struct btr_pool *btrp, char **result);
+int btr_pool_get_buffers(const struct btr_pool *btrp, struct iovec iov[2]);
 void btr_add_output_pool(struct btr_pool *btrp, size_t size,
        struct btr_node *btrn);
-size_t btr_pool_unused(struct btr_pool *btrp);
+size_t btr_pool_unused(const struct btr_pool *btrp);
 void btr_copy(const void *src, size_t n, struct btr_pool *btrp,
        struct btr_node *btrn);
-
 struct btr_node *btr_new_node(struct btr_node_description *bnd);
 void btr_remove_node(struct btr_node **btrnp);
 void btr_add_output(char *buf, size_t size, struct btr_node *btrn);
 void btr_add_output_dont_free(const char *buf, size_t size, struct btr_node *btrn);
-size_t btr_get_input_queue_size(struct btr_node *btrn);
-size_t btr_get_output_queue_size(struct btr_node *btrn);
-bool btr_no_parent(struct btr_node *btrn);
-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);
+size_t btr_get_input_queue_size(const struct btr_node *btrn);
+size_t btr_get_output_queue_size(const struct btr_node *btrn);
+bool btr_no_parent(const struct btr_node *btrn);
+size_t btr_next_buffer(const struct btr_node *btrn, char **bufp);
+size_t btr_next_buffer_omit(const 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);
+int btr_exec_up(const struct btr_node *btrn, const char *command, char **value_result);
 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_context(const struct btr_node *btrn);
 void btr_merge(struct btr_node *btrn, size_t dest_size);
-void btr_log_tree(struct btr_node *btrn, int ll);
+void btr_log_tree(const struct btr_node *btrn, int ll);
 void btr_pushdown_one(struct btr_node *btrn);
-bool btr_inplace_ok(struct btr_node *btrn);
-int btr_node_status(struct btr_node *btrn, size_t min_iqs,
+bool btr_inplace_ok(const struct btr_node *btrn);
+int btr_node_status(const struct btr_node *btrn, size_t min_iqs,
                enum btr_node_type type);
-void btr_get_node_start(struct btr_node *btrn, struct timeval *tv);
+void btr_get_node_start(const struct btr_node *btrn, struct timeval *tv);
 struct btr_node *btr_search_node(const char *name, struct btr_node *root);
 void btr_drain(struct btr_node *btrn);
-struct btr_node *btr_parent(struct btr_node *btrn);
+struct btr_node *btr_parent(const struct btr_node *btrn);
index 821483274aba25f5f74473d2151a205c8dafee55..48a204bb598c1f9ebc873b10d64704eb256cc2de 100644 (file)
@@ -54,7 +54,7 @@ void check_wav_pre_monitor(struct sched *s, struct check_wav_context *cwc)
                sched_min_delay(s);
 }
 
-static int check_wav_exec(struct btr_node *btrn, const char *cmd, char **result)
+static int check_wav_exec(const struct btr_node *btrn, const char *cmd, char **result)
 {
        struct check_wav_context *cwc = btr_context(btrn);
        int val, header_val, given, arg;
index 84b7580cf9554c433651da1f3eed28a6f1f39a74..661aff8fc2d9e90e0ac2b86f47d95957b69bdfa3 100644 (file)
--- a/client.c
+++ b/client.c
@@ -525,15 +525,9 @@ __noreturn static void interactive_session(void)
        };
 
        PARA_NOTICE_LOG("\n%s\n", version_text("client"));
-       if (CLIENT_OPT_GIVEN(HISTORY_FILE, ct->lpr))
-               ici.history_file = para_strdup(CLIENT_OPT_STRING_VAL(
-                       HISTORY_FILE, ct->lpr));
-       else {
-               char *home = para_homedir();
-               ici.history_file = make_message("%s/.paraslash/client.history",
-                       home);
-               free(home);
-       }
+       ici.history_file = CLIENT_OPT_GIVEN(HISTORY_FILE, ct->lpr)?
+               para_strdup(CLIENT_OPT_STRING_VAL(HISTORY_FILE, ct->lpr)) :
+               make_message("%s/client.history", get_confdir());
        act.sa_handler = i9e_signal_dispatch;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
@@ -549,6 +543,7 @@ __noreturn static void interactive_session(void)
        i9e_close();
        para_log = stderr_log;
 out:
+       free(ici.history_file);
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
        exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
@@ -680,5 +675,6 @@ out:
        client_close(ct);
        btr_remove_node(&sit.btrn);
        btr_remove_node(&sot.btrn);
+       free(get_confdir());
        return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
 }
index fe8234f98fe90f6ce74ea5e22699fbfc0059a042..cbd78bbbd6319653ef4950fe8d391922ee3aff59 100644 (file)
@@ -324,7 +324,7 @@ static int client_post_monitor(struct sched *s, void *context)
                 */
                {
                /* decrypted challenge/session key buffer */
-               unsigned char crypt_buf[1024];
+               unsigned char *crypt_buf;
                struct sb_buffer sbb;
 
                ret = recv_sb(ct, &sbb);
@@ -337,11 +337,16 @@ static int client_post_monitor(struct sched *s, void *context)
                }
                n = sbb.iov.iov_len;
                PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
-               ret = apc_priv_decrypt(ct->key_file, crypt_buf,
+               ret = apc_priv_decrypt(ct->key_file, &crypt_buf,
                        sbb.iov.iov_base, n);
                free(sbb.iov.iov_base);
                if (ret < 0)
                        goto out;
+               if (ret != APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN) {
+                       free(crypt_buf);
+                       ret = -E_DECRYPT;
+                       goto out;
+               }
                ct->challenge_hash = alloc(HASH2_SIZE);
                if (has_feature("sha256", ct)) {
                        hash2_function((char *)crypt_buf, APC_CHALLENGE_SIZE,
@@ -356,6 +361,7 @@ static int client_post_monitor(struct sched *s, void *context)
                         SESSION_KEY_LEN);
                ct->scc.recv = sc_new(crypt_buf + APC_CHALLENGE_SIZE
                        + SESSION_KEY_LEN, SESSION_KEY_LEN);
+               free(crypt_buf);
                PARA_INFO_LOG("--> %s\n", buf);
                ct->status = CL_RECEIVED_CHALLENGE;
                return 0;
@@ -559,7 +565,7 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr,
        struct lls_parse_result *lpr;
        int ret, ll;
        struct client_task *ct;
-       char *kf = NULL, *user, *errctx, *home = para_homedir();
+       char *kf = NULL, *user, *errctx;
 
        ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx));
        if (ret < 0)
@@ -582,8 +588,11 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr,
                kf = para_strdup(CLIENT_OPT_STRING_VAL(KEY_FILE, lpr));
        else {
                struct stat statbuf;
-               kf = make_message("%s/.paraslash/key.%s", home, user);
+               const char *confdir = get_confdir();
+               kf = make_message("%s/key.%s", confdir, user);
                if (stat(kf, &statbuf) != 0) { /* assume file does not exist */
+                       const char *home = getenv("HOME");
+                       assert(home); /* get_confdir() above succeeded */
                        free(kf);
                        kf = make_message("%s/.ssh/id_rsa", home);
                }
@@ -599,7 +608,6 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr,
        *ct_ptr = ct;
        ret = lls_num_inputs(lpr);
 out:
-       free(home);
        if (ret < 0) {
                if (errctx)
                        PARA_ERROR_LOG("%s\n", errctx);
index 60c2aeba4300124c51af13d03c522fe2c2bbb1f1..78c9106c9ff84062e874b326a386f7073e09aeca 100644 (file)
--- a/command.c
+++ b/command.c
 #include "signal.h"
 #include "version.h"
 
+/** \cond server_cmd_aux_info */
 #define SERVER_CMD_AUX_INFO(_arg) _arg,
 static const unsigned server_command_perms[] = {LSG_SERVER_CMD_AUX_INFOS};
 #undef SERVER_CMD_AUX_INFO
 #define SERVER_CMD_AUX_INFO(_arg) #_arg,
 static const char * const server_command_perms_txt[] = {LSG_SERVER_CMD_AUX_INFOS};
 #undef SERVER_CMD_AUX_INFO
+/** \endcond server_cmd_aux_info */
 
 /** Commands including options must be shorter than this. */
 #define MAX_COMMAND_LEN 32768
@@ -420,7 +422,8 @@ static int com_version(struct command_context *cc, struct lls_parse_result *lpr)
 }
 EXPORT_SERVER_CMD_HANDLER(version);
 
-/** These status items are cleared if no audio file is currently open. */
+/** \cond empty_status_items */
+/* These status items are cleared if no audio file is currently open. */
 #define EMPTY_STATUS_ITEMS \
        ITEM(path) \
        ITEM(directory) \
@@ -454,6 +457,8 @@ EXPORT_SERVER_CMD_HANDLER(version);
        ITEM(amplification) \
        ITEM(play_time) \
 
+/** \endcond empty_status_items */
+
 /*
  * Create a set of audio-file related status items with empty values. These are
  * written to stat clients when no audio file is open.
@@ -917,7 +922,8 @@ int handle_connect(int fd)
        int ret;
        unsigned char rand_buf[APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN];
        unsigned char challenge_hash[HASH2_SIZE];
-       char *command = NULL, *buf = alloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
+       char *command = NULL, *buf = NULL, hsbuf[HANDSHAKE_BUFSIZE];
+       unsigned char *crypt_buf;
        size_t numbytes;
        struct command_context cc_struct = {.u = NULL}, *cc = &cc_struct;
        struct iovec iov;
@@ -937,16 +943,16 @@ int handle_connect(int fd)
        if (ret < 0)
                goto net_err;
        /* recv auth request line */
-       ret = recv_buffer(fd, buf, HANDSHAKE_BUFSIZE);
+       ret = recv_buffer(fd, hsbuf, HANDSHAKE_BUFSIZE);
        if (ret < 0)
                goto net_err;
-       ret = parse_auth_request(buf, ret, &cc->u, &cf);
+       ret = parse_auth_request(hsbuf, ret, &cc->u, &cf);
        if (ret < 0)
                goto net_err;
        if (cc->u) {
                get_random_bytes_or_die(rand_buf, sizeof(rand_buf));
                ret = apc_pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf),
-                       (unsigned char *)buf);
+                       &crypt_buf);
                if (ret < 0)
                        goto net_err;
                numbytes = ret;
@@ -957,12 +963,12 @@ int handle_connect(int fd)
                 * fail the authentication later.
                 */
                numbytes = 256;
-               get_random_bytes_or_die((unsigned char *)buf, numbytes);
+               crypt_buf = alloc(numbytes);
+               get_random_bytes_or_die(crypt_buf, numbytes);
        }
        PARA_DEBUG_LOG("sending %d byte challenge + session key (%zu bytes)\n",
                APC_CHALLENGE_SIZE, numbytes);
-       ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
-       buf = NULL;
+       ret = send_sb(&cc->scc, crypt_buf, numbytes, SBD_CHALLENGE, false);
        if (ret < 0)
                goto net_err;
        ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE,
index 92560e00ec50b7fa7ae4fcfd7d8966bdca2c63bf..9e90ae5d6745d335f93b9eb3f7c8f8e44630964e 100644 (file)
@@ -1,11 +1,10 @@
 AC_PREREQ([2.61])
 
 AC_INIT([paraslash], [m4_esyscmd_s(./GIT-VERSION-GEN)],
-       [maan@tuebingen.mpg.de], [], [http://people.tuebingen.mpg.de/maan/paraslash/])
+       [maan@tuebingen.mpg.de], [], [https://people.tuebingen.mpg.de/maan/paraslash/])
 AC_CONFIG_HEADERS([config.h])
 
 AC_CONFIG_FILES([Makefile])
-AC_DEFUN([add_dot_o],[$(for i in $@; do printf "$i.o "; done)])
 AC_DEFUN([LIB_ARG_WITH], [
        AC_ARG_WITH($1-headers, [AS_HELP_STRING(--with-$1-headers=dir,
                [look for $1 headers in dir])])
@@ -38,6 +37,7 @@ AC_DEFUN([LIB_SUBST_FLAGS], [
        if test "$HAVE_[]m4_toupper([$1])" = 'yes'; then
                AC_DEFINE(HAVE_[]m4_toupper([$1]), 1,
                        define to 1 to turn on $1 support)
+               AC_SUBST(HAVE_[]m4_toupper([$1]))
        else
                $1_cppflags=
                $1_ldflags=
@@ -61,7 +61,6 @@ REQUIRE_EXECUTABLE([bison])
 REQUIRE_EXECUTABLE([flex])
 REQUIRE_EXECUTABLE([m4])
 
-executables="recv filter audioc write afh play"
 ########################################################################### osl
 STASH_FLAGS
 LIB_ARG_WITH([osl], [-losl])
@@ -82,7 +81,7 @@ if test $HAVE_LOPSUB = no; then AC_MSG_ERROR([
        The lopsub library is required to build this software, but
        the above checks indicate it is not installed on your system.
        Run the following command to download a copy.
-               git clone git://git.tuebingen.mpg.de/lopsub.git
+               git clone https://git.tuebingen.mpg.de/lopsub.git
        Install the library, then run this configure script again.
 ])
 fi
@@ -110,15 +109,10 @@ if test $HAVE_OPENSSL = yes; then
        will be removed in the next major paraslash release. Please upgrade
        your openssl installation.])
        fi
-       HAVE_CRYPTO_CLEANUP_ALL_EX_DATA=yes
-       AC_CHECK_DECL([CRYPTO_cleanup_all_ex_data], [],
-               [HAVE_CRYPTO_CLEANUP_ALL_EX_DATA=no],
-               [#include <openssl/rsa.h>])
-       AC_CHECK_LIB([crypto], [CRYPTO_cleanup_all_ex_data], [],
-               [HAVE_CRYPTO_CLEANUP_ALL_EX_DATA=no])
-       test $HAVE_CRYPTO_CLEANUP_ALL_EX_DATA = yes &&
-               AC_DEFINE([HAVE_CRYPTO_CLEANUP_ALL_EX_DATA], [1],
-                       [not available on FreeBSD 12])
+       AC_CHECK_LIB([crypto], [OSSL_PARAM_construct_BN], [HAVE_OSSL_PARAM=yes],
+               [HAVE_OSSL_PARAM=no])
+       test $HAVE_OSSL_PARAM = yes &&
+               AC_DEFINE([HAVE_OSSL_PARAM], [1], [openssl >= 3.0])
        HAVE_OPENSSL_THREAD_STOP=yes
        AC_CHECK_DECL([OPENSSL_thread_stop], [],
                [HAVE_OPENSSL_THREAD_STOP=no],
@@ -172,6 +166,7 @@ case "$enable_cryptolib" in
        ;;
 esac
 AC_SUBST(crypto_ldflags)
+AC_SUBST(CRYPTOLIB)
 ########################################################################## iconv
 STASH_FLAGS
 LIBS=
@@ -273,27 +268,26 @@ AC_CHECK_LIB([FLAC], [FLAC__stream_decoder_init_file], [], HAVE_FLAC=no)
 LIB_SUBST_FLAGS(flac)
 UNSTASH_FLAGS
 
-# some helper functions for codecs which use the ogg container format
-AC_DEFUN([NEED_OGG_OBJECTS], [{
-       test "$HAVE_OGG" = 'yes' -a \( \
+# some helpers for the ogg container format
+AS_IF([test "$HAVE_OGG" = 'yes' -a \( \
                 "$HAVE_VORBIS" = 'yes' \
                -o "$HAVE_SPEEX" = 'yes' \
                -o "$HAVE_OPUS" = 'yes' \
                -o "$HAVE_FLAC" = 'yes' \
-       \)
-}])
-AC_DEFUN([NEED_VORBIS_OBJECTS], [{
-       test "$HAVE_OGG" = 'yes' -a "$HAVE_VORBIS" = 'yes'
-}])
-AC_DEFUN([NEED_SPEEX_OBJECTS], [{
-       test "$HAVE_OGG" = 'yes' -a "$HAVE_SPEEX" = 'yes'
-}])
-AC_DEFUN([NEED_OPUS_OBJECTS], [{
-       test "$HAVE_OGG" = 'yes' -a "$HAVE_OPUS" = 'yes'
-}])
-AC_DEFUN([NEED_FLAC_OBJECTS], [{
-       test "$HAVE_OGG" = 'yes' -a "$HAVE_FLAC" = 'yes'
-}])
+\)], [NEED_OGG_OBJECTS=yes], [NEED_OGG_OBJECTS=no])
+AC_SUBST([NEED_OGG_OBJECTS])
+AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_VORBIS" = 'yes'],
+       [NEED_VORBIS_OBJECTS=yes], [NEED_VORBIS_OBJECTS=no])
+AC_SUBST([NEED_VORBIS_OBJECTS])
+AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_SPEEX" = 'yes'],
+       [NEED_SPEEX_OBJECTS=yes], [NEED_SPEEX_OBJECTS=no])
+AC_SUBST([NEED_SPEEX_OBJECTS])
+AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_OPUS" = 'yes'],
+       [NEED_OPUS_OBJECTS=yes], [NEED_OPUS_OBJECTS=no])
+AC_SUBST([NEED_OPUS_OBJECTS])
+AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_FLAC" = 'yes'],
+       [NEED_FLAC_OBJECTS=yes], [NEED_FLAC_OBJECTS=no])
+AC_SUBST([NEED_FLAC_OBJECTS])
 ########################################################################### faad
 STASH_FLAGS
 LIB_ARG_WITH([faad], [-lfaad])
@@ -349,7 +343,9 @@ AC_CHECK_HEADER(ao/ao.h, [], HAVE_AO=no)
 AC_CHECK_LIB([ao], [ao_initialize], [], HAVE_AO=no)
 LIB_SUBST_FLAGS(ao)
 UNSTASH_FLAGS
-AC_DEFUN([NEED_AO_OBJECTS], [{ test $HAVE_AO = yes -a $HAVE_PTHREAD = yes; }])
+AS_IF([test $HAVE_AO = yes -a $HAVE_PTHREAD = yes],
+       [NEED_AO_OBJECTS]=yes, [NEED_AO_OBJECTS=no])
+AC_SUBST([NEED_AO_OBJECTS])
 ######################################################################## readline
 STASH_FLAGS
 AC_SEARCH_LIBS([tgetent], [tinfo curses terminfo termcap])
@@ -381,502 +377,5 @@ AC_ARG_ENABLE([ubsan], [AS_HELP_STRING(--enable-ubsan,
        [Detect and report undefined behaviour.])],
        [ENABLE_UBSAN=yes], [ENABLE_UBSAN=no])
 AC_SUBST(ENABLE_UBSAN)
-######################################################################### server
-if test -n "$CRYPTOLIB" && test $HAVE_OSL = yes && test -n "$BISON" && \
-               test -n "$FLEX"; then
-       build_server="yes"
-       executables="$executables server upgrade_db"
-       server_errlist_objs="
-               server
-               afh_common
-               mp3_afh
-               vss
-               command
-               net
-               string
-               signal
-               time
-               daemon
-               http_send
-               close_on_fork
-               crypt_common
-               base64
-               ipc
-               dccp_send
-               fd
-               user_list
-               chunk_queue
-               afs
-               aft
-               mood
-               mp
-               score
-               attribute
-               blob
-               playlist
-               sched
-               acl
-               send_common
-               udp_send
-               color
-               fec
-               wma_afh
-               wma_common
-               sideband
-               version
-               lsu
-       "
-       if test "$CRYPTOLIB" = openssl; then
-               server_errlist_objs="$server_errlist_objs openssl"
-       else
-               server_errlist_objs="$server_errlist_objs gcrypt"
-       fi
-       NEED_OGG_OBJECTS() && server_errlist_objs="$server_errlist_objs ogg_afh_common"
-       NEED_VORBIS_OBJECTS() && server_errlist_objs="$server_errlist_objs ogg_afh"
-       NEED_SPEEX_OBJECTS() && server_errlist_objs="$server_errlist_objs spx_afh spx_common"
-       NEED_OPUS_OBJECTS() && server_errlist_objs="$server_errlist_objs opus_afh opus_common"
-       NEED_FLAC_OBJECTS && server_errlist_objs="$server_errlist_objs flac_afh"
-       if test $HAVE_FAAD = yes; then
-               server_errlist_objs="$server_errlist_objs aac_afh mp4"
-       fi
-       server_objs="$server_errlist_objs"
-       AC_SUBST(server_objs, add_dot_o($server_objs))
-else
-       build_server="no"
-fi
-############################################################# upgrade_db
-upgrade_db_objs='
-       crypt_common
-       exec
-       fd
-       string
-       upgrade_db
-       version
-       base64
-'
-AC_SUBST(upgrade_db_objs, add_dot_o($upgrade_db_objs))
-############################################################# client
-if test -n "$CRYPTOLIB"; then
-       build_client="yes"
-       executables="$executables client"
-       client_errlist_objs="
-               client
-               net
-               string
-               fd
-               lsu
-               sched
-               stdin
-               stdout
-               time
-               sideband
-               client_common
-               buffer_tree
-               crypt_common
-               base64
-               version
-       "
-       if test "$CRYPTOLIB" = openssl; then
-               client_errlist_objs="$client_errlist_objs openssl"
-       else
-               client_errlist_objs="$client_errlist_objs gcrypt"
-       fi
-       if test $HAVE_READLINE = yes; then
-               client_errlist_objs="$client_errlist_objs interactive"
-       fi
-       client_objs="$client_errlist_objs"
-       AC_SUBST(client_objs, add_dot_o($client_errlist_objs))
-else
-       build_client="no"
-fi
-############################################################# audiod
-if test -n "$CRYPTOLIB"; then
-       build_audiod="yes"
-       executables="$executables audiod"
-       audiod_audio_formats="wma"
-       audiod_errlist_objs="$audiod_errlist_objs
-               audiod
-               signal
-               string
-               daemon
-               stat
-               net
-               crypt_common
-               base64
-               sideband
-               time
-               grab_client
-               filter_common
-               wav_filter
-               compress_filter
-               amp_filter
-               http_recv
-               dccp_recv
-               recv_common
-               fd
-               sched
-               write_common
-               file_write
-               audiod_command
-               fecdec_filter
-               client_common
-               udp_recv
-               color
-               fec
-               prebuffer_filter
-               version
-               bitstream
-               imdct
-               wma_common
-               wmadec_filter
-               buffer_tree
-               sync_filter
-               lsu
-       "
-       if test "$CRYPTOLIB" = openssl; then
-               audiod_errlist_objs="$audiod_errlist_objs openssl"
-       else
-               audiod_errlist_objs="$audiod_errlist_objs gcrypt"
-       fi
-       NEED_VORBIS_OBJECTS && {
-               audiod_errlist_objs="$audiod_errlist_objs oggdec_filter"
-               audiod_audio_formats="$audiod_audio_formats ogg"
-       }
-       NEED_SPEEX_OBJECTS && {
-               audiod_errlist_objs="$audiod_errlist_objs spxdec_filter spx_common"
-               audiod_audio_formats="$audiod_audio_formats spx"
-       }
-       NEED_OPUS_OBJECTS && {
-               audiod_errlist_objs="$audiod_errlist_objs opusdec_filter opus_common"
-               audiod_audio_formats="$audiod_audio_formats opus"
-       }
-       NEED_FLAC_OBJECTS && {
-               audiod_errlist_objs="$audiod_errlist_objs flacdec_filter"
-               audiod_audio_formats="$audiod_audio_formats flac"
-       }
-       if test $HAVE_FAAD = yes; then
-               audiod_errlist_objs="$audiod_errlist_objs aacdec_filter"
-               audiod_audio_formats="$audiod_audio_formats aac"
-       fi
-       if test $HAVE_MAD = yes; then
-               audiod_audio_formats="$audiod_audio_formats mp3"
-               audiod_errlist_objs="$audiod_errlist_objs mp3dec_filter"
-       fi
-       if test $HAVE_OSS = yes; then
-               audiod_errlist_objs="$audiod_errlist_objs oss_write"
-       fi
-       if test $HAVE_ALSA = yes; then
-               audiod_errlist_objs="$audiod_errlist_objs alsa_write"
-       fi
-       NEED_AO_OBJECTS && {
-               audiod_errlist_objs="$audiod_errlist_objs ao_write"
-       }
-       if test $HAVE_SAMPLERATE = yes; then
-               audiod_errlist_objs="$audiod_errlist_objs resample_filter check_wav"
-       fi
-       audiod_objs="$audiod_errlist_objs"
-       AC_SUBST(audiod_objs, add_dot_o($audiod_objs))
-
-       enum="$(for i in $audiod_audio_formats; do printf "AUDIO_FORMAT_${i}, " | tr '[a-z]' '[A-Z]'; done)"
-       AC_DEFINE_UNQUOTED(AUDIOD_AUDIO_FORMATS_ENUM, $enum NUM_AUDIO_FORMATS,
-               enum of audio formats supported by audiod)
-       names="$(for i in $audiod_audio_formats; do printf \"$i\",' ' ; done)"
-       AC_DEFINE_UNQUOTED(AUDIOD_AUDIO_FORMAT_ARRAY, $names, array of audio formats supported by audiod)
-else
-       build_audiod="no"
-fi
-########################################################################### mixer
-if test $HAVE_OSS = yes -o $HAVE_ALSA = yes; then
-       build_mixer="yes"
-       executables="$executables mixer"
-       mixer_errlist_objs="mixer exec string fd time lsu version"
-       if test $HAVE_OSS = yes; then
-               mixer_errlist_objs="$mixer_errlist_objs oss_mix"
-       fi
-       if test $HAVE_ALSA = yes; then
-               mixer_errlist_objs="$mixer_errlist_objs alsa_mix"
-       fi
-       mixer_objs="$mixer_errlist_objs"
-       AC_SUBST(mixer_objs, add_dot_o($mixer_objs))
-else
-       build_mixer="no"
-       AC_MSG_WARN([no mixer support])
-fi
-########################################################################### gui
-if test $HAVE_CURSES = yes; then
-       build_gui="yes"
-       executables="$executables gui"
-       gui_errlist_objs="
-               exec
-               signal
-               string
-               stat
-               ringbuffer
-               fd
-               gui
-               gui_theme
-               lsu
-               time
-               sched
-               version
-       "
-       gui_objs="$gui_errlist_objs"
-       AC_SUBST(gui_objs, add_dot_o($gui_objs))
-else
-       build_gui="no"
-       AC_MSG_WARN([no curses lib, cannot build para_gui])
-fi
-######################################################################## filter
-filter_errlist_objs="
-       filter_common
-       wav_filter
-       compress_filter
-       filter
-       string
-       stdin
-       stdout
-       sched
-       fd
-       amp_filter
-       fecdec_filter
-       fec
-       lsu
-       version
-       prebuffer_filter
-       time
-       bitstream
-       imdct
-       wma_common
-       wmadec_filter
-       buffer_tree
-       net
-       sync_filter
-"
-NEED_VORBIS_OBJECTS && filter_errlist_objs="$filter_errlist_objs oggdec_filter"
-NEED_SPEEX_OBJECTS && filter_errlist_objs="$filter_errlist_objs spxdec_filter spx_common"
-NEED_OPUS_OBJECTS && filter_errlist_objs="$filter_errlist_objs opusdec_filter opus_common"
-NEED_FLAC_OBJECTS && filter_errlist_objs="$filter_errlist_objs flacdec_filter"
-if test $HAVE_FAAD = yes; then
-       filter_errlist_objs="$filter_errlist_objs aacdec_filter"
-fi
-if test $HAVE_MAD = yes; then
-       filter_errlist_objs="$filter_errlist_objs mp3dec_filter"
-fi
-if test $HAVE_SAMPLERATE = yes; then
-       filter_errlist_objs="$filter_errlist_objs resample_filter check_wav"
-fi
-filter_objs="$filter_errlist_objs"
-
-AC_SUBST(filter_objs, add_dot_o($filter_objs))
-########################################################################## recv
-recv_errlist_objs="
-       http_recv
-       recv_common
-       recv
-       time
-       string
-       net
-       dccp_recv
-       fd
-       sched
-       stdout
-       udp_recv
-       buffer_tree
-       afh_recv
-       afh_common
-       wma_afh
-       wma_common
-       mp3_afh
-       version
-"
-NEED_OGG_OBJECTS && recv_errlist_objs="$recv_errlist_objs ogg_afh_common"
-NEED_VORBIS_OBJECTS && recv_errlist_objs="$recv_errlist_objs ogg_afh"
-NEED_SPEEX_OBJECTS && recv_errlist_objs="$recv_errlist_objs spx_afh spx_common"
-NEED_OPUS_OBJECTS && recv_errlist_objs="$recv_errlist_objs opus_afh opus_common"
-NEED_FLAC_OBJECTS && recv_errlist_objs="$recv_errlist_objs flac_afh"
-
-if test $HAVE_FAAD = yes; then
-       recv_errlist_objs="$recv_errlist_objs aac_afh mp4"
-fi
-recv_objs="$recv_errlist_objs"
-AC_SUBST(recv_objs, add_dot_o($recv_objs))
-########################################################################### afh
-audio_format_handlers="mp3 wma"
-afh_errlist_objs="
-       afh
-       string
-       fd
-       mp3_afh
-       afh_common
-       time
-       wma_afh
-       wma_common
-       version
-"
-NEED_OGG_OBJECTS && afh_errlist_objs="$afh_errlist_objs ogg_afh_common"
-NEED_VORBIS_OBJECTS && {
-       afh_errlist_objs="$afh_errlist_objs ogg_afh"
-       audio_format_handlers="$audio_format_handlers ogg"
-}
-NEED_SPEEX_OBJECTS && {
-       afh_errlist_objs="$afh_errlist_objs spx_afh spx_common"
-       audio_format_handlers="$audio_format_handlers spx"
-}
-NEED_OPUS_OBJECTS && {
-       afh_errlist_objs="$afh_errlist_objs opus_afh opus_common"
-       audio_format_handlers="$audio_format_handlers opus"
-}
-NEED_FLAC_OBJECTS && {
-       afh_errlist_objs="$afh_errlist_objs flac_afh"
-       audio_format_handlers="$audio_format_handlers flac"
-}
-if test $HAVE_FAAD = yes; then
-       afh_errlist_objs="$afh_errlist_objs aac_afh mp4"
-       audio_format_handlers="$audio_format_handlers aac"
-fi
-
-afh_objs="$afh_errlist_objs"
-
-AC_SUBST(afh_objs, add_dot_o($afh_objs))
-########################################################################## play
-play_errlist_objs="
-       play
-       fd
-       sched
-       buffer_tree
-       time
-       string
-       net
-       afh_recv
-       afh_common
-       wma_afh
-       wma_common
-       mp3_afh
-       recv_common
-       udp_recv
-       http_recv
-       dccp_recv
-       filter_common
-       fec
-       bitstream
-       imdct
-       wav_filter
-       compress_filter
-       amp_filter
-       prebuffer_filter
-       fecdec_filter
-       wmadec_filter
-       write_common
-       file_write
-       version
-       sync_filter
-       lsu
-"
-NEED_OGG_OBJECTS && play_errlist_objs="$play_errlist_objs ogg_afh_common"
-NEED_VORBIS_OBJECTS && {
-       play_errlist_objs="$play_errlist_objs oggdec_filter ogg_afh"
-}
-NEED_SPEEX_OBJECTS && {
-       play_errlist_objs="$play_errlist_objs spxdec_filter spx_afh spx_common"
-}
-NEED_OPUS_OBJECTS &&
-       play_errlist_objs="$play_errlist_objs
-               opusdec_filter
-               opus_afh
-               opus_common
-       "
-NEED_FLAC_OBJECTS && {
-       play_errlist_objs="$play_errlist_objs flacdec_filter flac_afh"
-}
-if test $HAVE_FAAD = yes; then
-       play_errlist_objs="$play_errlist_objs aac_afh aacdec_filter mp4"
-fi
-if test $HAVE_MAD = yes; then
-       play_errlist_objs="$play_errlist_objs mp3dec_filter"
-fi
-if test $HAVE_OSS = yes; then
-       play_errlist_objs="$play_errlist_objs oss_write"
-fi
-if test $HAVE_ALSA = yes; then
-       play_errlist_objs="$play_errlist_objs alsa_write"
-fi
-NEED_AO_OBJECTS && {
-       play_errlist_objs="$play_errlist_objs ao_write"
-}
-if test $HAVE_READLINE = yes; then
-       play_errlist_objs="$play_errlist_objs interactive"
-fi
-if test $HAVE_SAMPLERATE = yes; then
-       play_errlist_objs="$play_errlist_objs resample_filter check_wav"
-fi
-
-play_objs="$play_errlist_objs"
-AC_SUBST(play_objs, add_dot_o($play_objs))
-######################################################################### write
-write_errlist_objs="
-       write
-       write_common
-       file_write
-       time
-       fd
-       string
-       sched
-       stdin
-       buffer_tree
-       check_wav
-       version
-"
-
-NEED_AO_OBJECTS && {
-       write_errlist_objs="$write_errlist_objs ao_write"
-}
-if test $HAVE_OSS = yes; then
-       write_errlist_objs="$write_errlist_objs oss_write"
-fi
-if test $HAVE_ALSA = yes; then
-       write_errlist_objs="$write_errlist_objs alsa_write"
-fi
-write_objs="$write_errlist_objs"
-AC_SUBST(write_objs, add_dot_o($write_objs))
-######################################################################## audioc
-audioc_errlist_objs="
-       audioc
-       string
-       lsu
-       net
-       fd
-       time
-       version
-"
-if test $HAVE_READLINE = yes; then
-       audioc_errlist_objs="$audioc_errlist_objs
-               buffer_tree
-               interactive
-               sched
-       "
-fi
-audioc_objs="$audioc_errlist_objs"
-AC_SUBST(audioc_objs, add_dot_o($audioc_objs))
-
-AC_DEFINE_UNQUOTED(AUDIO_FORMAT_HANDLERS, "$audio_format_handlers",
-       [formats supported by para_server and para_afh])
-AC_SUBST(executables)
 
 AC_OUTPUT
-AC_MSG_NOTICE([
-paraslash configuration:
-~~~~~~~~~~~~~~~~~~~~~~~~
-crypto lib: ${CRYPTOLIB:-[none]}
-unix socket credentials: $have_ucred
-readline (interactive CLIs): $HAVE_READLINE
-id3 version 2 support: $HAVE_ID3TAG
-faad: $HAVE_FAAD
-audio format handlers: $audio_format_handlers
-
-exe: $executables
-para_server: $build_server
-para_gui: $build_gui
-para_mixer: $build_mixer
-para_client: $build_client
-para_audiod: $build_audiod
-])
diff --git a/crypt.h b/crypt.h
index 5578cd563fae4dc24d673e653dcf21329eba90bc..2e094ced9ee760ced8a7647217a5046bc58e0c20 100644 (file)
--- a/crypt.h
+++ b/crypt.h
@@ -20,18 +20,18 @@ struct asymmetric_key;
  * \param pub: The public key.
  * \param inbuf The input buffer.
  * \param len The length of \a inbuf.
- * \param outbuf The output buffer.
+ * \param outbuf The output buffer will be allocated by the callee.
  *
  * \return The size of the encrypted data on success, negative on errors.
  */
 int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
-               unsigned len, unsigned char *outbuf);
+               unsigned len, unsigned char **outbuf);
 
 /**
  * Decrypt a buffer using a private key.
  *
  * \param key_file Full path of the key.
- * \param outbuf The output buffer.
+ * \param outbuf The output buffer is allocated by the callee.
  * \param inbuf The encrypted input buffer.
  * \param inlen The length of \a inbuf.
  *
@@ -39,7 +39,7 @@ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
  *
  * \return The size of the recovered plaintext on success, negative on errors.
  */
-int apc_priv_decrypt(const char *key_file, unsigned char *outbuf,
+int apc_priv_decrypt(const char *key_file, unsigned char **outbuf,
                unsigned char *inbuf, int inlen);
 
 /**
diff --git a/error.h b/error.h
index 8805c9c7a4c0de6fe958e1523df883ad47effaad..971d3e7f9b7df5a1c96744cc003f93343cd0d6c9 100644 (file)
--- a/error.h
+++ b/error.h
        PARA_ERROR(OGG_PACKET_IN, "ogg_stream_packetin() failed"), \
        PARA_ERROR(OGG_SYNC, "internal ogg storage overflow"), \
        PARA_ERROR(OPENSSH_PARSE, "could not parse openssh private key"), \
+       PARA_ERROR(OPENSSL, "openssl error"), \
        PARA_ERROR(OPUS_COMMENT, "invalid or corrupted opus comment"), \
        PARA_ERROR(OPUS_DECODE, "opus decode error"), \
        PARA_ERROR(OPUS_HEADER, "invalid opus header"), \
        PARA_ERROR(PATH_FOUND, ""), /* not really an error */ \
        PARA_ERROR(PLAYLIST_EMPTY, "attempted to load empty playlist"), \
        PARA_ERROR(PREBUFFER_SUCCESS, "prebuffering complete"), \
-       PARA_ERROR(PRIVATE_KEY, "can not read private key"), \
        PARA_ERROR(QUEUE, "packet queue overrun"), \
        PARA_ERROR(READ_PATTERN, "did not read expected pattern"), \
        PARA_ERROR(RECVMSG, "recvmsg() failed"), \
diff --git a/exec.c b/exec.c
index 85dbaf9474aa286add74cd761f09d30dc74ad805..38f445ee20b4151b38d4b4fa296f25d10103e2e2 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -46,29 +46,26 @@ static int para_exec(pid_t *pid, const char *file, char *const *const args, int
        }
        *pid = ret;
        if (!(*pid)) { /* child */
-               if (fds[0] >= 0) {
-                       if (fds[0]) {
-                               close(in[1]);
-                               if (in[0] != STDIN_FILENO)
-                                       dup2(in[0], STDIN_FILENO);
-                       } else
-                               dup2(null, STDIN_FILENO);
+               if (fds[0] == 0)
+                       dup2(null, STDIN_FILENO);
+               else if (fds[0] > 0) {
+                       close(in[1]);
+                       if (in[0] != STDIN_FILENO)
+                               dup2(in[0], STDIN_FILENO);
                }
-               if (fds[1] >= 0) {
-                       if (fds[1]) {
-                               close(out[0]);
-                               if (out[1] != STDOUT_FILENO)
-                                       dup2(out[1], STDOUT_FILENO);
-                       } else
-                               dup2(null, STDOUT_FILENO);
+               if (fds[1] == 0)
+                       dup2(null, STDOUT_FILENO);
+               else if (fds[1] > 0) {
+                       close(out[0]);
+                       if (out[1] != STDOUT_FILENO)
+                               dup2(out[1], STDOUT_FILENO);
                }
-               if (fds[2] >= 0) {
-                       if (fds[2]) {
-                               close(err[0]);
-                               if (err[1] != STDERR_FILENO)
-                                       dup2(err[1], STDERR_FILENO);
-                       } else
-                               dup2(null, STDERR_FILENO);
+               if (fds[2] == 0)
+                       dup2(null, STDERR_FILENO);
+               else if (fds[2] > 0) {
+                       close(err[0]);
+                       if (err[1] != STDERR_FILENO)
+                               dup2(err[1], STDERR_FILENO);
                }
                if (null >= 0)
                        close(null);
index ba902070d9498677e94872860aeb9bbcbcd5235e..0a5d6bbaf2505618edecde49063036d08a876894 100644 (file)
@@ -31,13 +31,8 @@ struct private_file_write_data {
  */
 __must_check __malloc static char *random_filename(void)
 {
-       char *result, *home = para_homedir();
-
        srandom(clock_get_realtime(NULL)->tv_usec);
-       result = make_message("%s/.paraslash/%08ld", home,
-               para_random(99999999));
-       free(home);
-       return result;
+       return make_message("%s/%08ld", get_confdir(), para_random(99999999));
 }
 
 static int prepare_output_file(struct writer_node *wn)
index 722cb16fb35bfaec09bbaca046ebf62931df8036..50447ec0cd2a165c974e4fea68e288e98a1713e3 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -128,7 +128,10 @@ int main(int argc, char *argv[])
                struct task_info ti;
 
                fn = fns[i] = zalloc(sizeof(*fn));
-               fn->filter_num = filter_setup(fa, &fn->conf, &filter_lpr);
+               ret = filter_setup(fa, &fn->conf, &filter_lpr);
+               if (ret < 0)
+                       goto teardown;
+               fn->filter_num = ret;
                name = filter_name(fn->filter_num);
                fn->lpr = filter_lpr;
                PARA_DEBUG_LOG("filter #%d: %s\n", i, name);
@@ -153,6 +156,7 @@ int main(int argc, char *argv[])
        btr_log_tree(sit->btrn, LL_INFO);
        ret = schedule(&s);
        sched_shutdown(&s);
+teardown:
        for (i--; i >= 0; i--) {
                struct filter_node *fn = fns[i];
 
index f48e457005ca3510fb51d5e5f95405af15d927c1..bcc79f55264b3e8264b0f4171eed40c073ee9b97 100644 (file)
@@ -67,11 +67,11 @@ const char *filter_name(int filter_num)
  * filter, optionally followed by options for this filter. If yes, call the
  * command line parser of that filter and its ->setup method.
  *
- * \return This function either succeeds or does not return. On success, the
- * number of the filter is returned and conf is initialized to point to the
- * filter configuration as returned by the filter's ->setup() method, if any.
- * Moreover, *lprp is initialized to contain the parsed command line options.
- * On errors, the function calls exit(EXIT_FAILURE).
+ * \return On success, the number of the filter is returned and conf is
+ * initialized to point to the filter configuration as returned by the filter's
+ * ->setup() method, if any.  Moreover, *lprp is initialized to contain the
+ * parsed command line options. On errors a negative paraslash error code is
+ * returned.
  */
 int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp)
 {
@@ -80,9 +80,10 @@ int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp)
        const struct lls_command *cmd;
        const struct filter *f;
 
+       *lprp = NULL;
        ret = create_argv(fa, " \t\n", &argv);
        if (ret < 0)
-               goto fail;
+               return ret;
        argc = ret;
        ret = lls(lls_lookup_subcmd(argv[0], filter_cmd_suite, &errctx));
        if (ret < 0)
@@ -99,18 +100,17 @@ int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp)
        if (ret < 0)
                goto free_argv;
        f = filter_get(filter_num);
+       assert(f);
        *conf = f->setup? f->setup(*lprp) : NULL;
        ret = filter_num;
 free_argv:
        free_argv(argv);
        if (ret >= 0)
                return ret;
-fail:
        if (errctx)
                PARA_ERROR_LOG("%s\n", errctx);
        free(errctx);
-       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
-       exit(EXIT_FAILURE);
+       return ret;
 }
 
 /**
index fb8ebf15d1ec664e39923c58515a3704441ab0da..bc3a678b52cf7811ca6032e61f1eb6128766f819 100644 (file)
@@ -187,7 +187,7 @@ static int flacdec_init(struct filter_node *fn)
        return -E_FLACDEC_DECODER_INIT;
 }
 
-static int flacdec_execute(struct btr_node *btrn, const char *cmd,
+static int flacdec_execute(const struct btr_node *btrn, const char *cmd,
                char **result)
 {
        struct filter_node *fn = btr_context(btrn);
index b46f8f9555824eb86b7bbf600b4352558ed2db26..e5f64688cbbc6ef5aa907fb7336675bdc9818e61 100644 (file)
--- a/gcrypt.c
+++ b/gcrypt.c
@@ -114,6 +114,7 @@ void crypt_shutdown(void)
 
 struct asymmetric_key {
        gcry_sexp_t sexp;
+       int bits;
 };
 
 static const char *gcrypt_strerror(gcry_error_t gret)
@@ -457,6 +458,7 @@ int apc_get_pubkey(const char *key_file, struct asymmetric_key **result)
        PARA_INFO_LOG("successfully read %u bit ssh public key\n", bits);
        key = alloc(sizeof(*key));
        key->sexp = sexp;
+       key->bits = bits;
        *result = key;
        ret = bits / 8;
 release_n:
@@ -476,17 +478,20 @@ void apc_free_pubkey(struct asymmetric_key *key)
        free(key);
 }
 
-static int decode_rsa(gcry_sexp_t sexp, unsigned char *outbuf, size_t *nbytes)
+static int decode_rsa(gcry_sexp_t sexp, unsigned char **outbuf, size_t *nbytes)
 {
        const char *p = gcry_sexp_nth_data(sexp, 1, nbytes);
 
-       if (!p)
+       if (!p) {
+               *outbuf = NULL;
                return -E_RSA_DECODE;
-       memcpy(outbuf, p, *nbytes);
+       }
+       *outbuf = alloc(*nbytes);
+       memcpy(*outbuf, p, *nbytes);
        return 1;
 }
 
-int apc_priv_decrypt(const char *key_file, unsigned char *outbuf,
+int apc_priv_decrypt(const char *key_file, unsigned char **outbuf,
                unsigned char *inbuf, int inlen)
 {
        gcry_error_t gret;
@@ -496,6 +501,7 @@ int apc_priv_decrypt(const char *key_file, unsigned char *outbuf,
        gcry_sexp_t in, out, priv_key;
        size_t nbytes;
 
+       *outbuf = NULL;
        ret = check_private_key_file(key_file);
        if (ret < 0)
                return ret;
@@ -554,7 +560,7 @@ free_key:
 }
 
 int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
-               unsigned len, unsigned char *outbuf)
+               unsigned len, unsigned char **outbuf)
 {
        gcry_error_t gret;
        gcry_sexp_t pub_key, in, out, out_a;
@@ -562,6 +568,7 @@ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
        size_t nbytes;
        int ret;
 
+       *outbuf = NULL;
        /* get pub key */
        pub_key = gcry_sexp_find_token(pub->sexp, "public-key", 0);
        if (!pub_key)
@@ -590,14 +597,18 @@ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
                ret = -E_SEXP_FIND;
                goto out_a_release;
        }
-       gret = gcry_mpi_print(GCRYMPI_FMT_USG, outbuf, 512 /* FIXME */, &nbytes, out_mpi);
+       *outbuf = alloc(pub->bits);
+       gret = gcry_mpi_print(GCRYMPI_FMT_USG, *outbuf, pub->bits, &nbytes,
+               out_mpi);
        if (gret) {
+               free(*outbuf);
+               *outbuf = NULL;
                PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
                ret = -E_SEXP_ENCRYPT;
                goto out_mpi_release;
        }
        PARA_INFO_LOG("encrypted buffer is %zu bytes\n", nbytes);
-       dump_buffer("enc buf", outbuf, nbytes);
+       dump_buffer("enc buf", *outbuf, nbytes);
        ret = nbytes;
 
 out_mpi_release:
diff --git a/gui.c b/gui.c
index 66fb7870bd65868a750b5918747da59ad4681b6d..9f55c624745b7846db56f12157956d48c3b64f0d 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -1507,5 +1507,6 @@ out:
                free(errctx);
                PARA_EMERG_LOG("%s\n", para_strerror(-ret));
        }
+       free(get_confdir());
        return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 1376cf1d72739b3f7c9c3218dd96666a5d475812..4d48742f686862bb8d5fe8871116925309dbc978 100644 (file)
@@ -229,6 +229,7 @@ void i9e_close(void)
        rl_callback_handler_remove();
        if (hf)
                write_history(hf);
+       clear_history();
        wipe_bottom_line();
        fcntl(i9ep->ici->fds[0], F_SETFL, i9ep->fd_flags[0]);
        fcntl(i9ep->ici->fds[1], F_SETFL, i9ep->fd_flags[1]);
diff --git a/ipc.c b/ipc.c
index 8e9dd51a2369e7e60ebd4bda3fa889eaed892248..c245f690788630e19f2c7e82bda903360e1c0fa5 100644 (file)
--- a/ipc.c
+++ b/ipc.c
@@ -218,7 +218,7 @@ size_t shm_get_shmmax(void)
        {
                int fd = open("/proc/sys/kernel/shmmax", O_RDONLY);
                if (fd >= 0) {
-                       char buf[100] = "";
+                       char buf[100];
                        int ret = read(fd, buf, sizeof(buf) - 1);
                        if (ret > 0) {
                                buf[ret] = '\0';
diff --git a/list.h b/list.h
index 78c302fa322fe6bc2dae2926e95e58189c10c944..82f5b36dbd5468a35e3b752b41bc017d65bf9a28 100644 (file)
--- a/list.h
+++ b/list.h
@@ -161,3 +161,5 @@ static inline int list_is_singular(const struct list_head *head)
  */
 #define list_first_entry(ptr, type, member) \
        list_entry((ptr)->next, type, member)
+#define list_last_entry(ptr, type, member) \
+       list_entry((ptr)->prev, type, member)
diff --git a/lsu.c b/lsu.c
index 8ccf80d541929194f984759e38d7ffa7998d3c97..75114e68a5fa443ca675987b05bb9eb452ee9270 100644 (file)
--- a/lsu.c
+++ b/lsu.c
@@ -179,13 +179,8 @@ int lsu_merge_config_file_options(const char *path, const char *dflt,
        struct lls_parse_result *old_lpr = *lpr, *cf_lpr, *merged_lpr;
        const char *subcmd_name;
 
-       if (path)
-               cf = para_strdup(path);
-       else {
-               char *home = para_homedir();
-               cf = make_message("%s/.paraslash/%s", home, dflt);
-               free(home);
-       }
+       cf = path? para_strdup(path) : make_message("%s/%s",
+               get_confdir(), dflt);
        ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
        if (ret < 0) {
                if (ret == -E_EMPTY)
index 02afaabb5252a0580711547ad399cef932cfcadc..d694082beac70f0990f0356d1cc2443ca9c38657 100644 (file)
@@ -216,11 +216,12 @@ m4_include(`com_ll.m4')
                        a length field.
 
                        mbox (m). Generate output suitable to be viewed with a mail
-                       program. One "mail" per matching audio file.
-
-                       chunk-table (c). Print path (or basename, depending on whether -p is
-                       also given), chunk time and chunk offsets.
+                       program. One "mail" per matching audio file. This listing mode is
+                       deprecated and will be removed after paraslash-0.8.0 has been released.
 
+                       chunk-table (c). Print path (or basename, depending on whether -p
+                       is also given), chunk time and chunk offsets. This listing mode is
+                       deprecated and will be removed after paraslash-0.8.0 has been released.
                [/help]
        [option limit]
                short_opt = L
diff --git a/mixer.c b/mixer.c
index dda7fc1df729722266db7136733a28ac2391e977..a5c415f7265388fa1e0ef3c34b051190d70f378e 100644 (file)
--- a/mixer.c
+++ b/mixer.c
@@ -609,12 +609,13 @@ free_sub_lpr:
        lls_free_parse_result(sub_lpr, cmd);
 free_lpr:
        lls_free_parse_result(lpr, CMD_PTR(PARA_MIXER));
-       if (ret >= 0)
-               return EXIT_SUCCESS;
 fail:
-       if (errctx)
-               PARA_ERROR_LOG("%s\n", errctx);
-       free(errctx);
-       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
-       return EXIT_FAILURE;
+       if (ret < 0) {
+               if (errctx)
+                       PARA_ERROR_LOG("%s\n", errctx);
+               free(errctx);
+               PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+       }
+       free(get_confdir());
+       return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
 }
index d40df85edbe24b9dc54f01fc9305a1575c022507..d4d4712f0d25a9e8981e8882ff0cbe1ddef14d0c 100644 (file)
@@ -79,12 +79,11 @@ static int mp3dec_post_monitor(__a_unused struct sched *s, void *context)
        int i, ret;
        struct private_mp3dec_data *pmd = fn->private_data;
        struct btr_node *btrn = fn->btrn;
-       size_t loaded = 0, len, iqs;
+       size_t loaded = 0, len;
        char *inbuffer, *outbuffer;
 
 next_buffer:
        pmd->stream.error = 0;
-       iqs = btr_get_input_queue_size(btrn);
        ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
        if (ret < 0)
                goto err;
@@ -104,7 +103,7 @@ next_frame:
        if (ret < 0) {
                mp3dec_consume(btrn, &pmd->stream, len);
                if (pmd->stream.error == MAD_ERROR_BUFLEN) {
-                       if (len == iqs && btr_no_parent(btrn)) {
+                       if (fn->min_iqs > 0 && btr_no_parent(btrn)) {
                                ret = -E_EOF;
                                goto err;
                        }
@@ -128,7 +127,7 @@ decode:
                mad_stream_sync(&pmd->stream);
                if (pmd->stream.error == MAD_ERROR_BUFLEN) {
                        ret = -E_EOF;
-                       if (len == iqs && btr_no_parent(btrn))
+                       if (btr_no_parent(btrn))
                                goto err;
                        fn->min_iqs += 100;
                        ret = -E_MP3DEC_CORRUPT;
@@ -176,7 +175,8 @@ static void mp3dec_open(struct filter_node *fn)
                mad_stream_options(&pmd->stream, MAD_OPTION_IGNORECRC);
 }
 
-static int mp3dec_execute(struct btr_node *btrn, const char *cmd, char **result)
+static int mp3dec_execute(const struct btr_node *btrn, const char *cmd,
+               char **result)
 {
        struct filter_node *fn = btr_context(btrn);
        struct private_mp3dec_data *pmd = fn->private_data;
diff --git a/mp4.c b/mp4.c
index 5ca1307f680d366c155b2e98257ba807c5a4fb92..fe9d4b37e3e94c0c906b3cc16234539cde19a6b6 100644 (file)
--- a/mp4.c
+++ b/mp4.c
@@ -131,7 +131,8 @@ static int read_int16(struct mp4 *f, uint16_t *result)
        return ret;
 }
 
-/** A macro defining the atoms we care about. It gets expanded twice. */
+/** \cond atom_items */
+/* A macro defining the atoms we care about. It gets expanded twice. */
 #define ATOM_ITEMS \
        ATOM_ITEM(MOOV, 'm', 'o', 'o', 'v') /* movie (top-level container) */ \
        ATOM_ITEM(TRAK, 't', 'r', 'a', 'k') /* container for a single track */ \
@@ -155,6 +156,8 @@ static int read_int16(struct mp4 *f, uint16_t *result)
        ATOM_ITEM(META, 'm', 'e', 't', 'a') /* iTunes Metadata box */ \
        ATOM_ITEM(DATA, 'd', 'a', 't', 'a') /* iTunes Metadata data box */ \
 
+/** \endcond atom_items */
+
 /** For the C enumeration we concatenate ATOM_ with the first argument. */
 #define ATOM_ITEM(_name, a, b, c, d) ATOM_ ## _name,
 /** The enumeration of interesting atoms. */
index b1aec4bc2c4cb0049ed942d3b7e7708b2de84688..91c18c48899bd4741a6efe55c1d9a734e3ecfb14 100644 (file)
@@ -107,7 +107,8 @@ static void ogg_close(struct filter_node *fn)
        fn->private_data = NULL;
 }
 
-static int oggdec_execute(struct btr_node *btrn, const char *cmd, char **result)
+static int oggdec_execute(const struct btr_node *btrn, const char *cmd,
+               char **result)
 {
        struct filter_node *fn = btr_context(btrn);
        struct private_oggdec_data *pod = fn->private_data;
index f696cd9e83606bc4e6bdd89d666f0885575f1d9f..a5a6a17576989ed51fbe36c116effb3ae0679f1a 100644 (file)
--- a/openssl.c
+++ b/openssl.c
 
 struct asymmetric_key {
        RSA *rsa;
+       EVP_PKEY *pkey;
+       EVP_PKEY_CTX *ctx;
 };
 
+static int openssl_perror(const char *pfx)
+{
+       unsigned long err = ERR_get_error();
+       PARA_ERROR_LOG("%s: \"%s\"\n", pfx, ERR_reason_error_string(err));
+       return -E_OPENSSL;
+}
+
 void get_random_bytes_or_die(unsigned char *buf, int num)
 {
-       unsigned long err;
+       int ret;
 
-       /* RAND_bytes() returns 1 on success, 0 otherwise. */
-       if (RAND_bytes(buf, num) == 1)
+       if (RAND_bytes(buf, num) == 1) /* success */
                return;
-       err = ERR_get_error();
-       PARA_EMERG_LOG("%s\n", ERR_reason_error_string(err));
+       ret = openssl_perror("RAND_bytes");
+       PARA_EMERG_LOG("%s\n", strerror(-ret));
        exit(EXIT_FAILURE);
 }
 
@@ -54,9 +62,6 @@ void crypt_init(void)
 
 void crypt_shutdown(void)
 {
-#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
-       CRYPTO_cleanup_all_ex_data();
-#endif
 #ifdef HAVE_OPENSSL_THREAD_STOP /* openssl-1.1 or later */
        OPENSSL_thread_stop();
 #else /* openssl-1.0 */
@@ -97,88 +102,155 @@ static int read_bignum(const unsigned char *buf, size_t len, BIGNUM **result)
        return bnsize + 4;
 }
 
-static int read_public_key(const unsigned char *blob, int blen, RSA **result)
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+
+static int generate_private_pkey(struct asymmetric_key *priv,
+               const BIGNUM *n, const BIGNUM *e, const BIGNUM *d,
+               const BIGNUM *p, const BIGNUM *q)
 {
-       int ret;
-       RSA *rsa;
-       BIGNUM *n, *e;
+       const BIGNUM *bignums[] = {n, e, d, p, q};
+       const char *strings[] = {"n", "e", "d", "p", "q"};
+       int ret, bytes[ARRAY_SIZE(bignums)];
+       unsigned char *bufs[ARRAY_SIZE(bignums)];
+       OSSL_PARAM params[ARRAY_SIZE(bignums) + 1];
+       /*
+        * Convert bignums to buffers for OSSL_PARAM_construct_BN() and init
+        * params[].
+        */
+       for (int i = 0; i < ARRAY_SIZE(bignums); i++) {
+               bytes[i] = BN_num_bytes(bignums[i]);
+               PARA_DEBUG_LOG("%s: %d bits\n", strings[i], bytes[i] * 8);
+               bufs[i] = alloc(bytes[i]);
+               assert(BN_bn2nativepad(bignums[i], bufs[i], bytes[i]) > 0);
+               params[i] = OSSL_PARAM_construct_BN(strings[i], bufs[i],
+                       bytes[i]);
+       }
+       params[ARRAY_SIZE(bignums)] = OSSL_PARAM_construct_end();
+       /* Transfer buffers to openssl to create the pkey from it */
+       priv->ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+       assert(priv->ctx);
+       assert(EVP_PKEY_fromdata_init(priv->ctx) > 0);
+       ret = EVP_PKEY_fromdata(priv->ctx, &priv->pkey,
+               EVP_PKEY_KEYPAIR, params);
+       for (int i = 0; i < ARRAY_SIZE(bignums); i++)
+               free(bufs[i]);
+       if (ret <= 0) {
+               EVP_PKEY_CTX_free(priv->ctx);
+               return openssl_perror("EVP_PKEY_fromdata()");
+       }
+       assert(priv->pkey);
+       return BN_num_bytes(n) * 8;
+}
+
+/*
+ * Convert bignumns e and n to a pkey and context.
+ */
+static int generate_public_pkey(struct asymmetric_key *pub,
+               const BIGNUM *e, const BIGNUM *n)
+{
+       unsigned char *ebuf, *nbuf;
+       int ret, ebytes = BN_num_bytes(e), nbytes = BN_num_bytes(n);
+       OSSL_PARAM params[3];
+
+       /* Convert e and n to a buffer for OSSL_PARAM_construct_BN() */
+       ebuf = alloc(ebytes);
+       assert(BN_bn2nativepad(e, ebuf, ebytes) > 0);
+       nbuf = alloc(nbytes);
+       assert(BN_bn2nativepad(n, nbuf, nbytes) > 0);
+       /* Init params[] with {e,n}buf and create the pkey from it */
+       params[0] = OSSL_PARAM_construct_BN("e", ebuf, ebytes);
+       params[1] = OSSL_PARAM_construct_BN("n", nbuf, nbytes);
+       params[2] = OSSL_PARAM_construct_end();
+       pub->ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+       assert(pub->ctx);
+       assert(EVP_PKEY_fromdata_init(pub->ctx) > 0);
+       ret = EVP_PKEY_fromdata(pub->ctx, &pub->pkey, EVP_PKEY_PUBLIC_KEY,
+               params);
+       free(nbuf);
+       free(ebuf);
+       if (ret <= 0) {
+               EVP_PKEY_CTX_free(pub->ctx);
+               return openssl_perror("EVP_PKEY_fromdata()");
+       }
+       assert(pub->pkey);
+       return nbytes * 8;
+}
+
+#endif /* HAVE_OSSL_PARAM */
+
+static int read_public_key(const unsigned char *blob, size_t blen,
+               struct asymmetric_key *pub)
+{
+       int ret, bits;
        const unsigned char *p = blob, *end = blob + blen;
+       BIGNUM *e, *n;
 
-       rsa = RSA_new();
-       if (!rsa)
-               return -E_BIGNUM;
        ret = read_bignum(p, end - p, &e);
        if (ret < 0)
-               goto free_rsa;
+               return ret;
        p += ret;
        ret = read_bignum(p, end - p, &n);
-       if (ret < 0)
-               goto free_e;
-#ifdef HAVE_RSA_SET0_KEY
-       RSA_set0_key(rsa, n, e, NULL);
-#else
-       rsa->n = n;
-       rsa->e = e;
-#endif
-       *result = rsa;
-       return 1;
-free_e:
+       if (ret < 0) {
+               BN_free(e);
+               return ret;
+       }
+       bits = BN_num_bytes(n) * 8;
+       PARA_DEBUG_LOG("modulus: %d bits\n", bits);
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       ret = generate_public_pkey(pub, e, n);
        BN_free(e);
-free_rsa:
-       RSA_free(rsa);
-       return ret;
+       BN_free(n);
+       if (ret < 0)
+               return ret;
+#else /* openssl < 3.0 */
+       pub->rsa = RSA_new();
+       assert(pub->rsa);
+       #if HAVE_RSA_SET0_KEY /* openssl-1.1 */
+               RSA_set0_key(pub->rsa, n, e, NULL);
+       #else /* openssl-1.0 */
+               pub->rsa->n = n;
+               pub->rsa->e = e;
+       #endif
+       /* e and n are now owned by openssl */
+#endif /* HAVE_OSSL_PARAM */
+       return bits;
 }
 
-static int read_pem_private_key(const char *path, RSA **rsa)
+static int read_pem_private_key(const char *path, struct asymmetric_key *priv)
 {
-       EVP_PKEY *pkey;
-       BIO *bio = BIO_new(BIO_s_file());
-
-       *rsa = NULL;
-       if (!bio)
-               return -E_PRIVATE_KEY;
-       if (BIO_read_filename(bio, path) <= 0)
-               goto bio_free;
-       pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
-       if (!pkey)
-               goto bio_free;
-       *rsa = EVP_PKEY_get1_RSA(pkey);
-       EVP_PKEY_free(pkey);
-bio_free:
+       BIO *bio;
+       int ret;
+
+       assert((bio = BIO_new(BIO_s_file())));
+       ret = BIO_read_filename(bio, path);
+       if (ret <= 0) {
+               priv->pkey = NULL;
+               ret = openssl_perror("BIO_read_filename");
+               goto free_bio;
+       }
+       priv->pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+       if (!priv->pkey) {
+               ret = openssl_perror("PEM_read_bio_PrivateKey");
+               goto free_bio;
+       }
+#ifndef HAVE_OSSL_PARAM /* openssl-1 */
+       priv->rsa = EVP_PKEY_get1_RSA(priv->pkey);
+#endif
+free_bio:
        BIO_free(bio);
-       return *rsa? RSA_size(*rsa) : -E_PRIVATE_KEY;
+       return ret;
 }
 
 static int read_openssh_private_key(const unsigned char *blob,
-               const unsigned char *end, RSA **result)
+               const unsigned char *end, struct asymmetric_key *priv)
 {
        int ret;
-       RSA *rsa;
-       BN_CTX *ctx;
        BIGNUM *n, *e, *d, *iqmp, *p, *q; /* stored in the key file */
-       BIGNUM *dmp1, *dmq1; /* these will be computed */
-       BIGNUM *tmp;
        const unsigned char *cp = blob;
 
-       rsa = RSA_new();
-       if (!rsa)
-               return -E_BIGNUM;
-       ret = -E_BIGNUM;
-       tmp = BN_new();
-       if (!tmp)
-               goto free_rsa;
-       ctx = BN_CTX_new();
-       if (!ctx)
-               goto free_tmp;
-       dmp1 = BN_new();
-       if (!dmp1)
-               goto free_ctx;
-       dmq1 = BN_new();
-       if (!dmq1)
-               goto free_dmp1;
        ret = read_bignum(cp, end - cp, &n);
        if (ret < 0)
-               goto free_dmq1;
+               return ret;
        cp += ret;
        ret = read_bignum(cp, end - cp, &e);
        if (ret < 0)
@@ -199,33 +271,29 @@ static int read_openssh_private_key(const unsigned char *blob,
        ret = read_bignum(cp, end - cp, &q);
        if (ret < 0)
                goto free_p;
-       ret = -E_BIGNUM;
-       if (!BN_sub(tmp, q, BN_value_one()))
-               goto free_q;
-       if (!BN_mod(dmp1, d, tmp, ctx))
-               goto free_q;
-       if (!BN_sub(tmp, q, BN_value_one()))
-               goto free_q;
-       if (!BN_mod(dmq1, d, tmp, ctx))
-               goto free_q;
-#ifdef HAVE_RSA_SET0_KEY
-       RSA_set0_key(rsa, n, e, d);
-       RSA_set0_factors(rsa, p, q);
-       RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp);
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       /*
+        * Ignore iqmp, the coefficient for Chinese remainder theorem. It is
+        * dispensable because it can be derived from the other values. Passing
+        * it to the EVP API results in a memory leak.
+        */
+       ret = generate_private_pkey(priv, n, e, d, p, q);
 #else
-       rsa->n = n;
-       rsa->e = e;
-       rsa->d = d;
-       rsa->iqmp = iqmp;
-       rsa->p = p;
-       rsa->q = q;
-       rsa->dmp1 = dmp1;
-       rsa->dmq1 = dmq1;
-#endif
-       *result = rsa;
-       ret = 1;
-       goto free_ctx;
-free_q:
+       assert((priv->rsa = RSA_new()));
+       #ifdef HAVE_RSA_SET0_KEY
+               RSA_set0_key(priv->rsa, n, e, d);
+               RSA_set0_factors(priv->rsa, p, q);
+               RSA_set0_crt_params(priv->rsa, NULL, NULL, iqmp);
+       #else
+               priv->rsa->n = n;
+               priv->rsa->e = e;
+               priv->rsa->d = d;
+               priv->rsa->iqmp = iqmp;
+               priv->rsa->p = p;
+               priv->rsa->q = q;
+       #endif
+       return 1;
+#endif /* HAVE_OSSL_PARAM */
        BN_clear_free(q);
 free_p:
        BN_clear_free(p);
@@ -237,27 +305,15 @@ free_e:
        BN_free(e);
 free_n:
        BN_free(n);
-free_dmq1:
-       BN_clear_free(dmq1);
-free_dmp1:
-       BN_clear_free(dmp1);
-free_ctx:
-       BN_CTX_free(ctx);
-free_tmp:
-       BN_clear_free(tmp);
-free_rsa:
-       if (ret < 0)
-               RSA_free(rsa);
        return ret;
 }
 
-static int get_private_key(const char *path, RSA **rsa)
+static int get_private_key(const char *path, struct asymmetric_key *priv)
 {
        int ret;
        unsigned char *blob, *end;
        size_t blob_size;
 
-       *rsa = NULL;
        ret = decode_private_key(path, &blob, &blob_size);
        if (ret < 0)
                return ret;
@@ -267,9 +323,9 @@ static int get_private_key(const char *path, RSA **rsa)
                if (ret < 0)
                        goto free_blob;
                PARA_INFO_LOG("reading RSA params at offset %d\n", ret);
-               ret = read_openssh_private_key(blob + ret, end, rsa);
+               ret = read_openssh_private_key(blob + ret, end, priv);
        } else
-               ret = read_pem_private_key(path, rsa);
+               ret = read_pem_private_key(path, priv);
 free_blob:
        free(blob);
        return ret;
@@ -280,53 +336,84 @@ int apc_get_pubkey(const char *key_file, struct asymmetric_key **result)
        unsigned char *blob;
        size_t decoded_size;
        int ret;
-       struct asymmetric_key *pub = alloc(sizeof(*pub));
+       struct asymmetric_key *pub;
 
        ret = decode_public_key(key_file, &blob, &decoded_size);
        if (ret < 0)
-               goto out;
-       ret = read_public_key(blob + ret, decoded_size - ret, &pub->rsa);
-       if (ret < 0)
-               goto free_blob;
-       ret = RSA_size(pub->rsa);
-       assert(ret > 0);
-       *result = pub;
-free_blob:
+               return ret;
+       pub = zalloc(sizeof(*pub)); /* ->pkey needs to start out zeroed */
+       ret = read_public_key(blob + ret, decoded_size - ret, pub);
        free(blob);
-out:
        if (ret < 0) {
                free(pub);
                *result = NULL;
                PARA_ERROR_LOG("can not load key %s\n", key_file);
+               return ret;
        }
-       return ret;
+       PARA_NOTICE_LOG("loaded %d bit key from %s\n", ret, key_file);
+       *result = pub;
+       return ret / 8;
 }
 
 void apc_free_pubkey(struct asymmetric_key *pub)
 {
        if (!pub)
                return;
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       EVP_PKEY_CTX_free(pub->ctx);
+       EVP_PKEY_free(pub->pkey);
+#else
        RSA_free(pub->rsa);
+#endif
        free(pub);
 }
 
-int apc_priv_decrypt(const char *key_file, unsigned char *outbuf,
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+static int pkey_priv_decrypt(const struct asymmetric_key *priv,
+               unsigned char **outbuf, unsigned char *inbuf, int inlen)
+{
+       EVP_PKEY_CTX *ctx;
+       size_t outlen;
+
+       assert((ctx = EVP_PKEY_CTX_new(priv->pkey, NULL)));
+       assert((EVP_PKEY_decrypt_init(ctx) > 0));
+       assert(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) > 0);
+       if (EVP_PKEY_decrypt(ctx, NULL, &outlen, inbuf, inlen) <= 0) {
+               *outbuf = NULL;
+               EVP_PKEY_CTX_free(ctx);
+               return openssl_perror("EVP_PKEY_encrypt()");
+       }
+       *outbuf = alloc(outlen);
+       assert((EVP_PKEY_decrypt(ctx, *outbuf, &outlen, inbuf, inlen) > 0));
+       EVP_PKEY_CTX_free(ctx);
+       PARA_INFO_LOG("wrote %zu decrypted data bytes\n", outlen);
+       return outlen;
+}
+#endif /* HAVE_OSSL_PARAM */
+
+int apc_priv_decrypt(const char *key_file, unsigned char **outbuf,
                unsigned char *inbuf, int inlen)
 {
        struct asymmetric_key *priv;
        int ret;
 
+       *outbuf = NULL;
        ret = check_private_key_file(key_file);
        if (ret < 0)
                return ret;
        if (inlen < 0)
                return -E_RSA;
-       priv = alloc(sizeof(*priv));
-       ret = get_private_key(key_file, &priv->rsa);
+       priv = zalloc(sizeof(*priv)); /* ->pkey needs to start out zeroed */
+       ret = get_private_key(key_file, priv);
        if (ret < 0) {
                free(priv);
                return ret;
        }
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       ret = pkey_priv_decrypt(priv, outbuf, inbuf, inlen);
+       EVP_PKEY_CTX_free(priv->ctx);
+       EVP_PKEY_free(priv->pkey);
+#else
        /*
         * RSA is vulnerable to timing attacks. Generate a random blinding
         * factor to protect against this kind of attack.
@@ -334,27 +421,56 @@ int apc_priv_decrypt(const char *key_file, unsigned char *outbuf,
        ret = -E_BLINDING;
        if (RSA_blinding_on(priv->rsa, NULL) == 0)
                goto out;
-       ret = RSA_private_decrypt(inlen, inbuf, outbuf, priv->rsa,
+       *outbuf = alloc(RSA_size(priv->rsa));
+       ret = RSA_private_decrypt(inlen, inbuf, *outbuf, priv->rsa,
                RSA_PKCS1_OAEP_PADDING);
        RSA_blinding_off(priv->rsa);
-       if (ret <= 0)
+       if (ret <= 0) {
+               free(*outbuf);
+               *outbuf = NULL;
                ret = -E_DECRYPT;
+       }
 out:
        RSA_free(priv->rsa);
+#endif
        free(priv);
        return ret;
 }
 
 int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
-               unsigned len, unsigned char *outbuf)
+               unsigned len, unsigned char **outbuf)
 {
-       int ret, flen = len; /* RSA_public_encrypt expects a signed int */
-
-       if (flen < 0)
-               return -E_ENCRYPT;
-       ret = RSA_public_encrypt(flen, inbuf, outbuf, pub->rsa,
+       int ret;
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       EVP_PKEY_CTX *ctx;
+       size_t outlen;
+
+       *outbuf = NULL;
+       assert((ctx = EVP_PKEY_CTX_new(pub->pkey, NULL)));
+       assert((EVP_PKEY_encrypt_init(ctx) > 0));
+       assert((EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) > 0));
+       if (EVP_PKEY_encrypt(ctx, NULL, &outlen, inbuf, len) <= 0) {
+               ret = openssl_perror("EVP_PKEY_encrypt()");
+               goto free_ctx;
+       }
+       *outbuf = alloc(outlen);
+       assert((EVP_PKEY_encrypt(ctx, *outbuf, &outlen, inbuf, len) > 0));
+       PARA_INFO_LOG("wrote %zu encrypted data bytes\n", outlen);
+       ret = outlen;
+free_ctx:
+       EVP_PKEY_CTX_free(ctx);
+       return ret;
+#else /* openssl < 3.0 */
+       *outbuf = alloc(RSA_size(pub->rsa));
+       ret = RSA_public_encrypt((int)len, inbuf, *outbuf, pub->rsa,
                RSA_PKCS1_OAEP_PADDING);
-       return ret < 0? -E_ENCRYPT : ret;
+       if (ret < 0) {
+               free(*outbuf);
+               *outbuf = NULL;
+               return -E_ENCRYPT;
+       }
+       return ret;
+#endif /* HAVE_OSSL_PARAM */
 }
 
 struct stream_cipher {
@@ -366,7 +482,7 @@ struct stream_cipher *sc_new(const unsigned char *data, int len)
        struct stream_cipher *sc = alloc(sizeof(*sc));
 
        assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
-       sc->aes = EVP_CIPHER_CTX_new();
+       assert((sc->aes = EVP_CIPHER_CTX_new()));
        EVP_EncryptInit_ex(sc->aes, EVP_aes_128_ctr(), NULL, data,
                data + AES_CRT128_BLOCK_SIZE);
        return sc;
@@ -406,8 +522,11 @@ void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
 
 void hash_function(const char *data, unsigned long len, unsigned char *hash)
 {
-       EVP_MD_CTX *c = EVP_MD_CTX_new();
-       int ret = EVP_DigestInit_ex(c, EVP_sha1(), NULL);
+       int ret;
+       EVP_MD_CTX *c;
+
+       assert((c = EVP_MD_CTX_new()));
+       ret = EVP_DigestInit_ex(c, EVP_sha1(), NULL);
        assert(ret != 0);
        ret = EVP_DigestUpdate(c, data, len);
        assert(ret != 0);
@@ -418,8 +537,11 @@ void hash_function(const char *data, unsigned long len, unsigned char *hash)
 
 void hash2_function(const char *data, unsigned long len, unsigned char *hash)
 {
-       EVP_MD_CTX *c = EVP_MD_CTX_new();
-       int ret = EVP_DigestInit_ex(c, EVP_sha256(), NULL);
+       int ret;
+       EVP_MD_CTX *c;
+
+       assert((c = EVP_MD_CTX_new()));
+       ret = EVP_DigestInit_ex(c, EVP_sha256(), NULL);
        assert(ret != 0);
        ret = EVP_DigestUpdate(c, data, len);
        assert(ret != 0);
index f36990faf43a4110c8e7f7dc2f822f5a8e09046c..504ba0e881ef7fe268670be28d267b68c85188d2 100644 (file)
@@ -75,7 +75,7 @@ struct opusdec_context {
        ogg_int32_t opus_serialno;
 };
 
-static int opusdec_execute(struct btr_node *btrn, const char *cmd,
+static int opusdec_execute(const struct btr_node *btrn, const char *cmd,
                char **result)
 {
        struct filter_node *fn = btr_context(btrn);
diff --git a/play.c b/play.c
index bd183b6b8dd48906e08cf142d7ff8c1e05aad48a..5b20315af2bbb11bcf1b79a67550788992fcbda9 100644 (file)
--- a/play.c
+++ b/play.c
@@ -24,6 +24,7 @@
 #include "recv.h"
 #include "write.h"
 #include "fd.h"
+#include "interactive.h"
 
 /** Array of error strings. */
 DEFINE_PARA_ERRLIST;
@@ -222,7 +223,7 @@ static int get_playback_error(void)
        int err;
 
        if (!pt->wn.task)
-               return 0;
+               return 1;
        err = task_status(pt->wn.task);
        if (err >= 0)
                return 0;
@@ -253,7 +254,7 @@ static int eof_cleanup(void)
 
        decoder = filter_get(pt->fn.filter_num);
        task_reap(&pt->fn.task);
-       if (decoder->close)
+       if (decoder && decoder->close)
                decoder->close(&pt->fn);
        btr_remove_node(&pt->fn.btrn);
        lls_free_parse_result(pt->fn.lpr, FILTER_CMD(pt->fn.filter_num));
@@ -470,8 +471,6 @@ static void kill_stream(void)
                task_notify(pt->wn.task, E_EOF);
 }
 
-#ifdef HAVE_READLINE
-
 /* only called from com_prev(), nec. only if we have readline */
 static int previous_valid_file(void)
 {
@@ -488,8 +487,6 @@ static int previous_valid_file(void)
        return -E_NO_VALID_FILES;
 }
 
-#include "interactive.h"
-
 /*
  * Define the default (internal) key mappings and helper functions to get the
  * key sequence or the command from a key id, which is what we obtain from
@@ -573,15 +570,17 @@ static inline char *get_internal_key_map_seq(int key)
        return para_strdup(default_keyseqs[get_internal_key_map_idx(key)]);
 }
 
-static char *get_user_key_map_seq(int key)
+static char *get_key_map_seq(int key)
 {
-       const char *kma = get_user_key_map_arg(key);
-       const char *p = strchr(kma + 1, ':');
+       const char *kma, *p;
        char *result;
        int len;
 
-       if (!p)
-               return NULL;
+       if (is_internal_key(key))
+               return get_internal_key_map_seq(key);
+       kma = get_user_key_map_arg(key);
+       p = strchr(kma + 1, ':');
+       assert(p); /* We checked earlier that kma contains a colon */
        len = p - kma;
        result = alloc(len + 1);
        memcpy(result, kma, len);
@@ -589,12 +588,6 @@ static char *get_user_key_map_seq(int key)
        return result;
 }
 
-static char *get_key_map_seq(int key)
-{
-       return is_internal_key(key)?
-               get_internal_key_map_seq(key) : get_user_key_map_seq(key);
-}
-
 static char *get_key_map_seq_safe(int key)
 {
        const char hex[] = "0123456789abcdef";
@@ -918,7 +911,7 @@ static int com_jmp(struct lls_parse_result *lpr)
                return com_next(NULL);
        if (pt->playing && !pt->fn.btrn)
                return 0;
-       pt->start_chunk = percent * pt->num_chunks / 100;
+       pt->start_chunk = (uint64_t)percent * pt->num_chunks / 100;
        if (!pt->playing)
                return 0;
        pt->rq = CRT_REPOS;
@@ -948,7 +941,7 @@ static int com_ff(struct lls_parse_result *lpr)
        seconds += (get_play_time() + 500) / 1000;
        seconds = PARA_MIN(seconds, (typeof(seconds))pt->seconds - 4);
        seconds = PARA_MAX(seconds, 0);
-       pt->start_chunk = pt->num_chunks * seconds / pt->seconds;
+       pt->start_chunk = (uint64_t)pt->num_chunks * seconds / pt->seconds;
        pt->start_chunk = PARA_MIN(pt->start_chunk, pt->num_chunks - 1);
        pt->start_chunk = PARA_MAX(pt->start_chunk, 0UL);
        if (!pt->playing)
@@ -1044,17 +1037,14 @@ static void session_open(void)
        if (OPT_GIVEN(HISTORY_FILE))
                history_file = para_strdup(OPT_STRING_VAL(HISTORY_FILE));
        else {
-               char *home = para_homedir();
-               char *dot_para = make_message("%s/.paraslash", home);
+               const char *confdir = get_confdir();
 
-               free(home);
-               ret = para_mkdir(dot_para);
+               ret = para_mkdir(confdir);
                /* warn, but otherwise ignore mkdir error */
                if (ret < 0)
-                       PARA_WARNING_LOG("Can not create %s: %s\n", dot_para,
+                       PARA_WARNING_LOG("Can not create %s: %s\n", confdir,
                                para_strerror(-ret));
-               history_file = make_message("%s/play.history", dot_para);
-               free(dot_para);
+               history_file = make_message("%s/play.history", confdir);
        }
        ici.history_file = history_file;
        ici.loglevel = loglevel;
@@ -1098,64 +1088,6 @@ static void session_update_time_string(char *str, unsigned len)
        i9e_print_status_bar(str, len);
 }
 
-/*
- * If we are about to die we must call i9e_close() to reset the terminal.
- * However, i9e_close() must be called in *this* context, i.e. from
- * play_task.post_monitor() rather than from i9e_post_monitor(), because
- * otherwise i9e would access freed memory upon return. So the play task must
- * stay alive until the i9e task terminates.
- *
- * We achieve this by sending a fake SIGTERM signal via i9e_signal_dispatch()
- * and reschedule. In the next iteration, i9e->post_monitor returns an error and
- * terminates. Subsequent calls to i9e_get_error() then return negative and we
- * are allowed to call i9e_close() and terminate as well.
- */
-static int session_post_monitor(__a_unused struct sched *s)
-{
-       int ret;
-
-       if (pt->background)
-               detach_stdout();
-       else
-               attach_stdout(__FUNCTION__);
-       ret = i9e_get_error();
-       if (ret < 0) {
-               kill_stream();
-               i9e_close();
-               para_log = stderr_log;
-               free(ici.history_file);
-               return ret;
-       }
-       if (get_playback_state() == 'X')
-               i9e_signal_dispatch(SIGTERM);
-       return 0;
-}
-
-#else /* HAVE_READLINE */
-
-static int session_post_monitor(struct sched *s)
-{
-       char c;
-
-       if (!sched_read_ok(STDIN_FILENO, s))
-               return 0;
-       if (read(STDIN_FILENO, &c, 1))
-               do_nothing;
-       kill_stream();
-       return 1;
-}
-
-static void session_open(void)
-{
-}
-
-static void session_update_time_string(char *str, __a_unused unsigned len)
-{
-       printf("\r%s     ", str);
-       fflush(stdout);
-}
-#endif /* HAVE_READLINE */
-
 static void play_pre_monitor(struct sched *s, __a_unused void *context)
 {
        char state;
@@ -1194,18 +1126,24 @@ static unsigned get_time_string(char **result)
        );
 }
 
-static int play_post_monitor(struct sched *s, __a_unused void *context)
+static int play_post_monitor(__a_unused struct sched *s, __a_unused void *context)
 {
-       int ret;
+       int ret, i9e_error;
 
+       if (pt->background)
+               detach_stdout();
+       else
+               attach_stdout(__FUNCTION__);
+       i9e_error = i9e_get_error();
        ret = eof_cleanup();
-       if (ret < 0) {
-               pt->rq = CRT_TERM_RQ;
-               return 0;
-       }
-       ret = session_post_monitor(s);
-       if (ret < 0)
-               goto out;
+       if (pt->rq == CRT_TERM_RQ || i9e_error < 0) /* com_quit() or CTRL+D */
+               kill_stream(); /* terminate receiver/filter/writer */
+       if ((ret < 0 || pt->rq == CRT_TERM_RQ) && i9e_error >= 0)
+               i9e_signal_dispatch(SIGTERM); /* terminate the i9e task */
+       if (ret < 0) /* unexpected error from the writer node */
+               return ret;
+       if (ret != 0 && i9e_error < 0) /* eof, and i9e has died */
+               return i9e_error;
        if (!pt->wn.btrn && !pt->fn.btrn) {
                char state = get_playback_state();
                if (state == 'P' || state == 'R' || state == 'F') {
@@ -1214,8 +1152,7 @@ static int play_post_monitor(struct sched *s, __a_unused void *context)
                        if (ret < 0) {
                                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                                pt->rq = CRT_TERM_RQ;
-                               ret = 1;
-                               goto out;
+                               return 1;
                        }
                        pt->next_update = *now;
                }
@@ -1229,9 +1166,7 @@ static int play_post_monitor(struct sched *s, __a_unused void *context)
                free(str);
                tv_add(now, &delay, &pt->next_update);
        }
-       ret = 1;
-out:
-       return ret;
+       return 1;
 }
 
 /**
@@ -1278,7 +1213,12 @@ int main(int argc, char *argv[])
        }, &sched);
        ret = schedule(&sched);
        sched_shutdown(&sched);
+       i9e_close();
+       wipe_receiver_node();
+       para_log = stderr_log;
+       free(ici.history_file);
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+       free(get_confdir());
        return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 72cb3f62ea766ee7ed94e3a68ed5a17591f2f133..6d4599a8f6718a4fafa7c3f2cf1e2296002609ac 100644 (file)
@@ -28,7 +28,8 @@ struct resample_context {
        struct check_wav_context *cwc;
 };
 
-static int resample_execute(struct btr_node *btrn, const char *cmd, char **result)
+static int resample_execute(const struct btr_node *btrn, const char *cmd,
+               char **result)
 {
        struct filter_node *fn = btr_context(btrn);
        struct resample_context *ctx = fn->private_data;
index ea9cc9c003616762a96aa546c381d54417fd34a2..229a146de36aab2f8585be8c662c476b0e93e16e 100644 (file)
--- a/server.c
+++ b/server.c
@@ -228,18 +228,12 @@ void parse_config_or_die(bool reload)
                daemon_set_flag(DF_LOG_TIMING);
        daemon_set_priority(OPT_UINT32_VAL(PRIORITY));
        if (!reload || getpid() != afs_pid) {
-               char *user_list_file;
-               if (OPT_GIVEN(USER_LIST))
-                       user_list_file = para_strdup(OPT_STRING_VAL(USER_LIST));
-               else {
-                       char *home = para_homedir();
-                       user_list_file = make_message("%s/.paraslash/server.users", home);
-                       free(home);
-               }
+               char *user_list_file = OPT_GIVEN(USER_LIST)?
+                       para_strdup(OPT_STRING_VAL(USER_LIST)) :
+                       make_message("%s/server.users", get_confdir());
                user_list_init(user_list_file);
                free(user_list_file);
        }
-       return;
 }
 
 /*
@@ -693,5 +687,6 @@ int main(int argc, char *argv[])
        shm_detach(mmd);
        user_list_deplete();
        free_lpr();
+       free(get_confdir());
        exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
 }
index 08eac02a557b2d503646666edd7ffb35e1c5c5f7..ce72125e125951feb2a14bd0add6e61762e77b1a 100644 (file)
@@ -102,7 +102,7 @@ static void speexdec_close(struct filter_node *fn)
        fn->private_data = NULL;
 }
 
-static int speexdec_execute(struct btr_node *btrn, const char *cmd,
+static int speexdec_execute(const struct btr_node *btrn, const char *cmd,
                char **result)
 {
        struct filter_node *fn = btr_context(btrn);
index d8bd027b7010a149be59b8883b3e5ee685fb3c01..56f1443fe72f5a016fc685cc652b2796477f6359 100644 (file)
--- a/string.c
+++ b/string.c
@@ -308,32 +308,33 @@ __must_check __malloc char *para_logname(void)
 }
 
 /**
- * Get the home directory of the calling user.
+ * Return the expansion of $HOME/.paraslash.
  *
- * \return A dynamically allocated string that must be freed by the caller. If
- * no entry is found which matches the UID of the calling process, or any other
- * error occurs, the function prints an error message and aborts.
+ * If the environment variable HOME is unset or empty, the function prints an
+ * error message and aborts. Otherwise, on the first call the memory for the
+ * string is allocated and a pointer to this memory location is returned.
+ * Subsequent calls return a pointer to the memory that was allocated during
+ * the first call.
  *
- * \sa getpwuid(3), getuid(2).
+ * \return A pointer to a C string, allocated on the heap. Callers should make
+ * sure that free() is only called once.
+ *
+ * \sa getenv(3), getuid(2).
  */
-__must_check __malloc char *para_homedir(void)
+__malloc char *get_confdir(void)
 {
-       struct passwd *pw;
-
-       /*
-        * To distinguish between the error case and the "not found" case we
-        * have to check errno after getpwuid(3). The manual page recommends to
-        * set it to zero before the call.
-        */
-       errno = 0;
-       pw = getpwuid(getuid());
-       if (pw)
-               return para_strdup(pw->pw_dir);
-       if (errno != 0)
-               PARA_EMERG_LOG("getpwuid error: %s\n", strerror(errno));
-       else
-               PARA_EMERG_LOG("no pw entry for uid %u\n", (unsigned)getuid());
-       exit(EXIT_FAILURE);
+       static char *dot_para;
+       const char *home;
+
+       if (dot_para)
+               return dot_para;
+       home = getenv("HOME");
+       if (!home || !*home) {
+               PARA_EMERG_LOG("fatal: HOME is unset or empty");
+               exit(EXIT_FAILURE);
+       }
+       dot_para = make_message("%s/.paraslash", home);
+       return dot_para;
 }
 
 /**
index d773600fbf0a0168584235a5098beabb110a3416..f59f2d286020ae10417cba76be1af80589ed37c8 100644 (file)
--- a/string.h
+++ b/string.h
@@ -80,7 +80,7 @@ __printf_2_3 unsigned xasprintf(char **result, const char *fmt, ...);
 __must_check __malloc __printf_1_2 char *make_message(const char *fmt, ...);
 __must_check __malloc char *para_strcat(char *a, const char *b);
 __must_check __malloc char *para_logname(void);
-__must_check __malloc char *para_homedir(void);
+__malloc char *get_confdir(void);
 __malloc char *para_hostname(void);
 __printf_2_3 int para_printf(struct para_buffer *b, const char *fmt, ...);
 int para_atoi64(const char *str, int64_t *result);
index 904c779353bbd5e08dfab8e449e607dead8a622c..1ef3ac696f42a78df6942cccd34958341b9044c6 100644 (file)
@@ -7,7 +7,7 @@ test_options := --executables-dir $(shell pwd)
 test_options += --results-dir $(results_dir)
 test_options += --trash-dir $(trash_dir)
 test_options += --executables "$(prefixed_executables)"
-test_options += --objects "$(basename $(all_objs))"
+test_options += --objects "$(basename $(dep_objs))"
 test_options += --man-dir $(man_dir)
 
 ifdef V
index ee1949c05a04d4fd4b81f2b9c847a403a753e2f5..307be1240a559dd5b8a1773a0b1dc1c2447e1a4f 100755 (executable)
@@ -58,7 +58,12 @@ else
                "grep_man '$regex' server"
 fi
 
-# para_play is always built
-regex='LIST OF COMMANDS.\{100,\}'
-test_expect_success 'para_play: play commands' "grep_man '$regex' play"
+test_require_objects 'play'
+missing_objects="$result"
+if [[ -n "$missing_objects" ]]; then
+       test_skip 'para_play' "missing object(s): $missing_objects"
+else
+       regex='LIST OF COMMANDS.\{100,\}'
+       test_expect_success 'para_play: play commands' "grep_man '$regex' play"
+fi
 test_done
index 487d46c06f2ce1df61630aaa34ca44dc99fb1d86..39bd6686a3c09949fb127b37380c441223aab224 100644 (file)
@@ -76,21 +76,18 @@ static char *src_db_dir, *dst_db_dir, *src_aft_dir, *dst_aft_dir;
 
 static void set_paths(const struct lls_parse_result *lpr)
 {
-       char *home = para_homedir();
+       const char *confdir = get_confdir();
 
        if (OPT_GIVEN(SRC_DATABASE_DIR, lpr))
                src_db_dir = para_strdup(OPT_STRING_VAL(SRC_DATABASE_DIR,
                        lpr));
        else
-               src_db_dir = make_message(
-                       "%s/.paraslash/afs_database-0.4", home);
+               src_db_dir = make_message("%s/afs_database-0.4", confdir);
        if (OPT_GIVEN(DST_DATABASE_DIR, lpr))
                dst_db_dir = para_strdup(OPT_STRING_VAL(DST_DATABASE_DIR,
                        lpr));
        else
-               dst_db_dir = make_message(
-                       "%s/.paraslash/afs_database-0.7", home);
-       free(home);
+               dst_db_dir = make_message("%s/afs_database-0.7", confdir);
        src_aft_dir = make_message("%s/audio_files", src_db_dir);
        dst_aft_dir = make_message("%s/audio-files", src_db_dir);
        PARA_NOTICE_LOG("source aft dir: %s\n", src_aft_dir);
index f188ff2566ad30645365e73aa62e399439dfbf5e..452fa3574f4e051627d62ecd24242d63fa0c7350 100644 (file)
@@ -19,7 +19,7 @@ Unix systems. It is written in C and released under the GPLv2. </p>
 <p> Author: Andre Noll, <a
 href="mailto:maan@tuebingen.mpg.de">maan@tuebingen.mpg.de</a>,
 Homepage: <a
-href="http://people.tuebingen.mpg.de/maan/">http://people.tuebingen.mpg.de/maan/</a>
+href="https://people.tuebingen.mpg.de/maan/">https://people.tuebingen.mpg.de/maan/</a>
 </p>
 
 <p> Comments and bug reports are welcome. Please provide the version
index 2b31e5d76c7f9f7c348ba08f852dc6c5a5780f73..1287597e20cdb4bc3c002e9e28447626819e8401 100644 (file)
@@ -11,7 +11,7 @@ source: </p>
                Clone the git repository by executing
 
                <pre> <kbd>
-                       git clone git://git.tuebingen.mpg.de/paraslash.git
+                       git clone https://git.tuebingen.mpg.de/paraslash.git
                </kbd> </pre>
 
                <p> The repository contains the full history of the
@@ -66,7 +66,7 @@ source: </p>
 
                The
 
-                       <a href="http://git.tuebingen.mpg.de/paraslash.git">gitweb</a>
+                       <a href="https://git.tuebingen.mpg.de/paraslash.git">gitweb</a>
 
                page contains a snapshot link for each revision. This
                allows getting a specific revision without downloading
index 9524182c292882b12c3efceccfc2a8e57da7a610..c52fd4a2fa2d580b46e7a4dad1d989509604b6c1 100644 (file)
Binary files a/web/images/signature.png and b/web/images/signature.png differ
index 4b1b472d1624129c109f0aa4688418f4b11b9bb2..596b53a1267d3be6cbe05f241837f7a2649b3fa0 100644 (file)
Binary files a/web/images/tar-icon.png and b/web/images/tar-icon.png differ
index b5329ea07f3d8a2f9553f384c9129c4ad1a262e3..3c49d6fb8601b03b0e9b5908f34307faaae61e38 100644 (file)
@@ -14,7 +14,7 @@ Introduction
 
 In this chapter we give an [overview](#Overview) of the interactions
 of the programs contained in the paraslash package, followed by
-[brief descriptions](#The.paraslash.executables) of all executables.
+[brief descriptions](#The-paraslash-executables) of all executables.
 
 Overview
 --------
@@ -135,7 +135,7 @@ fine-grained selection based on various properties of the audio file,
 including information found in (ID3) tags. Simple playlists are also
 supported. It is possible to store images (album covers) and lyrics
 in the database and associate these to the corresponding audio files.
-The section on the [audio file selector](#The.audio.file.selector)
+The section on the [audio file selector](#The-audio-file-selector)
 discusses this topic in more detail.
 
 Another component of para_server is the virtual streaming system,
@@ -287,9 +287,9 @@ Requirements
 ------------
 <h3> For the impatient </h3>
 
-       git clone git://git.tuebingen.mpg.de/lopsub
+       git clone https://git.tuebingen.mpg.de/lopsub
        cd lopsub && make && sudo make install
-       git clone git://git.tuebingen.mpg.de/osl
+       git clone https://git.tuebingen.mpg.de/osl
        cd osl && make && sudo make install && sudo ldconfig
        sudo apt-get install autoconf libssl-dev m4 \
               libmad0-dev libid3tag0-dev libasound2-dev libvorbis-dev \
@@ -306,7 +306,7 @@ option parser for subcommands generates the command line and config
 file parsers for all paraslash executables. Clone the source code
 repository with
 
-               git clone git://git.tuebingen.mpg.de/lopsub
+               git clone https://git.tuebingen.mpg.de/lopsub
 
 - [gcc](ftp://ftp.gnu.org/pub/gnu/gcc) or
 [clang](http://clang.llvm.org). All gcc versions >= 5.4 are currently
@@ -324,11 +324,11 @@ from templates by the m4 macro processor.
 
 Optional:
 
-- [libosl](http://people.tuebingen.mpg.de/maan/osl/). The _object
+- [libosl](https://people.tuebingen.mpg.de/maan/osl/). The _object
 storage layer_ library is used by para_server. To clone the source
 code repository, execute
 
-               git clone git://git.tuebingen.mpg.de/osl
+               git clone https://git.tuebingen.mpg.de/osl
 
 - [openssl](https://www.openssl.org/) or
 [libgcrypt](ftp://ftp.gnupg.org/gcrypt/libgcrypt/).  At least one
@@ -339,7 +339,7 @@ to install the development package (`libssl-dev` or `libgcrypt-dev`
 on debian systems) as well.
 
 - [flex](https://github.com/westes/flex) and
-[bison](https://www.gnu.org/software/bison) are needed to build the
+[bison](https://www.gnu.org/software/bison/) are needed to build the
 mood parser of para_server. The build system will skip para_server
 if these tools are not installed.
 
@@ -384,10 +384,10 @@ the ao writer (ESD, PulseAudio,...).  Debian package: `libao-dev`.
 - [curses](ftp://ftp.gnu.org/pub/gnu/ncurses). Needed for
 para_gui. Debian package: `libncurses-dev`.
 
-- [GNU
-Readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html). If
-this library (`libreadline-dev`) is installed, para_client, para_audioc
-and para_play support interactive sessions.
+- [GNU Readline](https://www.gnu.org/software/readline/). Only if
+this library (`libreadline-dev`) is installed, para_play is built,
+Without it, para_client(1) and para_audioc(1) still work, but lack
+support for interactive sessions.
 
 Installation
 ------------
@@ -523,7 +523,7 @@ starts streaming. To activate streaming, execute
 
 Since no playlist has been specified yet, the "dummy" mode which
 selects all known audio files is activated automatically. See the
-section on the [audio file selector](#The.audio.file.selector) for how
+section on the [audio file selector](#The-audio-file-selector) for how
 to use playlists and moods to specify which files should be streamed
 in which order.
 
@@ -555,12 +555,12 @@ authentication method. Authenticated connections are encrypted using
 the AES stream cipher in integer counter mode.
 
 In this chapter we briefly describe RSA and AES, and sketch the
-[authentication handshake](#Client-server.authentication)
+[authentication handshake](#Client-2d-server-authentication)
 between para_client and para_server. User management is discussed
-in the section on [the user_list file](#The.user_list.file).
+in the section on [the user_list file](#The-user_list-file).
 These sections are all about communication between the client and the
 server. Connecting para_audiod is a different matter and is described
-in a [separate section](#Connecting.para_audiod).
+in a [separate section](#Connecting-para_audiod).
 
 RSA and AES
 -----------
@@ -635,8 +635,8 @@ infeasibility to invert the hash function.
 
 Neither para_server or para_client create RSA keys on their
 own. This has to be done once for each user as sketched in
-[Quick start](#Quick.start) and discussed in more detail
-[below](#The.user_list.file).
+[Quick start](#Quick-start) and discussed in more detail
+[below](#The-user_list-file).
 
 The user_list file
 ------------------
@@ -708,13 +708,13 @@ maintains tables containing images (e.g. album cover art) and lyrics
 that can be associated with one or more audio files.
 
 In this chapter we sketch the setup of the [AFS
-process](#The.AFS.process) during server startup and proceed with the
-description of the [layout](#Database.layout) of the various database
-tables. The section on [playlists and moods](#Playlists.and.moods)
+process](#The-AFS-process) during server startup and proceed with the
+description of the [layout](#Database-layout) of the various database
+tables. The section on [playlists and moods](#Playlists-and-moods)
 explains these two audio file selection mechanisms in detail
 and contains practical examples. The way [file renames and content
-changes](#File.renames.and.content.changes) are detected is discussed
-briefly before the [Troubleshooting](#Troubleshooting) section
+changes](#File-renames-and-content-changes) are detected is discussed
+briefly before the [Troubleshooting](#Common-problems) section
 concludes the chapter.
 
 The AFS process
@@ -774,7 +774,7 @@ entry with metadata obtained from the audio format handler is added
 to the database.
 
 Note that AFS employs
-[libosl](http://people.tuebingen.mpg.de/maan/osl/), the object
+[libosl](https://people.tuebingen.mpg.de/maan/osl/), the object
 storage layer library, as the database backend. This library offers
 functionality similar to a relational database, but is much more
 lightweight than a full featured database management system.
@@ -1166,7 +1166,7 @@ data remains as before.
 It is possible to change the behaviour of the add command by using the
 "-l" (lazy add) or the "-f" (force add) option.
 
-Troubleshooting
+Common problems
 ---------------
 
 Use the debug loglevel (-l debug) to show debugging info. All paraslash
@@ -1349,12 +1349,12 @@ used. For these data connections, a variety of transports (UDP, DCCP,
 HTTP) can be chosen.
 
 The chapter starts with the [control
-service](#The.paraslash.control.service), followed by a section
-on the various [streaming protocols](#Streaming.protocols)
+service](#The-paraslash-control-service), followed by a section
+on the various [streaming protocols](#Streaming-protocols)
 in which the data connections are described. The way
 audio file headers are embedded into the stream is discussed
-[briefly](#Streams.with.headers.and.headerless.streams) before the
-[example section](#Networking.examples) which illustrates typical
+[briefly](#Streams-with-headers-and-headerless-streams) before the
+[example section](#Networking-examples) which illustrates typical
 commands for real-life scenarios.
 
 Both IPv4 and IPv6 are supported.
@@ -1374,7 +1374,7 @@ is unaffected if the child dies or goes crazy for whatever reason. In
 fact, the child process can not change address space of server process.
 
 The section on [client-server
-authentication](#Client-server.authentication) above described the
+authentication](#Client-2d-server-authentication) above described the
 early connection establishment from the crypto point of view. Here
 it is described what happens after the connection (including crypto
 setup) has been established.  There are four processes involved during
@@ -1442,7 +1442,7 @@ only for Linux.
 
 - UDP. Recommended for multicast LAN streaming.
 
-See the Appendix on [network protocols](#Network.protocols)
+See the Appendix on [network protocols](#Network-protocols)
 for brief descriptions of the various protocols relevant for network
 audio streaming with paraslash.
 
@@ -1513,7 +1513,7 @@ be configured via the FEC parameters which are dictated by server
 and may also be configured through the "sender" command.  The FEC
 parameters are encoded in the header of each network packet, so no
 configuration is necessary on the receiver side. See the section on
-[FEC](#Forward.error.correction) below.
+[FEC](#Forward-error-correction) below.
 
 Streams with headers and headerless streams
 -------------------------------------------
@@ -1653,7 +1653,7 @@ executables. For example, the mp3dec filter depends on the mad library.
 Forward error correction
 ------------------------
 
-As already mentioned [earlier](#Streaming.protocols), paraslash
+As already mentioned [earlier](#Streaming-protocols), paraslash
 uses forward error correction (FEC) for the unreliable UDP and
 DCCP transports. FEC is a technique which was invented already in
 1960 by Reed and Solomon and which is widely used for the parity
@@ -1884,8 +1884,8 @@ shown by this theme. See gui_theme.c for examples.
 
 The "." and "," keys are used to switch between themes.
 
-Examples
---------
+Gui examples
+------------
 
 -> Show server info:
 
@@ -1953,8 +1953,8 @@ from tar balls) and for contributing non-trivial changes to the
 paraslash project, some additional tools should be installed on a
 developer machine.
 
-- [git](http://git.or.cz/). As described in more detail
-[below](#Git.branches), the git source code management tool is used for
+- [git](https://git-scm.com/). As described in more detail
+[below](#Git-branches), the git source code management tool is used for
 paraslash development. It is necessary for cloning the git repository
 and for getting updates.
 
@@ -1967,7 +1967,7 @@ HTML version of this manual and some of the paraslash web pages are
 written in the Markdown markup language and are translated into html
 with the converter of the *Discount* package.
 
-- [doxygen](http://www.stack.nl/~dimitri/doxygen/). The documentation
+- [doxygen](https://www.doxygen.nl/). The documentation
 of paraslash's C sources uses the doxygen documentation system. The
 conventions for documenting the source code is described in the
 [Doxygen section](#Doxygen).
@@ -2294,54 +2294,42 @@ and contributed significant improvements.
 References
 ==========
 
-Articles
---------
-- [Polynomial Codes over Certain Finite
-Fields](http://kom.aau.dk/~heb/kurser/NOTER/KOFA01.PDF) by Reed, Irving
-S.; Solomon, Gustave (1960), Journal of the Society for Industrial
-and Applied Mathematics (SIAM) 8 (2): 300-304, doi:10.1137/0108018)
-
 RFCs
 ----
 
-- [RFC 768](http://www.ietf.org/rfc/rfc768.txt) (1980): User Datagram
+- [RFC 768](https://www.ietf.org/rfc/rfc768.txt) (1980): User Datagram
 Protocol
 
-- [RFC 791](http://www.ietf.org/rfc/rfc791.txt) (1981): Internet
+- [RFC 791](https://www.ietf.org/rfc/rfc791.txt) (1981): Internet
 Protocol
 
-- [RFC 2437](http://www.ietf.org/rfc/rfc2437.txt) (1998): RSA
+- [RFC 2437](https://www.ietf.org/rfc/rfc2437.txt) (1998): RSA
 Cryptography Specifications
 
-- [RFC 4340](http://www.ietf.org/rfc/rfc4340.txt) (2006): Datagram
+- [RFC 4340](https://www.ietf.org/rfc/rfc4340.txt) (2006): Datagram
 Congestion Control Protocol (DCCP)
 
-- [RFC 4341](http://www.ietf.org/rfc/rfc4341.txt) (2006): Congestion
+- [RFC 4341](https://www.ietf.org/rfc/rfc4341.txt) (2006): Congestion
 Control ID 2: TCP-like Congestion Control
 
-- [RFC 4342](http://www.ietf.org/rfc/rfc4342.txt) (2006): Congestion
+- [RFC 4342](https://www.ietf.org/rfc/rfc4342.txt) (2006): Congestion
 Control ID 3: TCP-Friendly Rate Control (TFRC)
 
-- [RFC 6716](http://www.ietf.org/rfc/rfc6716.txt) (2012): Definition
+- [RFC 6716](https://www.ietf.org/rfc/rfc6716.txt) (2012): Definition
 of the Opus Audio Codec
 
 Application web pages
 ---------------------
 
-- [paraslash](http://people.tuebingen.mpg.de/maan/paraslash/)
-- [xmms](https://xmms2.org/wiki/Main_Page)
+- [paraslash](https://people.tuebingen.mpg.de/maan/paraslash/)
 - [mpg123](http://www.mpg123.de/)
 - [gstreamer](https://gstreamer.freedesktop.org/)
-- [icecast](http://www.icecast.org/)
-- [Audio Compress](https://beesbuzz.biz/code/audiocompress.php)
+- [icecast](https://www.icecast.org/)
+- [Audio Compress](https://github.com/fluffy-critter/audiocompress)
 
 External documentation
 ----------------------
 
-- [The mathematics of
-Raid6](https://www.kernel.org/pub/linux/kernel/people/hpa/raid6.pdf)
-by H. Peter Anvin
-
 - [Effective Erasure Codes for reliable Computer Communication
 Protocols](http://info.iet.unipi.it/~luigi/fec_ccr.ps.gz) by Luigi
 Rizzo
index 2043fbb70b2afdf9ef243200920910bf564f2a1e..3a928c058a53aa4156d4fb4473b5d4d8f6cc0b3e 100644 (file)
@@ -2,6 +2,8 @@ body {
        font-family: sans-serif;
        background-color: black;
        color: #bbbbbb;
+       text-align: justify;
+       padding: 0px 40px 40px 40px;
        margin: 20px;
 }
 
index f2ca273cd08979f33b42ab0a7f84b533fe29a583..5b3d9874bf5f905ef19c6b3689fd8006ad95c759 100644 (file)
@@ -1147,7 +1147,8 @@ static void wmadec_close(struct filter_node *fn)
        fn->private_data = NULL;
 }
 
-static int wmadec_execute(struct btr_node *btrn, const char *cmd, char **result)
+static int wmadec_execute(const struct btr_node *btrn, const char *cmd,
+               char **result)
 {
        struct filter_node *fn = btr_context(btrn);
        struct private_wmadec_data *pwd = fn->private_data;