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
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;
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);
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_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])
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)
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]);
*/
#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;
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;
- assert(p);
+ 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);
- [curses](ftp://ftp.gnu.org/pub/gnu/ncurses). Needed for
para_gui. Debian package: `libncurses-dev`.
-- [GNU
-Readline](https://www.gnu.org/software/readline/). 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
------------
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;