]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge topic branch t/sf_float into pu
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 17 Mar 2024 11:38:23 +0000 (12:38 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 17 Mar 2024 11:38:23 +0000 (12:38 +0100)
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).

31 files changed:
Makefile.in
Makefile.real
aacdec_filter.c
afh_recv.c
audiod.c
audiod.h
buffer_tree.c
buffer_tree.h
check_wav.c
client_common.c
command.c
configure.ac
crypt.h
error.h
filter.c
filter_common.c
flacdec_filter.c
gcrypt.c
interactive.c
list.h
mp3dec_filter.c
oggdec_filter.c
openssl.c
opusdec_filter.c
play.c
resample_filter.c
spxdec_filter.c
t/makefile.test
t/t0005-man.sh
web/manual.md
wmadec_filter.c

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
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;
index 7c223995a9a29cec3c8e8ae5497c3be58655f63c..3e86af537431ff67b00a47694fcaa506dea41837 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));
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 fe8234f98fe90f6ce74ea5e22699fbfc0059a042..396fd88c894cda20e4f55a7955a9a4fe77e9633d 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;
index 60c2aeba4300124c51af13d03c522fe2c2bbb1f1..42152ca8cbfff616df68abf050816a3a3e670fef 100644 (file)
--- a/command.c
+++ b/command.c
@@ -917,7 +917,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 +938,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 +958,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..2bba8129b92a834a998a1aea84fee9b475e3cdde 100644 (file)
@@ -5,7 +5,6 @@ AC_INIT([paraslash], [m4_esyscmd_s(./GIT-VERSION-GEN)],
 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])
@@ -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"), \
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..7966b806f0745bfc6d35b630693ef31e285ac3a8 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)
@@ -105,12 +106,10 @@ 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:
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/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)
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;
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..c9a9f7d7e8a69a0d2db51d3fdbdc8e04aec1c6d7 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";
@@ -1098,64 +1091,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 +1129,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 +1155,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 +1169,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,6 +1216,10 @@ 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));
        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 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 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 b5329ea07f3d8a2f9553f384c9129c4ad1a262e3..a2942d71ac6d1f63aab3ec8a08ee2cc7c516fe1f 100644 (file)
@@ -385,9 +385,10 @@ the ao writer (ESD, PulseAudio,...).  Debian package: `libao-dev`.
 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.
+Readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html). 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
 ------------
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;