Installing lopsub
~~~~~~~~~~~~~~~~~
- git clone git://git.tuebingen.mpg.de/lopsub
+ git clone https://git.tuebingen.mpg.de/lopsub
cd lopsub && make && sudo make install
- (see http://people.tuebingen.mpg.de/maan/lopsub/)
+ (see https://people.tuebingen.mpg.de/maan/lopsub/)
Installing osl
~~~~~~~~~~~~~~
- git clone git://git.tuebingen.mpg.de/osl
+ git clone https://git.tuebingen.mpg.de/osl
cd osl && make && sudo make install
- (see http://people.tuebingen.mpg.de/maan/osl/)
+ (see https://people.tuebingen.mpg.de/maan/osl/)
Installing paraslash from tarball
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For details see the user manual:
- http://people.tuebingen.mpg.de/maan/paraslash/manual.html
+ https://people.tuebingen.mpg.de/maan/paraslash/manual.html
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@
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")
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
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
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)
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
Distribution of paraslash is covered by the GNU GPL, version 2 unless
otherwise stated. See file COPYING.
-Web page: http://people.tuebingen.mpg.de/maan/paraslash/
-Gitweb: http://git.tuebingen.mpg.de/paraslash.git/
-Git URL: git://git.tuebingen.mpg.de/paraslash.git
+Web page: https://people.tuebingen.mpg.de/maan/paraslash/
+Gitweb: https://git.tuebingen.mpg.de/paraslash.git/
+Git URL: https://git.tuebingen.mpg.de/paraslash.git
Email: Andre Noll <maan@tuebingen.mpg.de>
Comments and bug reports are welcome.
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;
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;
static void get_database_dir(void)
{
if (!database_dir) {
- if (OPT_GIVEN(AFS_DATABASE_DIR))
- database_dir = para_strdup(OPT_STRING_VAL(AFS_DATABASE_DIR));
- else {
- char *home = para_homedir();
- database_dir = make_message(
- "%s/.paraslash/afs_database-0.7", home);
- free(home);
- }
+ database_dir = OPT_GIVEN(AFS_DATABASE_DIR)?
+ para_strdup(OPT_STRING_VAL(AFS_DATABASE_DIR)) :
+ make_message("%s/afs_database-0.7", get_confdir());
}
PARA_INFO_LOG("afs_database dir %s\n", database_dir);
}
opts->mode = LS_MODE_SHORT;
else if (!strcmp(val, "v") || !strcmp(val, "verbose"))
opts->mode = LS_MODE_VERBOSE;
- else if (!strcmp(val, "m") || !strcmp(val, "mbox"))
+ else if (!strcmp(val, "m") || !strcmp(val, "mbox")) {
+ send_sb_va(&cc->scc, SBD_WARNING_LOG,
+ "Warning: mbox listing mode is deprecated\n");
opts->mode = LS_MODE_MBOX;
- else if (!strcmp(val, "c") || !strcmp(val, "chunk-table"))
+ } else if (!strcmp(val, "c") || !strcmp(val, "chunk-table")) {
+ send_sb_va(&cc->scc, SBD_WARNING_LOG,
+ "Warning: chunk table listing mode is deprecated\n");
opts->mode = LS_MODE_CHUNKS;
- else if (!strcmp(val, "p") || !strcmp(val, "parser-friendly"))
+ } else if (!strcmp(val, "p") || !strcmp(val, "parser-friendly"))
opts->mode = LS_MODE_PARSER;
else {
ret = -ERRNO_TO_PARA_ERROR(EINVAL);
__noreturn static void interactive_session(void)
{
int ret;
- char *history_file;
struct sigaction act;
struct i9e_client_info ici = {
.fds = {0, 1, 2},
};
PARA_NOTICE_LOG("\n%s\n", version_text("audioc"));
- if (OPT_GIVEN(HISTORY_FILE))
- history_file = para_strdup(OPT_STRING_VAL(HISTORY_FILE));
- else {
- char *home = para_homedir();
- history_file = make_message("%s/.paraslash/audioc.history",
- home);
- free(home);
- }
- ici.history_file = history_file;
-
+ ici.history_file = OPT_GIVEN(HISTORY_FILE)?
+ para_strdup(OPT_STRING_VAL(HISTORY_FILE)) :
+ make_message("%s/audioc.history", get_confdir());
act.sa_handler = i9e_signal_dispatch;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
i9e_close();
para_log = stderr_log;
out:
- free(history_file);
+ free(ici.history_file);
free(socket_name);
if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
#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 {
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));
PARA_ERROR_LOG("%s\n", errctx);
if (ret < 0)
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+ free(get_confdir());
return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
}
/** \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 */
* \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);
* 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);
}
* 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;
* \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;
* 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;
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;
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.
*/
}
}
+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)
{
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;
}
*
* \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);
}
* 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;
}
*
* \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) {
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;
* 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;
* 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);
}
* 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;
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.
*
* \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;
*
* \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;
*
* \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);
}
}
-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);
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;
* \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);
}
* 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))
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);
}
/**
*
* 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;
}
* \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;
}
/**
* \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
* 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);
/**
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);
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;
};
PARA_NOTICE_LOG("\n%s\n", version_text("client"));
- if (CLIENT_OPT_GIVEN(HISTORY_FILE, ct->lpr))
- ici.history_file = para_strdup(CLIENT_OPT_STRING_VAL(
- HISTORY_FILE, ct->lpr));
- else {
- char *home = para_homedir();
- ici.history_file = make_message("%s/.paraslash/client.history",
- home);
- free(home);
- }
+ ici.history_file = CLIENT_OPT_GIVEN(HISTORY_FILE, ct->lpr)?
+ para_strdup(CLIENT_OPT_STRING_VAL(HISTORY_FILE, ct->lpr)) :
+ make_message("%s/client.history", get_confdir());
act.sa_handler = i9e_signal_dispatch;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
i9e_close();
para_log = stderr_log;
out:
+ free(ici.history_file);
if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
client_close(ct);
btr_remove_node(&sit.btrn);
btr_remove_node(&sot.btrn);
+ free(get_confdir());
return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
}
*/
{
/* decrypted challenge/session key buffer */
- unsigned char crypt_buf[1024];
+ unsigned char *crypt_buf;
struct sb_buffer sbb;
ret = recv_sb(ct, &sbb);
}
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,
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;
struct lls_parse_result *lpr;
int ret, ll;
struct client_task *ct;
- char *kf = NULL, *user, *errctx, *home = para_homedir();
+ char *kf = NULL, *user, *errctx;
ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx));
if (ret < 0)
kf = para_strdup(CLIENT_OPT_STRING_VAL(KEY_FILE, lpr));
else {
struct stat statbuf;
- kf = make_message("%s/.paraslash/key.%s", home, user);
+ const char *confdir = get_confdir();
+ kf = make_message("%s/key.%s", confdir, user);
if (stat(kf, &statbuf) != 0) { /* assume file does not exist */
+ const char *home = getenv("HOME");
+ assert(home); /* get_confdir() above succeeded */
free(kf);
kf = make_message("%s/.ssh/id_rsa", home);
}
*ct_ptr = ct;
ret = lls_num_inputs(lpr);
out:
- free(home);
if (ret < 0) {
if (errctx)
PARA_ERROR_LOG("%s\n", errctx);
#include "signal.h"
#include "version.h"
+/** \cond server_cmd_aux_info */
#define SERVER_CMD_AUX_INFO(_arg) _arg,
static const unsigned server_command_perms[] = {LSG_SERVER_CMD_AUX_INFOS};
#undef SERVER_CMD_AUX_INFO
#define SERVER_CMD_AUX_INFO(_arg) #_arg,
static const char * const server_command_perms_txt[] = {LSG_SERVER_CMD_AUX_INFOS};
#undef SERVER_CMD_AUX_INFO
+/** \endcond server_cmd_aux_info */
/** Commands including options must be shorter than this. */
#define MAX_COMMAND_LEN 32768
}
EXPORT_SERVER_CMD_HANDLER(version);
-/** These status items are cleared if no audio file is currently open. */
+/** \cond empty_status_items */
+/* These status items are cleared if no audio file is currently open. */
#define EMPTY_STATUS_ITEMS \
ITEM(path) \
ITEM(directory) \
ITEM(amplification) \
ITEM(play_time) \
+/** \endcond empty_status_items */
+
/*
* Create a set of audio-file related status items with empty values. These are
* written to stat clients when no audio file is open.
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;
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;
* 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,
AC_PREREQ([2.61])
AC_INIT([paraslash], [m4_esyscmd_s(./GIT-VERSION-GEN)],
- [maan@tuebingen.mpg.de], [], [http://people.tuebingen.mpg.de/maan/paraslash/])
+ [maan@tuebingen.mpg.de], [], [https://people.tuebingen.mpg.de/maan/paraslash/])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile])
-AC_DEFUN([add_dot_o],[$(for i in $@; do printf "$i.o "; done)])
AC_DEFUN([LIB_ARG_WITH], [
AC_ARG_WITH($1-headers, [AS_HELP_STRING(--with-$1-headers=dir,
[look for $1 headers in dir])])
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=
REQUIRE_EXECUTABLE([flex])
REQUIRE_EXECUTABLE([m4])
-executables="recv filter audioc write afh play"
########################################################################### osl
STASH_FLAGS
LIB_ARG_WITH([osl], [-losl])
The lopsub library is required to build this software, but
the above checks indicate it is not installed on your system.
Run the following command to download a copy.
- git clone git://git.tuebingen.mpg.de/lopsub.git
+ git clone https://git.tuebingen.mpg.de/lopsub.git
Install the library, then run this configure script again.
])
fi
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],
;;
esac
AC_SUBST(crypto_ldflags)
+AC_SUBST(CRYPTOLIB)
########################################################################## iconv
STASH_FLAGS
LIBS=
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])
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])
[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
-])
* \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.
*
*
* \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);
/**
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"), \
}
*pid = ret;
if (!(*pid)) { /* child */
- if (fds[0] >= 0) {
- if (fds[0]) {
- close(in[1]);
- if (in[0] != STDIN_FILENO)
- dup2(in[0], STDIN_FILENO);
- } else
- dup2(null, STDIN_FILENO);
+ if (fds[0] == 0)
+ dup2(null, STDIN_FILENO);
+ else if (fds[0] > 0) {
+ close(in[1]);
+ if (in[0] != STDIN_FILENO)
+ dup2(in[0], STDIN_FILENO);
}
- if (fds[1] >= 0) {
- if (fds[1]) {
- close(out[0]);
- if (out[1] != STDOUT_FILENO)
- dup2(out[1], STDOUT_FILENO);
- } else
- dup2(null, STDOUT_FILENO);
+ if (fds[1] == 0)
+ dup2(null, STDOUT_FILENO);
+ else if (fds[1] > 0) {
+ close(out[0]);
+ if (out[1] != STDOUT_FILENO)
+ dup2(out[1], STDOUT_FILENO);
}
- if (fds[2] >= 0) {
- if (fds[2]) {
- close(err[0]);
- if (err[1] != STDERR_FILENO)
- dup2(err[1], STDERR_FILENO);
- } else
- dup2(null, STDERR_FILENO);
+ if (fds[2] == 0)
+ dup2(null, STDERR_FILENO);
+ else if (fds[2] > 0) {
+ close(err[0]);
+ if (err[1] != STDERR_FILENO)
+ dup2(err[1], STDERR_FILENO);
}
if (null >= 0)
close(null);
*/
__must_check __malloc static char *random_filename(void)
{
- char *result, *home = para_homedir();
-
srandom(clock_get_realtime(NULL)->tv_usec);
- result = make_message("%s/.paraslash/%08ld", home,
- para_random(99999999));
- free(home);
- return result;
+ return make_message("%s/%08ld", get_confdir(), para_random(99999999));
}
static int prepare_output_file(struct writer_node *wn)
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);
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];
* 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)
{
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)
if (ret < 0)
goto free_argv;
f = filter_get(filter_num);
+ assert(f);
*conf = f->setup? f->setup(*lprp) : NULL;
ret = filter_num;
free_argv:
free_argv(argv);
if (ret >= 0)
return ret;
-fail:
if (errctx)
PARA_ERROR_LOG("%s\n", errctx);
free(errctx);
- PARA_EMERG_LOG("%s\n", para_strerror(-ret));
- exit(EXIT_FAILURE);
+ return ret;
}
/**
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);
struct asymmetric_key {
gcry_sexp_t sexp;
+ int bits;
};
static const char *gcrypt_strerror(gcry_error_t gret)
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:
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;
gcry_sexp_t in, out, priv_key;
size_t nbytes;
+ *outbuf = NULL;
ret = check_private_key_file(key_file);
if (ret < 0)
return ret;
}
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;
size_t nbytes;
int ret;
+ *outbuf = NULL;
/* get pub key */
pub_key = gcry_sexp_find_token(pub->sexp, "public-key", 0);
if (!pub_key)
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:
free(errctx);
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
}
+ free(get_confdir());
return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
}
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]);
{
int fd = open("/proc/sys/kernel/shmmax", O_RDONLY);
if (fd >= 0) {
- char buf[100] = "";
+ char buf[100];
int ret = read(fd, buf, sizeof(buf) - 1);
if (ret > 0) {
buf[ret] = '\0';
*/
#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)
struct lls_parse_result *old_lpr = *lpr, *cf_lpr, *merged_lpr;
const char *subcmd_name;
- if (path)
- cf = para_strdup(path);
- else {
- char *home = para_homedir();
- cf = make_message("%s/.paraslash/%s", home, dflt);
- free(home);
- }
+ cf = path? para_strdup(path) : make_message("%s/%s",
+ get_confdir(), dflt);
ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
if (ret < 0) {
if (ret == -E_EMPTY)
a length field.
mbox (m). Generate output suitable to be viewed with a mail
- program. One "mail" per matching audio file.
-
- chunk-table (c). Print path (or basename, depending on whether -p is
- also given), chunk time and chunk offsets.
+ program. One "mail" per matching audio file. This listing mode is
+ deprecated and will be removed after paraslash-0.8.0 has been released.
+ chunk-table (c). Print path (or basename, depending on whether -p
+ is also given), chunk time and chunk offsets. This listing mode is
+ deprecated and will be removed after paraslash-0.8.0 has been released.
[/help]
[option limit]
short_opt = L
lls_free_parse_result(sub_lpr, cmd);
free_lpr:
lls_free_parse_result(lpr, CMD_PTR(PARA_MIXER));
- if (ret >= 0)
- return EXIT_SUCCESS;
fail:
- if (errctx)
- PARA_ERROR_LOG("%s\n", errctx);
- free(errctx);
- PARA_EMERG_LOG("%s\n", para_strerror(-ret));
- return EXIT_FAILURE;
+ if (ret < 0) {
+ if (errctx)
+ PARA_ERROR_LOG("%s\n", errctx);
+ free(errctx);
+ PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+ }
+ free(get_confdir());
+ return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
}
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;
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;
}
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;
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;
return ret;
}
-/** A macro defining the atoms we care about. It gets expanded twice. */
+/** \cond atom_items */
+/* A macro defining the atoms we care about. It gets expanded twice. */
#define ATOM_ITEMS \
ATOM_ITEM(MOOV, 'm', 'o', 'o', 'v') /* movie (top-level container) */ \
ATOM_ITEM(TRAK, 't', 'r', 'a', 'k') /* container for a single track */ \
ATOM_ITEM(META, 'm', 'e', 't', 'a') /* iTunes Metadata box */ \
ATOM_ITEM(DATA, 'd', 'a', 't', 'a') /* iTunes Metadata data box */ \
+/** \endcond atom_items */
+
/** For the C enumeration we concatenate ATOM_ with the first argument. */
#define ATOM_ITEM(_name, a, b, c, d) ATOM_ ## _name,
/** The enumeration of interesting atoms. */
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;
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);
}
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 */
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)
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);
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;
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;
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.
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 {
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;
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);
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);
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);
#include "recv.h"
#include "write.h"
#include "fd.h"
+#include "interactive.h"
/** Array of error strings. */
DEFINE_PARA_ERRLIST;
int err;
if (!pt->wn.task)
- return 0;
+ return 1;
err = task_status(pt->wn.task);
if (err >= 0)
return 0;
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));
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)
{
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
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);
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";
return com_next(NULL);
if (pt->playing && !pt->fn.btrn)
return 0;
- pt->start_chunk = percent * pt->num_chunks / 100;
+ pt->start_chunk = (uint64_t)percent * pt->num_chunks / 100;
if (!pt->playing)
return 0;
pt->rq = CRT_REPOS;
seconds += (get_play_time() + 500) / 1000;
seconds = PARA_MIN(seconds, (typeof(seconds))pt->seconds - 4);
seconds = PARA_MAX(seconds, 0);
- pt->start_chunk = pt->num_chunks * seconds / pt->seconds;
+ pt->start_chunk = (uint64_t)pt->num_chunks * seconds / pt->seconds;
pt->start_chunk = PARA_MIN(pt->start_chunk, pt->num_chunks - 1);
pt->start_chunk = PARA_MAX(pt->start_chunk, 0UL);
if (!pt->playing)
if (OPT_GIVEN(HISTORY_FILE))
history_file = para_strdup(OPT_STRING_VAL(HISTORY_FILE));
else {
- char *home = para_homedir();
- char *dot_para = make_message("%s/.paraslash", home);
+ const char *confdir = get_confdir();
- free(home);
- ret = para_mkdir(dot_para);
+ ret = para_mkdir(confdir);
/* warn, but otherwise ignore mkdir error */
if (ret < 0)
- PARA_WARNING_LOG("Can not create %s: %s\n", dot_para,
+ PARA_WARNING_LOG("Can not create %s: %s\n", confdir,
para_strerror(-ret));
- history_file = make_message("%s/play.history", dot_para);
- free(dot_para);
+ history_file = make_message("%s/play.history", confdir);
}
ici.history_file = history_file;
ici.loglevel = loglevel;
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;
);
}
-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') {
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;
}
free(str);
tv_add(now, &delay, &pt->next_update);
}
- ret = 1;
-out:
- return ret;
+ return 1;
}
/**
}, &sched);
ret = schedule(&sched);
sched_shutdown(&sched);
+ i9e_close();
+ wipe_receiver_node();
+ para_log = stderr_log;
+ free(ici.history_file);
if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+ free(get_confdir());
return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
}
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;
daemon_set_flag(DF_LOG_TIMING);
daemon_set_priority(OPT_UINT32_VAL(PRIORITY));
if (!reload || getpid() != afs_pid) {
- char *user_list_file;
- if (OPT_GIVEN(USER_LIST))
- user_list_file = para_strdup(OPT_STRING_VAL(USER_LIST));
- else {
- char *home = para_homedir();
- user_list_file = make_message("%s/.paraslash/server.users", home);
- free(home);
- }
+ char *user_list_file = OPT_GIVEN(USER_LIST)?
+ para_strdup(OPT_STRING_VAL(USER_LIST)) :
+ make_message("%s/server.users", get_confdir());
user_list_init(user_list_file);
free(user_list_file);
}
- return;
}
/*
shm_detach(mmd);
user_list_deplete();
free_lpr();
+ free(get_confdir());
exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
}
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);
}
/**
- * Get the home directory of the calling user.
+ * Return the expansion of $HOME/.paraslash.
*
- * \return A dynamically allocated string that must be freed by the caller. If
- * no entry is found which matches the UID of the calling process, or any other
- * error occurs, the function prints an error message and aborts.
+ * If the environment variable HOME is unset or empty, the function prints an
+ * error message and aborts. Otherwise, on the first call the memory for the
+ * string is allocated and a pointer to this memory location is returned.
+ * Subsequent calls return a pointer to the memory that was allocated during
+ * the first call.
*
- * \sa getpwuid(3), getuid(2).
+ * \return A pointer to a C string, allocated on the heap. Callers should make
+ * sure that free() is only called once.
+ *
+ * \sa getenv(3), getuid(2).
*/
-__must_check __malloc char *para_homedir(void)
+__malloc char *get_confdir(void)
{
- struct passwd *pw;
-
- /*
- * To distinguish between the error case and the "not found" case we
- * have to check errno after getpwuid(3). The manual page recommends to
- * set it to zero before the call.
- */
- errno = 0;
- pw = getpwuid(getuid());
- if (pw)
- return para_strdup(pw->pw_dir);
- if (errno != 0)
- PARA_EMERG_LOG("getpwuid error: %s\n", strerror(errno));
- else
- PARA_EMERG_LOG("no pw entry for uid %u\n", (unsigned)getuid());
- exit(EXIT_FAILURE);
+ static char *dot_para;
+ const char *home;
+
+ if (dot_para)
+ return dot_para;
+ home = getenv("HOME");
+ if (!home || !*home) {
+ PARA_EMERG_LOG("fatal: HOME is unset or empty");
+ exit(EXIT_FAILURE);
+ }
+ dot_para = make_message("%s/.paraslash", home);
+ return dot_para;
}
/**
__must_check __malloc __printf_1_2 char *make_message(const char *fmt, ...);
__must_check __malloc char *para_strcat(char *a, const char *b);
__must_check __malloc char *para_logname(void);
-__must_check __malloc char *para_homedir(void);
+__malloc char *get_confdir(void);
__malloc char *para_hostname(void);
__printf_2_3 int para_printf(struct para_buffer *b, const char *fmt, ...);
int para_atoi64(const char *str, int64_t *result);
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
"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
static void set_paths(const struct lls_parse_result *lpr)
{
- char *home = para_homedir();
+ const char *confdir = get_confdir();
if (OPT_GIVEN(SRC_DATABASE_DIR, lpr))
src_db_dir = para_strdup(OPT_STRING_VAL(SRC_DATABASE_DIR,
lpr));
else
- src_db_dir = make_message(
- "%s/.paraslash/afs_database-0.4", home);
+ src_db_dir = make_message("%s/afs_database-0.4", confdir);
if (OPT_GIVEN(DST_DATABASE_DIR, lpr))
dst_db_dir = para_strdup(OPT_STRING_VAL(DST_DATABASE_DIR,
lpr));
else
- dst_db_dir = make_message(
- "%s/.paraslash/afs_database-0.7", home);
- free(home);
+ dst_db_dir = make_message("%s/afs_database-0.7", confdir);
src_aft_dir = make_message("%s/audio_files", src_db_dir);
dst_aft_dir = make_message("%s/audio-files", src_db_dir);
PARA_NOTICE_LOG("source aft dir: %s\n", src_aft_dir);
<p> Author: Andre Noll, <a
href="mailto:maan@tuebingen.mpg.de">maan@tuebingen.mpg.de</a>,
Homepage: <a
-href="http://people.tuebingen.mpg.de/maan/">http://people.tuebingen.mpg.de/maan/</a>
+href="https://people.tuebingen.mpg.de/maan/">https://people.tuebingen.mpg.de/maan/</a>
</p>
<p> Comments and bug reports are welcome. Please provide the version
Clone the git repository by executing
<pre> <kbd>
- git clone git://git.tuebingen.mpg.de/paraslash.git
+ git clone https://git.tuebingen.mpg.de/paraslash.git
</kbd> </pre>
<p> The repository contains the full history of the
The
- <a href="http://git.tuebingen.mpg.de/paraslash.git">gitweb</a>
+ <a href="https://git.tuebingen.mpg.de/paraslash.git">gitweb</a>
page contains a snapshot link for each revision. This
allows getting a specific revision without downloading
In this chapter we give an [overview](#Overview) of the interactions
of the programs contained in the paraslash package, followed by
-[brief descriptions](#The.paraslash.executables) of all executables.
+[brief descriptions](#The-paraslash-executables) of all executables.
Overview
--------
including information found in (ID3) tags. Simple playlists are also
supported. It is possible to store images (album covers) and lyrics
in the database and associate these to the corresponding audio files.
-The section on the [audio file selector](#The.audio.file.selector)
+The section on the [audio file selector](#The-audio-file-selector)
discusses this topic in more detail.
Another component of para_server is the virtual streaming system,
------------
<h3> For the impatient </h3>
- git clone git://git.tuebingen.mpg.de/lopsub
+ git clone https://git.tuebingen.mpg.de/lopsub
cd lopsub && make && sudo make install
- git clone git://git.tuebingen.mpg.de/osl
+ git clone https://git.tuebingen.mpg.de/osl
cd osl && make && sudo make install && sudo ldconfig
sudo apt-get install autoconf libssl-dev m4 \
libmad0-dev libid3tag0-dev libasound2-dev libvorbis-dev \
file parsers for all paraslash executables. Clone the source code
repository with
- git clone git://git.tuebingen.mpg.de/lopsub
+ git clone https://git.tuebingen.mpg.de/lopsub
- [gcc](ftp://ftp.gnu.org/pub/gnu/gcc) or
[clang](http://clang.llvm.org). All gcc versions >= 5.4 are currently
Optional:
-- [libosl](http://people.tuebingen.mpg.de/maan/osl/). The _object
+- [libosl](https://people.tuebingen.mpg.de/maan/osl/). The _object
storage layer_ library is used by para_server. To clone the source
code repository, execute
- git clone git://git.tuebingen.mpg.de/osl
+ git clone https://git.tuebingen.mpg.de/osl
- [openssl](https://www.openssl.org/) or
[libgcrypt](ftp://ftp.gnupg.org/gcrypt/libgcrypt/). At least one
on debian systems) as well.
- [flex](https://github.com/westes/flex) and
-[bison](https://www.gnu.org/software/bison) are needed to build the
+[bison](https://www.gnu.org/software/bison/) are needed to build the
mood parser of para_server. The build system will skip para_server
if these tools are not installed.
- [curses](ftp://ftp.gnu.org/pub/gnu/ncurses). Needed for
para_gui. Debian package: `libncurses-dev`.
-- [GNU
-Readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html). If
-this library (`libreadline-dev`) is installed, para_client, para_audioc
-and para_play support interactive sessions.
+- [GNU Readline](https://www.gnu.org/software/readline/). Only if
+this library (`libreadline-dev`) is installed, para_play is built,
+Without it, para_client(1) and para_audioc(1) still work, but lack
+support for interactive sessions.
Installation
------------
Since no playlist has been specified yet, the "dummy" mode which
selects all known audio files is activated automatically. See the
-section on the [audio file selector](#The.audio.file.selector) for how
+section on the [audio file selector](#The-audio-file-selector) for how
to use playlists and moods to specify which files should be streamed
in which order.
the AES stream cipher in integer counter mode.
In this chapter we briefly describe RSA and AES, and sketch the
-[authentication handshake](#Client-server.authentication)
+[authentication handshake](#Client-2d-server-authentication)
between para_client and para_server. User management is discussed
-in the section on [the user_list file](#The.user_list.file).
+in the section on [the user_list file](#The-user_list-file).
These sections are all about communication between the client and the
server. Connecting para_audiod is a different matter and is described
-in a [separate section](#Connecting.para_audiod).
+in a [separate section](#Connecting-para_audiod).
RSA and AES
-----------
Neither para_server or para_client create RSA keys on their
own. This has to be done once for each user as sketched in
-[Quick start](#Quick.start) and discussed in more detail
-[below](#The.user_list.file).
+[Quick start](#Quick-start) and discussed in more detail
+[below](#The-user_list-file).
The user_list file
------------------
that can be associated with one or more audio files.
In this chapter we sketch the setup of the [AFS
-process](#The.AFS.process) during server startup and proceed with the
-description of the [layout](#Database.layout) of the various database
-tables. The section on [playlists and moods](#Playlists.and.moods)
+process](#The-AFS-process) during server startup and proceed with the
+description of the [layout](#Database-layout) of the various database
+tables. The section on [playlists and moods](#Playlists-and-moods)
explains these two audio file selection mechanisms in detail
and contains practical examples. The way [file renames and content
-changes](#File.renames.and.content.changes) are detected is discussed
-briefly before the [Troubleshooting](#Troubleshooting) section
+changes](#File-renames-and-content-changes) are detected is discussed
+briefly before the [Troubleshooting](#Common-problems) section
concludes the chapter.
The AFS process
to the database.
Note that AFS employs
-[libosl](http://people.tuebingen.mpg.de/maan/osl/), the object
+[libosl](https://people.tuebingen.mpg.de/maan/osl/), the object
storage layer library, as the database backend. This library offers
functionality similar to a relational database, but is much more
lightweight than a full featured database management system.
It is possible to change the behaviour of the add command by using the
"-l" (lazy add) or the "-f" (force add) option.
-Troubleshooting
+Common problems
---------------
Use the debug loglevel (-l debug) to show debugging info. All paraslash
HTTP) can be chosen.
The chapter starts with the [control
-service](#The.paraslash.control.service), followed by a section
-on the various [streaming protocols](#Streaming.protocols)
+service](#The-paraslash-control-service), followed by a section
+on the various [streaming protocols](#Streaming-protocols)
in which the data connections are described. The way
audio file headers are embedded into the stream is discussed
-[briefly](#Streams.with.headers.and.headerless.streams) before the
-[example section](#Networking.examples) which illustrates typical
+[briefly](#Streams-with-headers-and-headerless-streams) before the
+[example section](#Networking-examples) which illustrates typical
commands for real-life scenarios.
Both IPv4 and IPv6 are supported.
fact, the child process can not change address space of server process.
The section on [client-server
-authentication](#Client-server.authentication) above described the
+authentication](#Client-2d-server-authentication) above described the
early connection establishment from the crypto point of view. Here
it is described what happens after the connection (including crypto
setup) has been established. There are four processes involved during
- UDP. Recommended for multicast LAN streaming.
-See the Appendix on [network protocols](#Network.protocols)
+See the Appendix on [network protocols](#Network-protocols)
for brief descriptions of the various protocols relevant for network
audio streaming with paraslash.
and may also be configured through the "sender" command. The FEC
parameters are encoded in the header of each network packet, so no
configuration is necessary on the receiver side. See the section on
-[FEC](#Forward.error.correction) below.
+[FEC](#Forward-error-correction) below.
Streams with headers and headerless streams
-------------------------------------------
Forward error correction
------------------------
-As already mentioned [earlier](#Streaming.protocols), paraslash
+As already mentioned [earlier](#Streaming-protocols), paraslash
uses forward error correction (FEC) for the unreliable UDP and
DCCP transports. FEC is a technique which was invented already in
1960 by Reed and Solomon and which is widely used for the parity
The "." and "," keys are used to switch between themes.
-Examples
---------
+Gui examples
+------------
-> Show server info:
paraslash project, some additional tools should be installed on a
developer machine.
-- [git](http://git.or.cz/). As described in more detail
-[below](#Git.branches), the git source code management tool is used for
+- [git](https://git-scm.com/). As described in more detail
+[below](#Git-branches), the git source code management tool is used for
paraslash development. It is necessary for cloning the git repository
and for getting updates.
written in the Markdown markup language and are translated into html
with the converter of the *Discount* package.
-- [doxygen](http://www.stack.nl/~dimitri/doxygen/). The documentation
+- [doxygen](https://www.doxygen.nl/). The documentation
of paraslash's C sources uses the doxygen documentation system. The
conventions for documenting the source code is described in the
[Doxygen section](#Doxygen).
References
==========
-Articles
---------
-- [Polynomial Codes over Certain Finite
-Fields](http://kom.aau.dk/~heb/kurser/NOTER/KOFA01.PDF) by Reed, Irving
-S.; Solomon, Gustave (1960), Journal of the Society for Industrial
-and Applied Mathematics (SIAM) 8 (2): 300-304, doi:10.1137/0108018)
-
RFCs
----
-- [RFC 768](http://www.ietf.org/rfc/rfc768.txt) (1980): User Datagram
+- [RFC 768](https://www.ietf.org/rfc/rfc768.txt) (1980): User Datagram
Protocol
-- [RFC 791](http://www.ietf.org/rfc/rfc791.txt) (1981): Internet
+- [RFC 791](https://www.ietf.org/rfc/rfc791.txt) (1981): Internet
Protocol
-- [RFC 2437](http://www.ietf.org/rfc/rfc2437.txt) (1998): RSA
+- [RFC 2437](https://www.ietf.org/rfc/rfc2437.txt) (1998): RSA
Cryptography Specifications
-- [RFC 4340](http://www.ietf.org/rfc/rfc4340.txt) (2006): Datagram
+- [RFC 4340](https://www.ietf.org/rfc/rfc4340.txt) (2006): Datagram
Congestion Control Protocol (DCCP)
-- [RFC 4341](http://www.ietf.org/rfc/rfc4341.txt) (2006): Congestion
+- [RFC 4341](https://www.ietf.org/rfc/rfc4341.txt) (2006): Congestion
Control ID 2: TCP-like Congestion Control
-- [RFC 4342](http://www.ietf.org/rfc/rfc4342.txt) (2006): Congestion
+- [RFC 4342](https://www.ietf.org/rfc/rfc4342.txt) (2006): Congestion
Control ID 3: TCP-Friendly Rate Control (TFRC)
-- [RFC 6716](http://www.ietf.org/rfc/rfc6716.txt) (2012): Definition
+- [RFC 6716](https://www.ietf.org/rfc/rfc6716.txt) (2012): Definition
of the Opus Audio Codec
Application web pages
---------------------
-- [paraslash](http://people.tuebingen.mpg.de/maan/paraslash/)
-- [xmms](https://xmms2.org/wiki/Main_Page)
+- [paraslash](https://people.tuebingen.mpg.de/maan/paraslash/)
- [mpg123](http://www.mpg123.de/)
- [gstreamer](https://gstreamer.freedesktop.org/)
-- [icecast](http://www.icecast.org/)
-- [Audio Compress](https://beesbuzz.biz/code/audiocompress.php)
+- [icecast](https://www.icecast.org/)
+- [Audio Compress](https://github.com/fluffy-critter/audiocompress)
External documentation
----------------------
-- [The mathematics of
-Raid6](https://www.kernel.org/pub/linux/kernel/people/hpa/raid6.pdf)
-by H. Peter Anvin
-
- [Effective Erasure Codes for reliable Computer Communication
Protocols](http://info.iet.unipi.it/~luigi/fec_ccr.ps.gz) by Luigi
Rizzo
font-family: sans-serif;
background-color: black;
color: #bbbbbb;
+ text-align: justify;
+ padding: 0px 40px 40px 40px;
margin: 20px;
}
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;