EXCLUDE_PATTERNS = *.cmdline.* \
gcc-compat.h \
- fade.c \
*.command_list.h \
*.completion.h
LDFLAGS += -Wl,--gc-sections
endif
+cc-option = $(shell \
+ $(CC) $(1) -Werror -c -x c /dev/null -o /dev/null > /dev/null 2>&1 \
+ && echo "$(1)" \
+)
+
+STRICT_CFLAGS += $(call cc-option, -Wformat-signedness)
+
# To put more focus on warnings, be less verbose as default
# Use 'make V=1' to see the full commands
ifeq ("$(origin V)", "command line")
- One of the two source browsers has been removed from the web pages.
The doxygen API reference still contains an HTML version of each
source file.
+- Two race conditions in para_server have been fixed.
+- ls -p is now deprecated in favor of -F or -b. See the help text of
+ the ls command for details.
+- The openssl code has been adjusted to work also with openssl-1.1.
+- The wma decoder and audio format handler now correctly decodes
+ files with unusual block sizes.
+- We now compile with -Wformat-signedness if possible.
+- The touch command now refuses to set an invalid image or lyrics ID.
+- New section on contributing for the user manual.
+- Major simplification of the error subsystem.
Download: [tarball](./releases/paraslash-git.tar.bz2)
- para_gui no longer reports 100% playing time at the stream start.
- Opus cleanups.
+Downloads:
[tarball](./releases/paraslash-0.5.6.tar.bz2),
[signature](./releases/paraslash-0.5.6.tar.bz2.asc)
#include <neaacdec.h>
NeAACDecHandle aac_open(void);
-int aac_find_esds(unsigned char *buf, size_t buflen, size_t *skip,
+int aac_find_esds(char *buf, size_t buflen, size_t *skip,
unsigned long *decoder_length);
-ssize_t aac_find_entry_point(unsigned char *buf, size_t buflen, size_t *skip);
-
-static inline unsigned aac_read_int32(unsigned char *buf)
-{
- uint8_t *d = (uint8_t*)buf;
- return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
-}
+ssize_t aac_find_entry_point(char *buf, size_t buflen, size_t *skip);
#include "para.h"
#include "error.h"
+#include "portable_io.h"
#include "afh.h"
#include "string.h"
#include "aac.h"
#include "fd.h"
-static int aac_find_stsz(unsigned char *buf, size_t buflen, off_t *skip)
+static int aac_find_stsz(char *buf, size_t buflen, off_t *skip)
{
int i;
for (i = 0; i + 16 < buflen; i++) {
- unsigned char *p = buf + i;
+ char *p = buf + i;
unsigned sample_count, sample_size;
if (p[0] != 's' || p[1] != 't' || p[2] != 's' || p[3] != 'z')
continue;
PARA_DEBUG_LOG("found stsz@%d\n", i);
i += 8;
- sample_size = aac_read_int32(buf + i);
- PARA_DEBUG_LOG("sample size: %d\n", sample_size);
+ sample_size = read_u32_be(buf + i);
+ PARA_DEBUG_LOG("sample size: %u\n", sample_size);
i += 4;
- sample_count = aac_read_int32(buf + i);
+ sample_count = read_u32_be(buf + i);
i += 4;
- PARA_DEBUG_LOG("sample count: %d\n", sample_count);
+ PARA_DEBUG_LOG("sample count: %u\n", sample_count);
*skip = i;
return sample_count;
}
return -E_STSZ;
}
-static int atom_cmp(const unsigned char *buf1, const char *buf2)
+static int atom_cmp(const char *buf1, const char *buf2)
{
return memcmp(buf1, buf2, 4)? 1 : 0;
}
-static int read_atom_header(unsigned char *buf, uint64_t *subsize, unsigned char type[5])
+static int read_atom_header(char *buf, uint64_t *subsize, char type[5])
{
- int i;
- uint64_t size = aac_read_int32(buf);
+ uint64_t size = read_u32_be(buf);
memcpy(type, buf + 4, 4);
type[4] = '\0';
}
buf += 4;
size = 0;
- for (i = 0; i < 8; i++)
- size |= ((uint64_t)buf[i]) << ((7 - i) * 8);
+ size = read_u64_be(buf);
*subsize = size;
return 16;
}
-static char *get_tag(unsigned char *p, int size)
+static char *get_tag(char *p, int size)
{
char *buf;
return buf;
}
-static void read_tags(unsigned char *buf, size_t buflen, struct afh_info *afhi)
+static void read_tags(char *buf, size_t buflen, struct afh_info *afhi)
{
- unsigned char *p = buf;
+ char *p = buf;
while (p + 32 < buf + buflen) {
- unsigned char *q, type1[5], type2[5];
+ char *q, type1[5], type2[5];
uint64_t size1, size2;
int ret, ret2;
}
}
-static void read_meta(unsigned char *buf, size_t buflen, struct afh_info *afhi)
+static void read_meta(char *buf, size_t buflen, struct afh_info *afhi)
{
- unsigned char *p = buf;
+ char *p = buf;
while (p + 4 < buf + buflen) {
}
}
-static void aac_get_taginfo(unsigned char *buf, size_t buflen,
- struct afh_info *afhi)
+static void aac_get_taginfo(char *buf, size_t buflen, struct afh_info *afhi)
{
int i;
uint64_t subsize;
- unsigned char type[5];
+ char type[5];
for (i = 0; i + 24 < buflen; i++) {
- unsigned char *p = buf + i;
+ char *p = buf + i;
if (p[0] != 'm' || p[1] != 'e' || p[2] != 't' || p[3] != 'a')
continue;
PARA_INFO_LOG("found metadata at offset %d\n", i);
}
static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
- unsigned char *map, size_t numbytes)
+ char *map, size_t numbytes)
{
int ret, i;
size_t sum = 0;
for (i = 1; i <= afhi->chunks_total; i++) {
if (skip + 4 > numbytes)
break;
- sum += aac_read_int32(map + skip);
+ sum += read_u32_be(map + skip);
afhi->chunk_table[i] = sum;
skip += 4;
// if (i < 10 || i + 10 > afhi->chunks_total)
unsigned char channels = 0;
mp4AudioSpecificConfig mp4ASC;
NeAACDecHandle handle = NULL;
- unsigned char *umap = (unsigned char *) map;
- ret = aac_find_esds(umap, numbytes, &skip, &decoder_len);
+ ret = aac_find_esds(map, numbytes, &skip, &decoder_len);
if (ret < 0)
goto out;
- aac_get_taginfo(umap, numbytes, afhi);
+ aac_get_taginfo(map, numbytes, afhi);
handle = aac_open();
ret = -E_AAC_AFH_INIT;
- if (NeAACDecInit(handle, umap + skip, decoder_len, &rate, &channels))
+ if (NeAACDecInit(handle, (unsigned char *)map + skip, decoder_len,
+ &rate, &channels))
goto out;
if (!channels)
goto out;
PARA_DEBUG_LOG("rate: %lu, channels: %d\n", rate, channels);
ret = -E_MP4ASC;
- if (NeAACDecAudioSpecificConfig(umap + skip, numbytes - skip, &mp4ASC))
+ if (NeAACDecAudioSpecificConfig((unsigned char *)map + skip,
+ numbytes - skip, &mp4ASC))
goto out;
if (!mp4ASC.samplingFrequency)
goto out;
- ret = aac_compute_chunk_table(afhi, umap, numbytes);
+ ret = aac_compute_chunk_table(afhi, map, numbytes);
if (ret < 0)
goto out;
skip = ret;
ret = aac_set_chunk_tv(afhi, &mp4ASC, &afhi->seconds_total);
if (ret < 0)
goto out;
- ret = aac_find_entry_point(umap + skip, numbytes - skip, &skip);
+ ret = aac_find_entry_point(map + skip, numbytes - skip, &skip);
if (ret < 0)
goto out;
afhi->chunk_table[0] = ret;
#include "para.h"
#include "aac.h"
#include "error.h"
+#include "portable_io.h"
/**
* Get a new libfaad decoder handle.
return h;
}
-static unsigned long aac_read_decoder_length(unsigned char *buf, int *description_len)
+static unsigned long aac_read_decoder_length(char *buf, int *description_len)
{
uint8_t b;
uint8_t numBytes = 0;
*
* \return positive on success, negative on errors
*/
-int aac_find_esds(unsigned char *buf, size_t buflen, size_t *skip,
+int aac_find_esds(char *buf, size_t buflen, size_t *skip,
unsigned long *decoder_length)
{
size_t i;
for (i = 0; i + 4 < buflen; i++) {
- unsigned char *p = buf + i;
+ char *p = buf + i;
int description_len;
if (p[0] != 'e' || p[1] != 's' || p[2] != 'd' || p[3] != 's')
continue;
i += 8;
p = buf + i;
- PARA_INFO_LOG("found esds@%zu, next: %x\n", i, *p);
+ PARA_INFO_LOG("found esds@%zu, next: %x\n", i, (unsigned)*p);
if (*p == 3)
i += 8;
else
i += 6;
p = buf + i;
- PARA_INFO_LOG("next: %x\n", *p);
+ PARA_INFO_LOG("next: %x\n", (unsigned)*p);
if (*p != 4)
continue;
i += 18;
p = buf + i;
- PARA_INFO_LOG("next: %x\n", *p);
+ PARA_INFO_LOG("next: %x\n", (unsigned)*p);
if (*p != 5)
continue;
i++;
* \return the position of the first entry in the table on success,
* -E_STCO on errors.
*/
-ssize_t aac_find_entry_point(unsigned char *buf, size_t buflen, size_t *skip)
+ssize_t aac_find_entry_point(char *buf, size_t buflen, size_t *skip)
{
ssize_t ret;
size_t i;
for (i = 0; i + 20 < buflen; i++) {
- unsigned char *p = buf + i;
+ char *p = buf + i;
if (p[0] != 's' || p[1] != 't' || p[2] != 'c' || p[3] != 'o')
continue;
PARA_INFO_LOG("found stco@%zu\n", i);
i += 12;
- ret = aac_read_int32(buf + i); /* first offset */
+ ret = read_u32_be(buf + i); /* first offset */
i += 4;
PARA_INFO_LOG("entry point: %zd\n", ret);
*skip = i;
struct btr_node *btrn = fn->btrn;
struct private_aacdec_data *padd = fn->private_data;
int i, ret;
- unsigned char *p, *inbuf, *outbuffer;
+ char *p, *inbuf, *outbuffer;
char *btr_buf;
size_t len, skip, consumed, loaded;
if (ret == 0)
return 0;
btr_merge(btrn, fn->min_iqs);
- len = btr_next_buffer(btrn, (char **)&inbuf);
+ len = btr_next_buffer(btrn, &inbuf);
len = PARA_MIN(len, (size_t)8192);
consumed = 0;
if (!padd->initialized) {
ret = aac_find_esds(inbuf, len, &skip, &padd->decoder_length);
if (ret < 0) {
PARA_INFO_LOG("%s\n", para_strerror(-ret));
- ret = NeAACDecInit(padd->handle, inbuf,
+ ret = NeAACDecInit(padd->handle, (unsigned char *)inbuf,
len, &rate, &channels);
PARA_INFO_LOG("decoder init: %d\n", ret);
if (ret < 0) {
consumed += skip;
p = inbuf + consumed;
ret = -E_AACDEC_INIT;
- if (NeAACDecInit2(padd->handle, p,
+ if (NeAACDecInit2(padd->handle, (unsigned char *)p,
padd->decoder_length, &rate,
&channels) != 0)
goto out;
}
padd->sample_rate = rate;
padd->channels = channels;
- PARA_INFO_LOG("rate: %u, channels: %d\n",
+ PARA_INFO_LOG("rate: %u, channels: %u\n",
padd->sample_rate, padd->channels);
padd->initialized = 1;
}
p = inbuf + consumed;
//PARA_CRIT_LOG("consumed: %zu (%zu + %zu), have: %zu\n", padd->consumed_total + consumed,
// padd->consumed_total, consumed, len - consumed);
- outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p,
- len - consumed);
+ outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info,
+ (unsigned char *)p, len - consumed);
if (padd->frame_info.error) {
int err = padd->frame_info.error;
ret = -E_AAC_DECODE;
goto success;
}
PARA_ERROR_LOG("%s\n", NeAACDecGetErrorMessage(err));
- PARA_ERROR_LOG("consumed: %zu + %zd + %lu\n",
+ PARA_ERROR_LOG("consumed: %zu + %zu + %lu\n",
padd->consumed_total, consumed,
padd->frame_info.bytesconsumed);
if (consumed < len)
inet_pton(AF_INET, addr, &ai->addr);
ai->netmask = netmask;
- PARA_INFO_LOG("adding %s/%i to access list\n", addr, ai->netmask);
+ PARA_INFO_LOG("adding %s/%u to access list\n", addr, ai->netmask);
para_list_add(&ai->node, acl);
}
if (v4_addr_match(to_delete.s_addr, ai->addr.s_addr,
PARA_MIN(netmask, ai->netmask))) {
- PARA_NOTICE_LOG("removing %s/%i from access list\n",
+ PARA_NOTICE_LOG("removing %s/%u from access list\n",
addr, ai->netmask);
list_del(&ai->node);
free(ai);
char *ret = NULL;
list_for_each_entry_safe(ai, tmp_ai, acl, node) {
- char *tmp = make_message("%s%s/%d ", ret? ret : "",
+ char *tmp = make_message("%s%s/%u ", ret? ret : "",
inet_ntoa(ai->addr), ai->netmask);
free(ret);
ret = tmp;
/** Id3 tags, vorbis comments, aac tags. */
struct taginfo tags;
/**
- * The table that specifies the offset of the individual pieces in
- * the current audio file.
- */
+ * The table that specifies the offset of the individual pieces in
+ * the current audio file.
+ */
uint32_t *chunk_table;
/** Period of time between sending data chunks. */
struct timeval chunk_tv;
* which means that this audio format does not need any special header
* treatment. The audio format handler does not need to set this to
* zero in this case.
- */
+ */
uint32_t header_len;
/** The number of channels. */
uint8_t channels;
for (k = PARA_MAX(0, approx_chunk_num); k >= 0; k--)
if (get_chunk_len(k, afhi) > 0)
- break;
- return k;
+ return k;
+ return 0;
}
/**
afh_get_chunk(pard->first_chunk, afhi, pard->map, &start, &size);
afh_get_chunk(pard->last_chunk, afhi, pard->map, &end, &size);
end += size;
- PARA_INFO_LOG("adding %zu bytes\n", end - start);
+ PARA_INFO_LOG("adding %td bytes\n", end - start);
btr_add_output_dont_free(start, end - start, btrn);
ret = -E_RECV_EOF;
goto out;
int i, ret;
get_database_dir();
- PARA_NOTICE_LOG("opening %u osl tables in %s\n", NUM_AFS_TABLES,
+ PARA_NOTICE_LOG("opening %d osl tables in %s\n", NUM_AFS_TABLES,
database_dir);
for (i = 0; i < NUM_AFS_TABLES; i++) {
ret = afs_tables[i].open(database_dir);
register_command_task(cookie, &s);
s.default_timeout.tv_sec = 0;
s.default_timeout.tv_usec = 999 * 1000;
+ ret = write(socket_fd, "\0", 1);
+ if (ret != 1) {
+ if (ret == 0)
+ errno = EINVAL;
+ ret = -ERRNO_TO_PARA_ERROR(errno);
+ goto out_close;
+ }
ret = schedule(&s);
sched_shutdown(&s);
out_close:
continue;
ret = t->event_handler(event, pb, data);
if (ret < 0) {
- PARA_CRIT_LOG("table %s, event %d: %s\n", t->name,
+ PARA_CRIT_LOG("table %s, event %u: %s\n", t->name,
event, para_strerror(-ret));
return ret;
}
H: m: mbox listing mode
H: c: chunk-table listing mode
H:
-H: -p List full paths. If this option is not specified, only the basename
+H: -F List full paths. If this option is not specified, only the basename
H: of each file is printed.
+H: -p Synonym for -F. Deprecated.
+H:
+H: -b Print only the basename of each matching file. This is the default, so
+H: the option is currently a no-op. It is recommended to specify this option,
+H: though, as the default might change in a future release.
H:
H: -a List only files that are admissible with respect to the current mood or
H: playlist.
H:
H: -d Print dates as seconds after the epoch.
H:
-H: -s=order Change sort order. Defaults to alphabetical path sort if not given.
+H: -s=order
+H: Change sort order. Defaults to alphabetical path sort if not given.
H:
H: Possible values for order:
H: p: by path
if (!hours) { /* m:ss or mm:ss */
max_width = opts->mode == LS_MODE_LONG?
opts->widths.duration_width : 4;
- sprintf(buf, "%*u:%02u", max_width - 3, mins, seconds % 60);
+ sprintf(buf, "%*u:%02d", max_width - 3, mins, seconds % 60);
} else { /* more than one hour => h:mm:ss, hh:mm:ss, hhh:mm:ss, ... */
max_width = opts->mode == LS_MODE_LONG?
opts->widths.duration_width : 7;
- sprintf(buf, "%*u:%02u:%02u", max_width - 6, hours, mins,
+ sprintf(buf, "%*u:%02u:%02d", max_width - 6, hours, mins,
seconds % 60);
}
}
para_printf(b,
"%s " /* attributes */
"%*u " /* amp */
- "%*d " /* image_id */
- "%*d " /* lyrics_id */
- "%*d " /* bitrate */
+ "%*u " /* image_id */
+ "%*u " /* lyrics_id */
+ "%*u " /* bitrate */
"%*s " /* audio format */
- "%*d " /* frequency */
- "%d " /* channels */
+ "%*u " /* frequency */
+ "%u " /* channels */
"%s " /* duration */
- "%*d " /* num_played */
+ "%*u " /* num_played */
"%s " /* last_played */
"%s\n", /* path */
att_buf,
WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n",
afhi->seconds_total);
WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time);
- WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%d\n", afsi->num_played);
+ WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%u\n", afsi->num_played);
WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp);
WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv));
WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n",
return -E_AFT_SYNTAX;
}
}
- if (!strcmp(arg, "-p")) {
+ if (!strcmp(arg, "-p") || !strcmp(arg, "-F")) {
flags |= LS_FLAG_FULL_PATH;
continue;
}
+ if (!strcmp(arg, "-b")) {
+ flags &= ~LS_FLAG_FULL_PATH;
+ continue;
+ }
if (!strcmp(arg, "-a")) {
flags |= LS_FLAG_ADMISSIBLE_ONLY;
continue;
.data = aca,
.action = touch_audio_file
};
+ if (cto->image_id >= 0) {
+ ret = img_get_name_by_id(cto->image_id, NULL);
+ if (ret < 0) {
+ para_printf(&aca->pbout, "invalid image ID: %d\n",
+ cto->image_id);
+ return ret;
+ }
+ }
+ if (cto->lyrics_id >= 0) {
+ ret = lyr_get_name_by_id(cto->lyrics_id, NULL);
+ if (ret < 0) {
+ para_printf(&aca->pbout, "invalid lyrics ID: %d\n",
+ cto->lyrics_id);
+ return ret;
+ }
+ }
if (cto->flags & TOUCH_FLAG_FNM_PATHNAME)
pmd.fnmatch_flags |= FNM_PATHNAME;
ret = for_each_matching_row(&pmd);
if (ret >= 0) {
unsigned num;
osl_get_num_rows(audio_file_table, &num);
- PARA_INFO_LOG("audio file table contains %d files\n", num);
+ PARA_INFO_LOG("audio file table contains %u files\n", num);
return ret;
}
PARA_NOTICE_LOG("failed to open audio file table\n");
snd_mixer_selem_id_set_name(sid, mixer_channel);
h->elem = snd_mixer_find_selem(h->mixer, sid);
if (!h->elem) {
- PARA_NOTICE_LOG("unable to find simple control '%s',%i\n",
+ PARA_NOTICE_LOG("unable to find simple control '%s',%u\n",
snd_mixer_selem_id_get_name(sid),
snd_mixer_selem_id_get_index(sid));
ret = -E_BAD_CHANNEL;
get_btr_sample_format(btrn, &val);
pad->sample_format = get_alsa_pcm_format(val);
- PARA_INFO_LOG("%d channel(s), %dHz\n", pad->channels,
+ PARA_INFO_LOG("%u channel(s), %uHz\n", pad->channels,
pad->sample_rate);
ret = alsa_init(pad, wn->conf);
if (ret < 0) {
if (count > 5) {
int s = tv_diff(&diff, &stat_task->sa_time_diff, &tmp);
if (tv_diff(&max_deviation, &tmp, NULL) < 0)
- PARA_WARNING_LOG("time diff jump: %lims\n",
+ PARA_WARNING_LOG("time diff jump: %lums\n",
s * tv2ms(&tmp));
}
count++;
if (st->clock_diff_count) { /* get status only one time */
char *argv[] = {"audiod", "--", "stat", "-p", "-n=1", NULL};
int argc = 5;
- PARA_INFO_LOG("clock diff count: %d\n", st->clock_diff_count);
+ PARA_INFO_LOG("clock diff count: %u\n", st->clock_diff_count);
st->clock_diff_count--;
client_open(argc, argv, &st->ct, NULL, NULL, st->btrn, s);
set_stat_task_restart_barrier(2);
if (pmd.num_matches == 0)
ret = -E_NO_MATCH;
else {
- para_printf(&aca->pbout, "removed %d blob(s)\n",
+ para_printf(&aca->pbout, "removed %u blob(s)\n",
pmd.num_matches);
ret = afs_event(BLOB_REMOVE, NULL, table);
}
struct osl_object obj = {.data = &id, .size = sizeof(id)};
int ret;
- *name = NULL;
+ if (name)
+ *name = NULL;
if (!id)
return 1;
ret = osl(osl_get_row(table, BLOBCOL_ID, &obj, &row));
return ret;
if (*(char *)obj.data == '\0')
return -E_DUMMY_ROW;
- *name = (char *)obj.data;
+ if (name)
+ *name = (char *)obj.data;
return 1;
}
else
cwc->sample_format = (a[3] == 'F')?
SF_S16_LE : SF_S16_BE;
- PARA_NOTICE_LOG("%dHz, %s, %s\n", cwc->sample_rate,
+ PARA_NOTICE_LOG("%uHz, %s, %s\n", cwc->sample_rate,
cwc->channels == 1? "mono" : "stereo",
sample_formats[cwc->sample_format]);
btr_consume(btrn, WAV_HEADER_LEN);
char *opts[] = {
"--", "-l", "-l=s", "-l=l", "-l=v", "-l=p", "-l=m", "-l=c",
"-p", "-a", "-r", "-d", "-s=p", "-s=l", "-s=s", "-s=n", "-s=f",
- "-s=c", "-s=i", "-s=y", "-s=b", "-s=d", "-s=a", NULL
+ "-s=c", "-s=i", "-s=y", "-s=b", "-s=d", "-s=a", "-F", "-b", NULL
};
if (ci->word[0] == '-')
i9e_complete_option(opts, ci, cr);
#define ITEM(x) "0004 %02x:\n"
EMPTY_STATUS_ITEMS
#undef ITEM
- #define ITEM(x) , SI_ ## x
+ #define ITEM(x) , (unsigned) SI_ ## x
EMPTY_STATUS_ITEMS
#undef ITEM
);
i = 100;
PARA_INFO_LOG("jumping to %lu%%\n", i);
mmd->repos_request = (mmd->afd.afhi.chunks_total * i + 50) / 100;
- PARA_INFO_LOG("sent: %lu, offset before jmp: %lu\n",
+ PARA_INFO_LOG("sent: %lu, offset before jmp: %li\n",
mmd->chunks_sent, mmd->offset);
mmd->new_vss_status_flags |= VSS_REPOS;
mmd->new_vss_status_flags &= ~VSS_NEXT;
numbytes = 256;
get_random_bytes_or_die((unsigned char *)buf, numbytes);
}
- PARA_DEBUG_LOG("sending %u byte challenge + session key (%zu bytes)\n",
+ PARA_DEBUG_LOG("sending %d byte challenge + session key (%zu bytes)\n",
CHALLENGE_SIZE, numbytes);
ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
buf = NULL;
AC_CHECK_HEADER(openssl/ssl.h, [], [HAVE_OPENSSL=no])
AC_CHECK_LIB([crypto], [RAND_bytes], [], [HAVE_OPENSSL=no])
LIB_SUBST_FLAGS(openssl)
+if test $HAVE_OPENSSL = yes; then
+ AC_CHECK_LIB([crypto], [RSA_set0_key],
+ AC_DEFINE([HAVE_RSA_SET0_KEY], [1], [openssl-1.1]))
+fi
UNSTASH_FLAGS
######################################################################### gcrypt
STASH_FLAGS
{
int ret;
RSA *rsa;
+ BIGNUM *n, *e;
const unsigned char *p = blob, *end = blob + blen;
rsa = RSA_new();
if (!rsa)
return -E_BIGNUM;
- ret = read_bignum(p, end - p, &rsa->e);
+ ret = read_bignum(p, end - p, &e);
if (ret < 0)
goto fail;
p += ret;
- ret = read_bignum(p, end - p, &rsa->n);
+ ret = read_bignum(p, end - p, &n);
if (ret < 0)
goto fail;
+#ifdef HAVE_RSA_SET0_KEY
+ RSA_set0_key(rsa, n, e, NULL);
+#else
+ rsa->n = n;
+ rsa->e = e;
+#endif
*result = rsa;
return 1;
fail:
return ret < 0? -E_ENCRYPT : ret;
}
-struct aes_ctr_128_context {
- AES_KEY key;
- unsigned char ivec[AES_CRT128_BLOCK_SIZE];
- unsigned char ecount[AES_CRT128_BLOCK_SIZE];
- unsigned int num;
-};
-
struct stream_cipher {
bool use_aes;
union {
RC4_KEY rc4_key;
- struct aes_ctr_128_context aes;
+ EVP_CIPHER_CTX *aes;
} context;
};
struct stream_cipher *sc_new(const unsigned char *data, int len,
bool use_aes)
{
- int ret;
struct stream_cipher *sc = para_malloc(sizeof(*sc));
- struct aes_ctr_128_context *aes;
sc->use_aes = use_aes;
if (!use_aes) {
return sc;
}
assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
- aes = &sc->context.aes;
- ret = AES_set_encrypt_key(data, AES_CRT128_BLOCK_SIZE * 8 /* bits */,
- &aes->key);
- assert(ret == 0);
- memcpy(aes->ivec, data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE);
- aes->num = 0;
+ sc->context.aes = EVP_CIPHER_CTX_new();
+ EVP_EncryptInit_ex(sc->context.aes, EVP_aes_128_ctr(), NULL, data,
+ data + AES_CRT128_BLOCK_SIZE);
return sc;
}
void sc_free(struct stream_cipher *sc)
{
+ if (!sc)
+ return;
+ EVP_CIPHER_CTX_free(sc->context.aes);
free(sc);
}
((char *)dst->iov_base)[len] = '\0';
}
-static void aes_ctr128_crypt(struct aes_ctr_128_context *aes, struct iovec *src,
+static void aes_ctr128_crypt(EVP_CIPHER_CTX *ctx, struct iovec *src,
struct iovec *dst)
{
- size_t len = src->iov_len;
+ int ret, inlen = src->iov_len, outlen, tmplen;
*dst = (typeof(*dst)) {
/* Add one for the terminating zero byte. */
- .iov_base = para_malloc(len + 1),
- .iov_len = len
+ .iov_base = para_malloc(inlen + 1),
+ .iov_len = inlen
};
- AES_ctr128_encrypt(src->iov_base, dst->iov_base, len,
- &aes->key, aes->ivec, aes->ecount, &aes->num);
- ((char *)dst->iov_base)[len] = '\0';
+ ret = EVP_EncryptUpdate(ctx, dst->iov_base, &outlen, src->iov_base, inlen);
+ assert(ret != 0);
+ ret = EVP_EncryptFinal_ex(ctx, dst->iov_base + outlen, &tmplen);
+ assert(ret != 0);
+ outlen += tmplen;
+ ((char *)dst->iov_base)[outlen] = '\0';
+ dst->iov_len = outlen;
}
void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
{
if (sc->use_aes)
- return aes_ctr128_crypt(&sc->context.aes, src, dst);
+ return aes_ctr128_crypt(sc->context.aes, src, dst);
return rc4_crypt(&sc->context.rc4_key, src, dst);
}
return -E_SSH_KEY_HEADER;
if (rlen < strlen(KEY_TYPE_TXT))
return -E_SSH_KEY_HEADER;
- PARA_DEBUG_LOG("type: %s, rlen: %d\n", p, rlen);
+ PARA_DEBUG_LOG("type: %s, rlen: %u\n", p, rlen);
if (strncmp((char *)p, KEY_TYPE_TXT, strlen(KEY_TYPE_TXT)))
return -E_SSH_KEY_HEADER;
return 4 + rlen;
return me->flags & flag;
}
-static void dummy_sighandler(__a_unused int s)
-{
-}
-
/**
* Do the usual stuff to become a daemon.
*
*
* Fork, become session leader, cd to /, and dup fd 0, 1, 2 to /dev/null. If \a
* parent_waits is false, the parent process terminates immediately.
- * Otherwise, it calls pause() to sleep until it receives \p SIGTERM or \p
- * SIGCHLD and exits successfully thereafter. This behaviour is useful if the
- * daemon process should not detach from the console until the child process
- * has completed its setup.
+ * Otherwise, a pipe is created prior to the fork() and the parent tries to
+ * read a single byte from the reading end of the pipe. The child is supposed
+ * to write to the writing end of the pipe after it completed its setup
+ * procedure successfully. This behaviour is useful to let the parent process
+ * die with an error if the child process aborts early, since in this case the
+ * read() will return non-positive.
+ *
+ * \return This function either succeeds or calls exit(3). If parent_waits is
+ * true, the return value is the file descriptor of the writing end of the
+ * pipe. Otherwise the function returns zero.
*
* \sa fork(2), setsid(2), dup(2), pause(2).
*/
-void daemonize(bool parent_waits)
+int daemonize(bool parent_waits)
{
pid_t pid;
- int null;
+ int null, pipe_fd[2];
- PARA_INFO_LOG("daemonizing\n");
+ if (parent_waits && pipe(pipe_fd) < 0)
+ goto err;
+ PARA_INFO_LOG("subsequent log messages go to %s\n", me->logfile_name?
+ me->logfile_name : "/dev/null");
pid = fork();
if (pid < 0)
goto err;
- if (pid) {
+ if (pid) { /* parent exits */
if (parent_waits) {
- signal(SIGTERM, dummy_sighandler);
- signal(SIGCHLD, dummy_sighandler);
- pause();
+ char c;
+ close(pipe_fd[1]);
+ exit(read(pipe_fd[0], &c, 1) <= 0?
+ EXIT_FAILURE : EXIT_SUCCESS);
}
- exit(EXIT_SUCCESS); /* parent exits */
+ exit(EXIT_SUCCESS);
}
+ if (parent_waits)
+ close(pipe_fd[0]);
/* become session leader */
if (setsid() < 0)
goto err;
if (dup2(null, STDERR_FILENO) < 0)
goto err;
close(null);
- return;
+ return parent_waits? pipe_fd[1] : 0;
err:
PARA_EMERG_LOG("fatal: %s\n", strerror(errno));
exit(EXIT_FAILURE);
/** \file daemon.h exported symbols from daemon.c */
-void daemonize(bool parent_waits);
+int daemonize(bool parent_waits);
void daemon_open_log_or_die(void);
void daemon_close_log(void);
void daemon_log_welcome(const char *whoami);
PARA_ERROR(ADD_CALLBACK, "can not add callback"), \
PARA_ERROR(ADDRESS_LOOKUP, "can not resolve requested address"),\
PARA_ERROR(AFH_RECV_BAD_FILENAME, "no file name given"), \
- PARA_ERROR(AFH_SYNTAX, "afh syntax error"), \
PARA_ERROR(AFS_SHORT_READ, "short read from afs socket"), \
PARA_ERROR(AFS_SIGNAL, "afs caught deadly signal"), \
PARA_ERROR(AFS_SOCKET, "afs socket not writable"), \
PARA_ERROR(AUDIO_FORMAT, "audio format not recognized"), \
PARA_ERROR(AUTH_REQUEST, "did not receive auth request"), \
PARA_ERROR(BAD_AFSI, "invalid afs info"), \
+ PARA_ERROR(BAD_ASF_FILE_PROPS, "invalid ASF file properties"), \
PARA_ERROR(BAD_AUTH, "authentication failure"), \
PARA_ERROR(BAD_BAND, "invalid or unexpected band designator"), \
PARA_ERROR(BAD_CHANNEL_COUNT, "channel count not supported"), \
if (ret < 0)
goto out;
vol = ret;
- PARA_NOTICE_LOG("fading %s from %d to %d in %d seconds\n",
+ PARA_NOTICE_LOG("fading %s from %d to %d in %u seconds\n",
conf.mixer_channel_arg, vol, new_vol, secs);
diff = new_vol - vol;
if (!diff) {
tm = localtime(&t1);
}
wake_time_epoch = mktime(tm);
- PARA_INFO_LOG("waketime: %u:%02u\n", tm->tm_hour, tm->tm_min);
+ PARA_INFO_LOG("waketime: %d:%02d\n", tm->tm_hour, tm->tm_min);
client_cmd("stop");
sleep(1);
if (fot) {
exit(0);
}
+/**
+ * The main function of para_fade.
+ *
+ * The executable is linked with the alsa or the oss mixer API, or both. It has
+ * a custom log function which prefixes log messages with the current date.
+ *
+ * \param argc Argument counter.
+ * \param argv Argument vector.
+ *
+ * \return EXIT_SUCCESS or EXIT_FAILURE.
+ */
int main(int argc, char *argv[])
{
int ret;
oldest = fg;
}
if (!group_complete(oldest) && !group_empty(oldest))
- PARA_WARNING_LOG("Clearing incomplete group %d "
+ PARA_WARNING_LOG("Clearing incomplete group %u "
"(contains %d slices)\n", oldest->h.group_num,
oldest->num_received_slices);
if (oldest == pfd->first_complete_group)
uint8_t slice_num = fg->h.slice_num;
if (group_complete(fg)) {
- PARA_DEBUG_LOG("group %d complete, ignoring slice %d\n",
+ PARA_DEBUG_LOG("group %u complete, ignoring slice %d\n",
fg->h.group_num, slice_num);
return 0;
}
r = fg->num_received_slices;
/* Check if we already have this slice. */
if (test_and_set_slice_bit(fg, slice_num)) {
- PARA_INFO_LOG("ignoring duplicate slice %d:%d\n", fg->h.group_num,
+ PARA_INFO_LOG("ignoring duplicate slice %u:%d\n", fg->h.group_num,
slice_num);
return 0;
}
char *buf = NULL;
if (u == FEC_GROUP_UNUSABLE) {
- PARA_INFO_LOG("dropping unusable group %d\n", fg->h.group_num);
+ PARA_INFO_LOG("dropping unusable group %u\n", fg->h.group_num);
return 0;
}
- PARA_DEBUG_LOG("decoding group %d (%d slices)\n", fg->h.group_num,
+ PARA_DEBUG_LOG("decoding group %u (%d slices)\n", fg->h.group_num,
fg->h.data_slices_per_group);
ret = fec_decode(pfd->fec, fg->data, fg->idx, sb);
if (ret < 0)
i = DIV_ROUND_UP(fg->h.audio_header_size, fg->h.slice_bytes);
PARA_DEBUG_LOG("skipping %d header slices\n", i);
}
- PARA_DEBUG_LOG("writing group %d (%d/%d decoded data bytes)\n",
+ PARA_DEBUG_LOG("writing group %u (%u/%d decoded data bytes)\n",
fg->h.group_num, fg->h.group_bytes,
fg->h.data_slices_per_group * sb);
need = (fg->h.data_slices_per_group - i) * sb;
char *result, *home = para_homedir();
srandom(clock_get_realtime(NULL)->tv_usec);
- result = make_message("%s/.paraslash/%08lu", home,
+ result = make_message("%s/.paraslash/%08ld", home,
para_random(99999999));
free(home);
return result;
return 1;
}
if (!strcmp(cmd, "sample_format")) {
- *result = make_message("%u", DECODER_SAMPLE_FORMAT);
+ *result = make_message("%d", DECODER_SAMPLE_FORMAT);
return 1;
}
return -ERRNO_TO_PARA_ERROR(ENOTSUP);
if (!ok) {
FLAC__Metadata_ChainStatus st;
st = FLAC__metadata_chain_status(chain);
- PARA_ERROR_LOG("chain status: %d\n", st);
+ PARA_ERROR_LOG("chain status: %u\n", st);
if (st == FLAC__METADATA_CHAIN_STATUS_READ_ERROR)
PARA_ERROR_LOG("read error\n");
return -E_FLAC_WRITE_CHAIN;
for (i = 0; i < num_bytes; i++, cp++)
bn_size = (bn_size << 8) + *cp;
}
- PARA_DEBUG_LOG("bn_size %d (0x%x)\n", bn_size, bn_size);
+ PARA_DEBUG_LOG("bn_size %d (0x%x)\n", bn_size, (unsigned)bn_size);
gret = gcry_mpi_scan(bn, GCRYMPI_FMT_STD, cp, bn_size, NULL);
if (gret) {
PARA_ERROR_LOG("%s while scanning n\n",
key->num_bytes = n_size;
*result = key;
ret = n_size;
- PARA_INFO_LOG("successfully read %u bit asn public key\n", n_size * 8);
+ PARA_INFO_LOG("successfully read %d bit asn public key\n", n_size * 8);
release_e:
gcry_mpi_release(e);
goto release_n;
}
ret = nr_scanned / 32 * 32;
- PARA_INFO_LOG("successfully read %u bit ssh public key\n", ret * 8);
+ PARA_INFO_LOG("successfully read %d bit ssh public key\n", ret * 8);
release_n:
gcry_mpi_release(n);
release_e:
unsigned lines_total, filled = ringbuffer_filled(bot_win_rb);
int first_rbe = first_visible_rbe(&lines_total);
- print_in_bar(COLOR_MSG, "scrolled view: %d-%d/%d\n", filled - first_rbe,
+ print_in_bar(COLOR_MSG, "scrolled view: %u-%u/%u\n", filled - first_rbe,
filled - scroll_position, ringbuffer_filled(bot_win_rb));
}
percent = 100;
else if (percent < 0)
percent = 0;
- PARA_DEBUG_LOG("moving from rank %u to %lu%%\n", rank, percent);
+ PARA_DEBUG_LOG("moving from rank %u to %li%%\n", rank, percent);
return score_update(aft_row, percent);
}
if (!val || !*val)
return 0;
fr = id3_frame_new(id);
- PARA_DEBUG_LOG("frame desc: %s, %d fields\n", fr->description, fr->nfields);
+ PARA_DEBUG_LOG("frame desc: %s, %u fields\n", fr->description, fr->nfields);
/* Frame 0 contains the encoding. We always use UTF-8. */
field = id3_frame_field(fr, 0);
struct addrinfo *addr = NULL, hints;
*result = NULL;
- sprintf(port, "%u", port_number & 0xffff);
+ sprintf(port, "%d", port_number & 0xffff);
/* Set up address hint structure */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
memcpy(p + og->header_len, og->body, og->body_len);
vghd->buf = buf;
vghd->len = new_len;
- PARA_DEBUG_LOG("header/body/old/new: %lu/%lu/%zu/%zu\n",
+ PARA_DEBUG_LOG("header/body/old/new: %li/%li/%zu/%zu\n",
og->header_len, og->body_len, old_len, new_len);
}
{
int ret;
- PARA_DEBUG_LOG("header/body: %lu/%lu\n", op->header_len, op->body_len);
+ PARA_DEBUG_LOG("header/body: %li/%li\n", op->header_len, op->body_len);
ret = xwrite(fd, (const char *)op->header, op->header_len);
if (ret < 0)
return ret;
goto out;
continue;
}
- PARA_DEBUG_LOG("packet: bytes: %d, granule: %d, packetno: %u\n",
+ PARA_DEBUG_LOG("packet: bytes: %d, granule: %d, packetno: %d\n",
(int)packet.bytes, (int)packet.granulepos,
(int)packet.packetno);
/* ignore meta data packet which we replaced */
#endif
if (ret <= 0)
break;
- PARA_DEBUG_LOG("writing page (%lu bytes)\n",
+ PARA_DEBUG_LOG("writing page (%li bytes)\n",
op.header_len + op.body_len);
ret = write_ogg_page(fd, &op);
if (ret < 0)
goto out;
pod->channels = ov_info(vf, 0)->channels;
pod->sample_rate = ov_info(vf, 0)->rate;
- PARA_NOTICE_LOG("%d channels, %d Hz\n", pod->channels,
+ PARA_NOTICE_LOG("%u channels, %u Hz\n", pod->channels,
pod->sample_rate);
ret = 1;
out:
p += 4;
if (p + ntags * 4 > end)
return -E_OPUS_COMMENT;
- PARA_INFO_LOG("found %d tag(s)\n", ntags);
+ PARA_INFO_LOG("found %u tag(s)\n", ntags);
for (i = 0; i < ntags; i++, p += val) {
char *tag;
ret = -E_BAD_SAMPLERATE;
if (100 * max > 110 * min) /* more than 10% deviation */
goto err;
- PARA_NOTICE_LOG("using %dHz rather than %dHz\n", rate,
+ PARA_NOTICE_LOG("using %uHz rather than %uHz\n", rate,
sample_rate);
}
wn->min_iqs = powd->bytes_per_frame;
pt->rn.receiver = afh_recv;
ret = afh_recv->open(&pt->rn);
if (ret < 0) {
- PARA_ERROR_LOG("could not open %s: %s\n", path,
- para_strerror(-ret));
+ PARA_ERROR_LOG("could not open %s\n", path);
goto fail;
}
pt->audio_format_num = ret;
/* set up decoding filter */
af = audio_format_name(pt->audio_format_num);
tmp = make_message("%sdec", af);
+ PARA_INFO_LOG("decoder: %s\n", tmp);
ret = check_filter_arg(tmp, &pt->fn.conf);
freep(&tmp);
if (ret < 0)
.handler = decoder->execute, .context = &pt->fn));
if (decoder->open)
decoder->open(&pt->fn);
+ PARA_INFO_LOG("buffer tree:\n");
+ btr_log_tree(pt->rn.btrn, LL_INFO);
/* setup default writer */
pt->wn.conf = check_writer_arg_or_die(NULL, &pt->wn.writer_num);
pt->next_file = pt->current_file;
ret = load_file(pt);
if (ret < 0) {
+ PARA_ERROR_LOG("%s: marking file as invalid\n",
+ para_strerror(-ret));
pt->invalid[pt->next_file] = true;
pt->rq = CRT_NONE;
goto again;
char *buf;
size_t sz;
- sz = xasprintf(&buf, "%s %4u %s\n", num == pt->current_file?
+ sz = xasprintf(&buf, "%s %4d %s\n", num == pt->current_file?
"*" : " ", num, conf.inputs[num]);
btr_add_output(buf, sz, pt->btrn);
}
* Licensed under the GPL v2. For licencing details see COPYING.
*/
-/** \file portable_io.h Inline functions for endian-independent binary IO. */
+/** \file portable_io.h Inline functions for binary IO. */
static inline uint64_t read_portable(unsigned bits, const char *buf)
{
return ret;
}
+static inline uint64_t read_portable_be(unsigned bits, const char *buf)
+{
+ uint64_t ret = 0;
+ int i, num_bytes = bits / 8;
+
+ for (i = 0; i < num_bytes; i++) {
+ unsigned char c = buf[i];
+ ret += ((uint64_t)c << (8 * (num_bytes - i - 1)));
+ }
+ return ret;
+}
+
static inline uint64_t read_u64(const char *buf)
{
return read_portable(64, buf);
return read_portable(8, buf);
}
+static inline uint64_t read_u64_be(const char *buf)
+{
+ return read_portable_be(64, buf);
+}
+
+static inline uint32_t read_u32_be(const char *buf)
+{
+ return read_portable_be(32, buf);
+}
+
+static inline uint16_t read_u16_be(const char *buf)
+{
+ return read_portable_be(16, buf);
+}
+
static inline void write_portable(unsigned bits, char *buf, uint64_t val)
{
int i, num_bytes = bits / 8;
-// fprintf(stderr, "val: %lu\n", val);
for (i = 0; i < num_bytes; i++) {
buf[i] = val & 0xff;
-// fprintf(stderr, "buf[%d]=%x\n", i, buf[i]);
+ val = val >> 8;
+ }
+}
+
+static inline void write_portable_be(unsigned bits, char *buf, uint64_t val)
+{
+ int i, num_bytes = bits / 8;
+ for (i = 0; i < num_bytes; i++) {
+ buf[num_bytes - i - 1] = val & 0xff;
val = val >> 8;
}
}
{
write_portable(8, buf, (uint64_t) val);
}
+
+static inline void write_u64_be(char *buf, uint64_t val)
+{
+ write_portable_be(64, buf, val);
+}
+
+static inline void write_u32_be(char *buf, uint32_t val)
+{
+ write_portable_be(32, buf, (uint64_t) val);
+}
+
+static inline void write_u16_be(char *buf, uint16_t val)
+{
+ write_portable_be(16, buf, (uint64_t) val);
+}
int ret, converter;
struct resample_context *ctx = fn->private_data;
struct resample_filter_args_info *conf = fn->conf;
- struct btr_node *btrn = fn->btrn;
- ret = -E_RESAMPLE_EOF;
- if (btr_no_parent(btrn))
- return ret;
- if (btr_get_input_queue_size(btrn) == 0)
- return 0;
ret = resample_set_params(fn);
if (ret < 0)
return ret;
ret = check_wav_post_select(ctx->cwc);
if (ret < 0)
goto out;
+ ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
+ if (ret <= 0)
+ goto out;
if (!ctx->src_state) {
ret = resample_init(fn);
if (ret <= 0)
goto out;
}
- ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
- if (ret <= 0)
- goto out;
if (ctx->source_sample_rate == conf->dest_sample_rate_arg) {
/*
* No resampling necessary. We do not splice ourselves out
static void unlink_and_free_task(struct task *t)
{
- PARA_INFO_LOG("freeing task %s\n", t->name);
+ PARA_INFO_LOG("freeing task %s (%s)\n", t->name, t->status < 0?
+ para_strerror(-t->status) :
+ (t->status == TS_DEAD? "[dead]" : "[running]"));
+
list_del(&t->node);
free(t->name);
free(t);
{
int ret, afs_server_socket[2];
pid_t afs_pid;
+ char c;
- ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, afs_server_socket);
+ ret = socketpair(PF_UNIX, SOCK_STREAM, 0, afs_server_socket);
if (ret < 0)
exit(EXIT_FAILURE);
get_random_bytes_or_die((unsigned char *)&afs_socket_cookie,
exit(EXIT_FAILURE);
if (afs_pid == 0) { /* child (afs) */
int i;
+
for (i = argc - 1; i >= 0; i--)
memset(argv[i], 0, strlen(argv[i]));
sprintf(argv[0], "para_server (afs)");
}
mmd->afs_pid = afs_pid;
close(afs_server_socket[1]);
+ if (read(afs_server_socket[0], &c, 1) <= 0) {
+ PARA_EMERG_LOG("early afs exit\n");
+ exit(EXIT_FAILURE);
+ }
ret = mark_fd_nonblocking(afs_server_socket[0]);
if (ret < 0)
exit(EXIT_FAILURE);
.check_ambiguity = 0,
.print_errors = 1
};
- int afs_socket;
+ int afs_socket, daemon_pipe = -1;
valid_fd_012();
init_random_seed_or_die();
init_user_list(user_list_file);
/* become daemon */
if (conf.daemon_given)
- daemonize(true /* parent waits for SIGTERM */);
+ daemon_pipe = daemonize(true /* parent waits for us */);
PARA_NOTICE_LOG("initializing audio format handlers\n");
afh_init();
PARA_NOTICE_LOG("initializing virtual streaming system\n");
init_vss_task(afs_socket, &sched);
init_server_command_task(argc, argv);
- if (conf.daemon_given)
- kill(getppid(), SIGTERM);
+ if (daemon_pipe >= 0) {
+ if (write(daemon_pipe, "\0", 1) < 0) {
+ PARA_EMERG_LOG("daemon_pipe: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ close(daemon_pipe);
+ }
PARA_NOTICE_LOG("server init complete\n");
}
prev_uptime = uptime;
prev_events = mmd->events;
mmd->vss_status_flags = mmd->new_vss_status_flags;
- PARA_DEBUG_LOG("%d events, forcing status update\n", mmd->events);
+ PARA_DEBUG_LOG("%u events, forcing status update\n", mmd->events);
killpg(0, SIGUSR1);
}
struct task *task;
};
+/**
+ * A generic pre-select method for signal tasks.
+ *
+ * \param s Passed to para_fd_set().
+ * \param context Signal task pointer.
+ *
+ * This convenience helper is called from several programs which need to handle
+ * signals, including para_server and para_audiod. These programs define a
+ * signal task structure and set its ->pre_select method to this function which
+ * adds the file descriptor of the signal task to the set of descriptors to be
+ * watched in the next select() call.
+ *
+ * Although the second parameter must be in fact a pointer to a signal_task
+ * structure, the parameter is specified as void * here to match the
+ * ->pre_select method of struct task.
+ */
_static_inline_ void signal_pre_select(struct sched *s, void *context)
{
struct signal_task *st = context;
if (c + 4 > end)
return -E_SPX_COMMENT;
nb_fields = read_u32(c);
- PARA_DEBUG_LOG("%d comment(s)\n", nb_fields);
+ PARA_DEBUG_LOG("%u comment(s)\n", nb_fields);
c += 4;
for (i = 0; i < nb_fields; i++, c += len) {
char *tag;
#define WRITE_STATUS_ITEM(b, n, f, ...) (\
{ \
if ((b)->flags & PBF_SIZE_PREFIX) { \
- para_printf((b), "%02x:" f, n, ## __VA_ARGS__); \
+ para_printf((b), "%02x:" f, (unsigned)n, ## __VA_ARGS__); \
} else { \
para_printf((b), "%s: " f, status_item_list[(n)], \
## __VA_ARGS__); \
let i++
commands[$i]="ls_ogg"
required_objects[$i]='ogg_afh'
-cmdline[$i]="ls -l=v ${oggs_base[@]}"
+cmdline[$i]="ls -l=v -b ${oggs_base[@]}"
good[$i]='^basename:'
let i++
let i++
commands[$i]="ls"
required_objects[$i]='ogg_afh'
-cmdline[$i]="ls -l=v -p ${oggs[@]}"
+cmdline[$i]="ls -l=v -F ${oggs[@]}"
good[$i]='^attributes_txt: 33'
let i++
for (; i < k; i++)
fc->src_data[i] = (const unsigned char *)buf;
}
- PARA_DEBUG_LOG("FEC group %d: %d chunks (%d - %d), %d bytes\n",
+ PARA_DEBUG_LOG("FEC group %u: %u chunks (%u - %u), %u bytes\n",
g->num, g->num_chunks, g->first_chunk,
g->first_chunk + g->num_chunks - 1, g->bytes
);
}
if (compute_next_fec_slice(fc, vsst) <= 0)
continue;
- PARA_DEBUG_LOG("sending %d:%d (%u bytes)\n", fc->group.num,
+ PARA_DEBUG_LOG("sending %u:%u (%u bytes)\n", fc->group.num,
fc->current_slice_num, fc->group.slice_bytes);
fc->fcp->send_fec(fc->sc, (char *)fc->enc_buf,
fc->group.slice_bytes + FEC_HEADER_SIZE);
int bytespersec = channels * sample_rate * BITS / 8;
int align = channels * BITS / 8;
- PARA_DEBUG_LOG("writing wave header: %d channels, %d KHz\n", channels, sample_rate);
+ PARA_DEBUG_LOG("writing wave header: %u channels, %u KHz\n", channels, sample_rate);
memset(headbuf, 0, WAV_HEADER_LEN);
memcpy(headbuf, "RIFF", 4);
write_u32(headbuf + 4, size - 8);
check out any of the four integration branches maint,
master, next, pu (see the
- <a href="manual.html#git_branches">git_branches</a>
+ <a href="manual.html#Git.branches">Git branches</a>
section of the manual). All previous releases
correspond to tagged commits and may be checked out
Development
===========
+Contributing
+------------
+
+Paraslash is an open source project and contributions are
+welcome. Here's a list of things you can do to help the project:
+
+- Report problems with building, installing or running the software.
+ In particular, test the experimental git branches ("next" and "pu").
+ This helps to identify and fix problems before the code gets merged
+ and thus keeps the master branch as stable as possible.
+- Proofread the documentation (manual, web pages, man pages, source
+ code documentation) and point out unclear or poorly written parts. If
+ you are a native English speaker you will easily find a lot of text
+ that could be improved.
+- Run analysis tools (coverity, afl, sparse, etc.) and report issues
+ found by those tools.
+- Suggest new features you would like to see implemented.
+- Compile and test on your favorite architecture or operating
+ system. The code is tested only on a limited set of systems, so you
+ will probably encounter problems when building on different systems.
+- Post about about paraslash on your blog or on social networks.
+- Build and maintain Debian/RPM packages for your favorite distribution.
+
+Note that there is no mailing list, no bug tracker and no discussion
+forum for paraslash. If you'd like to contribute, or have questions
+about contributing, send email to Andre Noll <maan@tuebingen.mpg.de>.
+
Tools
-----
The preferred coding style for paraslash coincides more or less
with the style of the Linux kernel. So rather than repeating what is
-written [there](http://www.kernel.org/doc/Documentation/CodingStyle),
+written [there](http://www.kernel.org/doc/Documentation/process/coding-style.rst),
here are the most important points.
- Burn the GNU coding standards.
bool use_bit_reservoir;
/** Whether blocks are of variable or of constant size. */
bool use_variable_block_len;
+ /** Obtained from the file properties object. */
+ uint32_t packet_size;
};
/* wma_common.c */
#include "wma.h"
#include "fd.h"
-#define FOR_EACH_FRAME(_f, _buf, _size, _ba) for (_f = (_buf); \
- _f + (_ba) + WMA_FRAME_SKIP < (_buf) + (_size); \
- _f += (_ba) + WMA_FRAME_SKIP)
+#define FOR_EACH_FRAME(_f, _buf, _size, _ps) for (_f = (_buf); \
+ _f + (_ps) < (_buf) + (_size); \
+ _f += (_ps))
/*
* Must be called on a frame boundary, e.g. start + header_len.
* \return Frame count, superframe count via *num_superframes.
*/
-static int count_frames(const char *buf, int buf_size, int block_align,
+static int count_frames(const char *buf, int buf_size, uint32_t packet_size,
int *num_superframes)
{
int fc = 0, sfc = 0; /* frame count, superframe count */
const uint8_t *p;
- FOR_EACH_FRAME(p, (uint8_t *)buf, buf_size, block_align) {
+ FOR_EACH_FRAME(p, (uint8_t *)buf, buf_size, packet_size) {
fc += p[WMA_FRAME_SKIP] & 0x0f;
sfc++;
}
}
/* Must be called on a frame boundary. */
-static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align,
+static int wma_make_chunk_table(char *buf, size_t buf_size, uint32_t packet_size,
struct afh_info *afhi)
{
const uint8_t *f, *start = (uint8_t *)buf;
afhi->chunk_table[0] = 0;
afhi->chunk_table[1] = afhi->header_len;
- num_frames = count_frames(buf, buf_size, block_align,
+ num_frames = count_frames(buf, buf_size, packet_size,
&num_superframes);
ret = -E_NO_WMA;
if (num_frames == 0 || num_superframes == 0)
frames_per_chunk = num_frames / num_superframes / 2;
PARA_INFO_LOG("%d frames per chunk\n", frames_per_chunk);
j = 1;
- FOR_EACH_FRAME(f, start, buf_size, block_align) {
+ FOR_EACH_FRAME(f, start, buf_size, packet_size) {
count += f[WMA_FRAME_SKIP] & 0x0f;
while (count > j * frames_per_chunk) {
j++;
afhi->chunk_table,
ct_size * sizeof(uint32_t));
}
- afhi->chunk_table[j] = f - start + afhi->header_len + block_align + WMA_FRAME_SKIP;
+ afhi->chunk_table[j] = f - start + afhi->header_len
+ + packet_size;
}
}
afhi->chunks_total = j;
ahi.use_variable_block_len? "vbl" : ""
);
wma_make_chunk_table(map + ahi.header_len, numbytes - ahi.header_len,
- ahi.block_align, afhi);
+ ahi.packet_size, afhi);
read_asf_tags(map, ahi.header_len, &afhi->tags);
return 0;
}
return NULL;
}
+static int find_file_properties(const char *buf, int len)
+{
+ const char pattern[] = {0xa1, 0xdc, 0xab, 0x8c};
+ const char *p = search_pattern(pattern, sizeof(pattern), buf, len);
+
+ if (!p)
+ return -E_WMA_NO_GUID;
+ PARA_DEBUG_LOG("found file property guid@%0x\n", (unsigned)(p - buf));
+ return p - buf + 16;
+}
+
/*
40 9e 69 f8 4d 5b cf 11 a8 fd 00 80 5f 5c 44 2b
*/
if (!p)
return -E_WMA_NO_GUID;
- PARA_DEBUG_LOG("found audio stream guid@%0x\n", (int)(p - buf));
+ PARA_DEBUG_LOG("found audio stream guid@%0x\n", (unsigned)(p - buf));
return p - buf + 16;
}
ahi->sample_rate);
ahi->bit_rate = 8 * read_u16(start + 46);
- PARA_INFO_LOG("bit rate: %d\n", ahi->bit_rate);
+ PARA_INFO_LOG("bit rate: %u\n", ahi->bit_rate);
ahi->block_align = read_u16(start + 50);
PARA_INFO_LOG("block_align: %d\n", ahi->block_align);
ahi->flags1 = read_u32(start + 56);
ahi->flags2 = read_u16(start + 60);
- PARA_INFO_LOG("read_asf_header: flags1: %d, flag2: %d\n",
+ PARA_INFO_LOG("read_asf_header: flags1: %u, flags2: %u\n",
ahi->flags1, ahi->flags2);
ahi->use_exp_vlc = ahi->flags2 & 0x0001;
ahi->use_bit_reservoir = ahi->flags2 & 0x0002;
ahi->use_variable_block_len = ahi->flags2 & 0x0004;
+
+ ret = find_file_properties(buf, ahi->header_len);
+ if (ret < 0)
+ return ret;
+ /* file property header is always 88 bytes (sans GUID) */
+ if (ret + 88 > loaded)
+ return 0;
+ start = buf + ret;
+ ahi->packet_size = read_u32(start + 76); /* min packet size */
+ /* we only support fixed packet sizes */
+ if (ahi->packet_size != read_u32(start + 80)) /* min != max */
+ return -E_BAD_ASF_FILE_PROPS;
+ if (ahi->packet_size <= ahi->block_align)
+ return -E_BAD_ASF_FILE_PROPS;
+ PARA_INFO_LOG("packet size: %u\n", ahi->packet_size);
return 1;
}
else
high_freq = high_freq * 0.5;
}
- PARA_INFO_LOG("channels=%d sample_rate=%d "
- "bitrate=%d block_align=%d\n",
+ PARA_INFO_LOG("channels=%u sample_rate=%u "
+ "bitrate=%u block_align=%d\n",
ahi->channels, ahi->sample_rate,
ahi->bit_rate, ahi->block_align);
PARA_INFO_LOG("frame_len=%d, bps=%f bps1=%f "
/* Decode a frame of frame_len samples. */
static int wma_decode_frame(struct private_wmadec_data *pwd, int16_t *samples)
{
- int ret, i, n, ch, incr;
+ int ret, i, ch;
int16_t *ptr;
float *iptr;
}
/* convert frame to integer */
- n = pwd->frame_len;
- incr = pwd->ahi.channels;
for (ch = 0; ch < pwd->ahi.channels; ch++) {
ptr = samples + ch;
iptr = pwd->frame_out[ch];
- for (i = 0; i < n; i++) {
+ for (i = 0; i < pwd->frame_len; i++) {
*ptr = av_clip_int16(lrintf(*iptr++));
- ptr += incr;
+ ptr += pwd->ahi.channels;
}
/* prepare for next block */
memmove(&pwd->frame_out[ch][0], &pwd->frame_out[ch][pwd->frame_len],
if (buf_size == 0) {
pwd->last_superframe_len = 0;
+ *data_size = 0;
return 0;
}
- if (buf_size < pwd->ahi.block_align)
+ if (buf_size < pwd->ahi.block_align) {
+ *data_size = 0;
return 0;
+ }
buf_size = pwd->ahi.block_align;
samples = data;
init_get_bits(&pwd->gb, buf, buf_size);
if (ret == 0)
return 0;
btr_merge(btrn, fn->min_iqs);
- len = btr_next_buffer(btrn, (char **)&in);
+ len = btr_next_buffer(btrn, &in);
ret = -E_WMADEC_EOF;
if (len < fn->min_iqs)
goto err;
fn->min_iqs += 4096;
goto next_buffer;
}
- fn->min_iqs = 2 * (WMA_FRAME_SKIP + pwd->ahi.block_align);
+ fn->min_iqs = 2 * pwd->ahi.packet_size;
fn->private_data = pwd;
converted = pwd->ahi.header_len;
goto success;
}
- fn->min_iqs = WMA_FRAME_SKIP + pwd->ahi.block_align;
+ fn->min_iqs = pwd->ahi.packet_size;
if (fn->min_iqs > len)
goto success;
out_size = WMA_OUTPUT_BUFFER_SIZE;
free(out);
goto err;
}
- out = para_realloc(out, out_size);
- if (out_size > 0)
+ if (out_size > 0) {
+ out = para_realloc(out, out_size);
btr_add_output(out, out_size, btrn);
- converted += ret + WMA_FRAME_SKIP;
+ } else
+ free(out);
+ converted += pwd->ahi.packet_size;
success:
btr_consume(btrn, converted);
return 0;