From: Andre Noll Date: Fri, 30 Dec 2016 14:58:41 +0000 (+0100) Subject: Merge branch 'refs/heads/t/invalid-ids' X-Git-Tag: v0.5.7~4 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=121015ff5cdbe6af7b84f6245ebe62fe2a52a859;hp=c4a57c05c9353a59db14dd57f8c911f175c63371 Merge branch 'refs/heads/t/invalid-ids' A single patch that was in misc for a while, and two follow up fixups that were detected after the branch was merged into next. * refs/heads/t/invalid-ids (cooking for two weeks): Makefile: Don't compile with -Wformat-signedness unconditionally. aft.c: Use correct format string for error output. touch: Refuse to set an invalid image or lyrics ID. --- diff --git a/Doxyfile b/Doxyfile index 50c74695..df6c87fd 100644 --- a/Doxyfile +++ b/Doxyfile @@ -797,7 +797,6 @@ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = *.cmdline.* \ gcc-compat.h \ - fade.c \ *.command_list.h \ *.completion.h diff --git a/Makefile.real b/Makefile.real index ce4881d2..464cd68e 100644 --- a/Makefile.real +++ b/Makefile.real @@ -128,6 +128,13 @@ ifeq ($(uname_s),Linux) 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") diff --git a/NEWS.md b/NEWS.md index 71eb6cb2..3d00528d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,24 @@ NEWS ==== +------------------------------------------ +0.5.7 (to be announced) "semantic density" +------------------------------------------ +- Speedup of the base64 decoder. +- 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. + +Download: [tarball](./releases/paraslash-git.tar.bz2) + --------------------------------------- 0.5.6 (2016-07-10) "cascading gradient" --------------------------------------- @@ -25,6 +43,7 @@ not mentioned here have accumulated and are also part of the release. - 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) diff --git a/aac.h b/aac.h index f31d723a..eeed2528 100644 --- a/aac.h +++ b/aac.h @@ -9,12 +9,6 @@ #include 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); diff --git a/aac_afh.c b/aac_afh.c index c49f30de..1c7fd706 100644 --- a/aac_afh.c +++ b/aac_afh.c @@ -15,44 +15,44 @@ #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'; @@ -64,13 +64,12 @@ static int read_atom_header(unsigned char *buf, uint64_t *subsize, unsigned char } 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; @@ -83,12 +82,12 @@ static char *get_tag(unsigned char *p, int size) 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; @@ -117,9 +116,9 @@ static void read_tags(unsigned char *buf, size_t buflen, struct afh_info *afhi) } } -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) { @@ -132,15 +131,14 @@ static void read_meta(unsigned char *buf, size_t buflen, struct afh_info *afhi) } } -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); @@ -154,7 +152,7 @@ static void aac_get_taginfo(unsigned char *buf, size_t buflen, } 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; @@ -169,7 +167,7 @@ static ssize_t aac_compute_chunk_table(struct afh_info *afhi, 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) @@ -212,32 +210,33 @@ static int aac_get_file_info(char *map, size_t numbytes, __a_unused int fd, 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; diff --git a/aac_common.c b/aac_common.c index fe9b7295..812c742c 100644 --- a/aac_common.c +++ b/aac_common.c @@ -13,6 +13,7 @@ #include "para.h" #include "aac.h" #include "error.h" +#include "portable_io.h" /** * Get a new libfaad decoder handle. @@ -31,7 +32,7 @@ NeAACDecHandle aac_open(void) 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; @@ -59,31 +60,31 @@ static unsigned long aac_read_decoder_length(unsigned char *buf, int *descriptio * * \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++; @@ -108,19 +109,19 @@ int aac_find_esds(unsigned char *buf, size_t buflen, size_t *skip, * \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; diff --git a/aacdec_filter.c b/aacdec_filter.c index ac8148e8..5725ce04 100644 --- a/aacdec_filter.c +++ b/aacdec_filter.c @@ -86,7 +86,7 @@ static int aacdec_post_select(__a_unused struct sched *s, void *context) 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; @@ -97,7 +97,7 @@ next_buffer: 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) { @@ -106,7 +106,7 @@ next_buffer: 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) { @@ -120,14 +120,14 @@ next_buffer: 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; } @@ -158,8 +158,8 @@ next_buffer: 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; @@ -171,7 +171,7 @@ next_buffer: 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) diff --git a/acl.c b/acl.c index 5ef9a51c..560ff999 100644 --- a/acl.c +++ b/acl.c @@ -87,7 +87,7 @@ static void acl_add_entry(struct list_head *acl, char *addr, int netmask) 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); } @@ -109,7 +109,7 @@ static void acl_del_entry(struct list_head *acl, char *addr, unsigned netmask) 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); @@ -131,7 +131,7 @@ char *acl_get_contents(struct list_head *acl) 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; diff --git a/afh.h b/afh.h index dad67351..a6f9c500 100644 --- a/afh.h +++ b/afh.h @@ -36,9 +36,9 @@ struct afh_info { /** 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; @@ -48,7 +48,7 @@ struct afh_info { * 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; diff --git a/afh_common.c b/afh_common.c index f36c32e2..dfbf7513 100644 --- a/afh_common.c +++ b/afh_common.c @@ -295,8 +295,8 @@ int32_t afh_get_start_chunk(int32_t approx_chunk_num, 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; } /** diff --git a/afh_recv.c b/afh_recv.c index 16463463..28d8f398 100644 --- a/afh_recv.c +++ b/afh_recv.c @@ -205,7 +205,7 @@ static int afh_recv_post_select(__a_unused struct sched *s, void *context) 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; diff --git a/afs.c b/afs.c index 0accc451..0946b6df 100644 --- a/afs.c +++ b/afs.c @@ -706,7 +706,7 @@ static int open_afs_tables(void) 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); @@ -1024,6 +1024,13 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd) 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: @@ -1195,7 +1202,7 @@ __must_check int afs_event(enum afs_events event, struct para_buffer *pb, 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; } diff --git a/afs.cmd b/afs.cmd index 584ba809..76b5f4dc 100644 --- a/afs.cmd +++ b/afs.cmd @@ -51,8 +51,13 @@ H: p: parser-friendly mode 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. @@ -61,7 +66,8 @@ H: -r Reverse sort order. 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 diff --git a/aft.c b/aft.c index e48708a3..bfcd1fb0 100644 --- a/aft.c +++ b/aft.c @@ -738,11 +738,11 @@ static void get_duration_buf(int seconds, char *buf, struct ls_options *opts) 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); } } @@ -876,14 +876,14 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, 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, @@ -930,7 +930,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, 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", @@ -1410,10 +1410,14 @@ int com_ls(struct command_context *cc) 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; @@ -2637,7 +2641,7 @@ static int aft_open(const char *dir) 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"); diff --git a/alsa_mix.c b/alsa_mix.c index cad58af0..3adee929 100644 --- a/alsa_mix.c +++ b/alsa_mix.c @@ -142,7 +142,7 @@ static int alsa_mix_set_channel(struct mixer_handle *h, 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; diff --git a/alsa_write.c b/alsa_write.c index 63a7055b..fd3b404c 100644 --- a/alsa_write.c +++ b/alsa_write.c @@ -303,7 +303,7 @@ again: 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) { diff --git a/audiod.c b/audiod.c index 285d2762..bd97f15e 100644 --- a/audiod.c +++ b/audiod.c @@ -764,7 +764,7 @@ static void compute_time_diff(const struct timeval *status_time) 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++; @@ -1378,7 +1378,7 @@ static int status_post_select(struct sched *s, void *context) 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); diff --git a/base64.c b/base64.c new file mode 100644 index 00000000..7b8fe292 --- /dev/null +++ b/base64.c @@ -0,0 +1,205 @@ +/* + * The code in this file was taken from openssh-5.2p1, Copyright (c) 1996 by + * Internet Software Consortium. Portions Copyright (c) 1995 by International + * Business Machines, Inc. + */ + +/** \file base64.c Uudecode and base64decode implementation. */ + +#include + +#include "para.h" +#include "error.h" +#include "base64.h" +#include "string.h" + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const unsigned char base64_tab[256] = { + 255, 255, 255, 255, 255, 255, 255, 255, /* 00-07 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* 08-0f */ + 255, 255, 255, 255, 255, 255, 255, 255, /* 10-17 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* 18-1f */ + 255, 255, 255, 255, 255, 255, 255, 255, /* 20-2f */ + 255, 255, 255, 62, 255, 255, 255, 63, /* 28-2f */ + 52 , 53, 54, 55, 56, 57, 58, 59, /* 30-37 */ + 60 , 61, 255, 255, 255, 255, 255, 255, /* 38-3f */ + 255, 0, 1, 2, 3, 4, 5, 6, /* 40-47 */ + 7 , 8, 9, 10, 11, 12, 13, 14, /* 48-4f */ + 15 , 16, 17, 18, 19, 20, 21, 22, /* 50-57 */ + 23 , 24, 25, 255, 255, 255, 255, 255, /* 58-5f */ + 255, 26, 27, 28, 29, 30, 31, 32, /* 60-6f */ + 33 , 34, 35, 36, 37, 38, 39, 40, /* 68-6f */ + 41 , 42, 43, 44, 45, 46, 47, 48, /* 70-77 */ + 49 , 50, 51, 255, 255, 255, 255, 255, /* 78-7f */ + 255, 255, 255, 255, 255, 255, 255, 255, /* 80-87 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* 88-8f */ + 255, 255, 255, 255, 255, 255, 255, 255, /* 90-97 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* 98-9f */ + 255, 255, 255, 255, 255, 255, 255, 255, /* a0-a7 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* a8-af */ + 255, 255, 255, 255, 255, 255, 255, 255, /* b0-b7 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* b8-bf */ + 255, 255, 255, 255, 255, 255, 255, 255, /* c0-c7 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* c8-cf */ + 255, 255, 255, 255, 255, 255, 255, 255, /* d0-d7 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* d8-df */ + 255, 255, 255, 255, 255, 255, 255, 255, /* e0-e7 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* e8-ef */ + 255, 255, 255, 255, 255, 255, 255, 255, /* f0-f7 */ + 255, 255, 255, 255, 255, 255, 255, 255, /* f8-ff */ +}; + +/** Maximal possible size of the decoded data. */ +#define BASE64_MAX_DECODED_SIZE(_encoded_size) ((_encoded_size) / 4 * 3) + +#define PAD64 '=' +/** + * base64-decode a buffer. + * + * \param src The buffer to decode. + * \param encoded_size The special value -1 means: look for terminating zero byte. + * \param result Points to dynamically allocated target buffer on success. + * \param decoded_size Number of bytes written to \a result. + * + * Skips all whitespace anywhere. Converts characters, four at a time, starting + * at (or after) src from base - 64 numbers into three 8 bit bytes in the + * target area. + * + * It is OK to pass a \p NULL pointer as \a decoded_size. The result is + * terminated with a zero byte. + * + * \return Standard. The contents of result \a and \a decoded_size are + * undefined on failure. + */ +int base64_decode(char const *src, size_t encoded_size, char **result, + size_t *decoded_size) +{ + size_t i, j, state; /* source/target indices */ + const char *end = src + encoded_size, *p; + unsigned char *target, uch; + + if (encoded_size == (size_t)-1) + encoded_size = strlen(src); + target = para_malloc(BASE64_MAX_DECODED_SIZE(encoded_size) + 1); + + for ( + i = 0, j = 0, state = 0; + i < encoded_size && (uch = src[i]) != '\0'; + i++ + ) { + if (para_isspace(uch)) /* Skip whitespace anywhere. */ + continue; + if (uch == PAD64) + break; + if (base64_tab[uch] == 255) /* A non-base64 character. */ + goto fail; + uch = base64_tab[uch]; + switch (state) { + case 0: + target[j] = uch << 2; + break; + case 1: + target[j] |= uch >> 4; + j++; + target[j] = (uch & 0x0f) << 4; + break; + case 2: + target[j] |= uch >> 2; + j++; + target[j] = (uch & 0x03) << 6; + break; + case 3: + target[j] |= uch; + j++; + break; + } + state = (state + 1) % 4; + } + p = (i < encoded_size)? src + i : NULL; + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + if (p && *p == PAD64) { /* We got a pad char. Skip it, get next. */ + p++; + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + goto fail; + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; p < end && *p != '\0'; p++) + if (!para_isspace(*p)) + break; + /* Make sure there is another trailing = sign. */ + if (*p != PAD64) + goto fail; + /* Fall through to "single trailing =" case. */ + p++; + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; p < end && *p != '\0'; p++) + if (!para_isspace(*p)) + goto fail; + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target[j] != 0) + goto fail; + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + goto fail; + } + /* success */ + target[j] = '\0'; /* just to be sure */ + if (decoded_size) + *decoded_size = j; + *result = (char *)target; + return 1; +fail: + free(target); + return -E_BASE64; +} + +/** + * Decode a buffer using the uuencode Base64 algorithm. + * + * \param src The buffer to decode. + * \param encoded_size Number of input bytes in the source buffer. + * \param result Contains the decoded data on success. + * \param decoded_size Number of output bytes on success. + * + * This is just a simple wrapper for \ref base64_decode() which strips + * whitespace. + * + * \return The return value of the underlying call to \ref base64_decode(). + * + * \sa uuencode(1), uudecode(1). + */ +int uudecode(char const *src, size_t encoded_size, char **result, + size_t *decoded_size) +{ + const char *end = src + encoded_size, *p; + + /* skip whitespace and data */ + for (p = src; p < end && (*p == ' ' || *p == '\t'); p++) + ; + for (; p < end && *p != '\0' && *p != ' ' && *p != '\t'; p++) + ; + /* and remove trailing whitespace because base64_decode needs this */ + return base64_decode(src, p - src, result, decoded_size); +} diff --git a/base64.h b/base64.h new file mode 100644 index 00000000..4bfaa99d --- /dev/null +++ b/base64.h @@ -0,0 +1,4 @@ +int uudecode(char const *src, size_t encoded_size, char **result, + size_t *decoded_size); +int base64_decode(char const *src, size_t encoded_size, char **result, + size_t *decoded_size); diff --git a/blob.c b/blob.c index 737f1980..ed684428 100644 --- a/blob.c +++ b/blob.c @@ -262,7 +262,7 @@ static int com_rmblob_callback(struct osl_table *table, 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); } diff --git a/check_wav.c b/check_wav.c index d1d27872..1a47f946 100644 --- a/check_wav.c +++ b/check_wav.c @@ -177,7 +177,7 @@ int check_wav_post_select(struct check_wav_context *cwc) 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); diff --git a/client.c b/client.c index 31cfff09..64b15537 100644 --- a/client.c +++ b/client.c @@ -278,7 +278,7 @@ static void ls_completer(struct i9e_completion_info *ci, 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); diff --git a/client_common.c b/client_common.c index cd1ccc61..eea7510f 100644 --- a/client_common.c +++ b/client_common.c @@ -292,11 +292,6 @@ static int client_post_select(struct sched *s, void *context) if (ret < 0 || n == 0) goto out; ct->features = parse_features(buf); - if (!has_feature("sideband", ct)) { - PARA_ERROR_LOG("server has no sideband support\n"); - ret = -E_INCOMPAT_FEAT; - goto out; - } ct->status = CL_RECEIVED_WELCOME; return 0; case CL_RECEIVED_WELCOME: /* send auth command */ diff --git a/command.c b/command.c index 93de2d2d..fe4b9232 100644 --- a/command.c +++ b/command.c @@ -473,7 +473,7 @@ static unsigned empty_status_items(int parser_friendly, char **result) #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 ); @@ -767,7 +767,7 @@ static int com_jmp(struct command_context *cc) 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; @@ -807,7 +807,6 @@ static void reset_signals(void) } struct connection_features { - bool sideband_requested; bool aes_ctr128_requested; }; @@ -835,8 +834,8 @@ static int parse_auth_request(char *buf, int len, struct user **u, create_argv(p, ",", &features); for (i = 0; features[i]; i++) { if (strcmp(features[i], "sideband") == 0) - cf->sideband_requested = true; - else if (strcmp(features[i], "aes_ctr128") == 0) + continue; + if (strcmp(features[i], "aes_ctr128") == 0) cf->aes_ctr128_requested = true; else { ret = -E_BAD_FEATURE; @@ -949,11 +948,6 @@ __noreturn void handle_connect(int fd, const char *peername) ret = parse_auth_request(buf, ret, &cc->u, &cf); if (ret < 0) goto net_err; - if (!cf.sideband_requested) { /* sideband is mandatory */ - PARA_ERROR_LOG("client did not request sideband\n"); - ret = -E_BAD_FEATURE; - goto net_err; - } if (cc->u) { get_random_bytes_or_die(rand_buf, sizeof(rand_buf)); ret = pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf), @@ -970,7 +964,7 @@ __noreturn void handle_connect(int fd, const char *peername) 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; diff --git a/configure.ac b/configure.ac index f9115fd6..74f3fd97 100644 --- a/configure.ac +++ b/configure.ac @@ -116,6 +116,10 @@ LIB_ARG_WITH([openssl], [-lssl -lcrypto]) 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 @@ -418,6 +422,7 @@ if test -n "$CRYPTOLIB" && test $HAVE_OSL = yes; then close_on_fork mm crypt_common + base64 ipc dccp_send fd @@ -480,6 +485,7 @@ if test -n "$CRYPTOLIB"; then client_common buffer_tree crypt_common + base64 version ggo " @@ -523,6 +529,7 @@ if test -n "$CRYPTOLIB"; then stat net crypt_common + base64 sideband time grab_client diff --git a/crypt.c b/crypt.c index 610d2057..8116fb6e 100644 --- a/crypt.c +++ b/crypt.c @@ -23,6 +23,7 @@ #include "crypt.h" #include "fd.h" #include "crypt_backend.h" +#include "base64.h" struct asymmetric_key { RSA *rsa; @@ -133,18 +134,25 @@ static int read_rsa_bignums(const unsigned char *blob, int blen, RSA **result) { 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: @@ -158,7 +166,7 @@ int get_asymmetric_key(const char *key_file, int private, struct asymmetric_key *key = NULL; void *map = NULL; unsigned char *blob = NULL; - size_t map_size, blob_size, decoded_size; + size_t map_size, encoded_size, decoded_size; int ret, ret2; char *cp; @@ -180,16 +188,11 @@ int get_asymmetric_key(const char *key_file, int private, goto out; } cp = map + ret; + encoded_size = map_size - ret; PARA_INFO_LOG("decoding public rsa-ssh key %s\n", key_file); - ret = -ERRNO_TO_PARA_ERROR(EOVERFLOW); - if (map_size > INT_MAX / 4) - goto out_unmap; - blob_size = 2 * map_size; - blob = para_malloc(blob_size); - ret = uudecode(cp, blob, blob_size); + ret = uudecode(cp, encoded_size, (char **)&blob, &decoded_size); if (ret < 0) goto out_unmap; - decoded_size = ret; ret = check_ssh_key_header(blob, decoded_size); if (ret < 0) goto out_unmap; @@ -260,27 +263,18 @@ int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, 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) { @@ -288,17 +282,17 @@ struct stream_cipher *sc_new(const unsigned char *data, int len, 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); } @@ -332,25 +326,29 @@ static void rc4_crypt(RC4_KEY *key, struct iovec *src, struct iovec *dst) ((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); } diff --git a/crypt_backend.h b/crypt_backend.h index 06c86d74..f9a69d94 100644 --- a/crypt_backend.h +++ b/crypt_backend.h @@ -13,7 +13,5 @@ size_t is_ssh_rsa_key(char *data, size_t size); uint32_t read_ssh_u32(const void *vp); -int uudecode(const char *src, unsigned char *target, size_t targsize); int check_ssh_key_header(const unsigned char *blob, int blen); int check_key_file(const char *file, bool private_key); -int base64_decode(char const *src, unsigned char *target, size_t targsize); diff --git a/crypt_common.c b/crypt_common.c index 022692ad..a05572df 100644 --- a/crypt_common.c +++ b/crypt_common.c @@ -45,166 +45,6 @@ size_t is_ssh_rsa_key(char *data, size_t size) return cp - data; } -/* - * This base64/uudecode stuff below is taken from openssh-5.2p1, Copyright (c) - * 1996 by Internet Software Consortium. Portions Copyright (c) 1995 by - * International Business Machines, Inc. - */ - -static const char Base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char Pad64 = '='; - -/** - * base64-decode a buffer. - * - * \param src The buffer to decode. - * \param target Result is stored here. - * \param targsize Number of bytes of \a target. - * - * Skips all whitespace anywhere. Converts characters, four at a time, starting - * at (or after) src from base - 64 numbers into three 8 bit bytes in the - * target area. - * - * \return The number of data bytes stored at the target, -E_BASE64 on errors. - */ -int base64_decode(char const *src, unsigned char *target, size_t targsize) -{ - unsigned int tarindex, state; - int ch; - char *pos; - - state = 0; - tarindex = 0; - - while ((ch = *src++) != '\0') { - if (para_isspace(ch)) /* Skip whitespace anywhere. */ - continue; - - if (ch == Pad64) - break; - - pos = strchr(Base64, ch); - if (pos == NULL) /* A non-base64 character. */ - return -E_BASE64; - - switch (state) { - case 0: - if (tarindex >= targsize) - return -E_BASE64; - target[tarindex] = (pos - Base64) << 2; - state = 1; - break; - case 1: - if (tarindex + 1 >= targsize) - return -E_BASE64; - target[tarindex] |= (pos - Base64) >> 4; - target[tarindex + 1] = ((pos - Base64) & 0x0f) << 4; - tarindex++; - state = 2; - break; - case 2: - if (tarindex + 1 >= targsize) - return -E_BASE64; - target[tarindex] |= (pos - Base64) >> 2; - target[tarindex + 1] = ((pos - Base64) & 0x03) << 6; - tarindex++; - state = 3; - break; - case 3: - if (tarindex >= targsize) - return -E_BASE64; - target[tarindex] |= pos - Base64; - tarindex++; - state = 0; - break; - } - } - - /* - * We are done decoding Base-64 chars. Let's see if we ended - * on a byte boundary, and/or with erroneous trailing characters. - */ - - if (ch == Pad64) { /* We got a pad char. */ - ch = *src++; /* Skip it, get next. */ - switch (state) { - case 0: /* Invalid = in first position */ - case 1: /* Invalid = in second position */ - return -E_BASE64; - - case 2: /* Valid, means one byte of info */ - /* Skip any number of spaces. */ - for (; ch != '\0'; ch = *src++) - if (!isspace(ch)) - break; - /* Make sure there is another trailing = sign. */ - if (ch != Pad64) - return -E_BASE64; - ch = *src++; /* Skip the = */ - /* Fall through to "single trailing =" case. */ - /* FALLTHROUGH */ - - case 3: /* Valid, means two bytes of info */ - /* - * We know this char is an =. Is there anything but - * whitespace after it? - */ - for (; ch != '\0'; ch = *src++) - if (!isspace(ch)) - return -E_BASE64; - - /* - * Now make sure for cases 2 and 3 that the "extra" - * bits that slopped past the last full byte were - * zeros. If we don't check them, they become a - * subliminal channel. - */ - if (target[tarindex] != 0) - return -E_BASE64; - } - } else { - /* - * We ended by seeing the end of the string. Make sure we - * have no partial bytes lying around. - */ - if (state != 0) - return -E_BASE64; - } - - return tarindex; -} - -/** - * uudecode a buffer. - * - * \param src The buffer to decode. - * \param target Result buffer. - * \param targsize The length of \a target in bytes. - * - * This is just a simple wrapper for base64_decode() which strips whitespace. - * - * \return The return value of the underlying call to base64_decode(). - */ -int uudecode(const char *src, unsigned char *target, size_t targsize) -{ - int len; - char *encoded, *p; - - /* copy the 'readonly' source */ - encoded = para_strdup(src); - /* skip whitespace and data */ - for (p = encoded; *p == ' ' || *p == '\t'; p++) - ; - for (; *p != '\0' && *p != ' ' && *p != '\t'; p++) - ; - /* and remove trailing whitespace because base64_decode needs this */ - *p = '\0'; - len = base64_decode(encoded, target, targsize); - free(encoded); - return len; -} - /** * Read a 4-byte number from a buffer in big-endian format. * @@ -256,7 +96,7 @@ int check_ssh_key_header(const unsigned char *blob, int blen) 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; diff --git a/daemon.c b/daemon.c index 7c625bbe..20cdc6ae 100644 --- a/daemon.c +++ b/daemon.c @@ -155,10 +155,6 @@ static bool daemon_test_flag(unsigned flag) return me->flags & flag; } -static void dummy_sighandler(__a_unused int s) -{ -} - /** * Do the usual stuff to become a daemon. * @@ -166,30 +162,42 @@ static void dummy_sighandler(__a_unused int s) * * 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; @@ -205,7 +213,7 @@ void daemonize(bool parent_waits) 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); diff --git a/daemon.h b/daemon.h index c7153605..989678df 100644 --- a/daemon.h +++ b/daemon.h @@ -1,7 +1,7 @@ /** \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); diff --git a/error.h b/error.h index 337160c9..a2f719f5 100644 --- a/error.h +++ b/error.h @@ -148,6 +148,7 @@ extern const char **para_errlist[]; #define WMA_COMMON_ERRORS \ + PARA_ERROR(BAD_ASF_FILE_PROPS, "invalid ASF file properties"), \ PARA_ERROR(WMA_NO_GUID, "audio stream guid not found"), \ @@ -306,7 +307,6 @@ extern const char **para_errlist[]; PARA_ERROR(SERVER_EOF, "connection closed by para_server"), \ PARA_ERROR(SERVER_CMD_SUCCESS, "command terminated successfully"), \ PARA_ERROR(SERVER_CMD_FAILURE, "command failed"), \ - PARA_ERROR(INCOMPAT_FEAT, "client/server incompatibility"), \ #define NET_ERRORS \ @@ -440,9 +440,10 @@ extern const char **para_errlist[]; #define CRYPT_COMMON_ERRORS \ PARA_ERROR(SSH_KEY_HEADER, "ssh key header not found"), \ - PARA_ERROR(BASE64, "failed to base64-decode ssh public key"), \ PARA_ERROR(KEY_PERM, "unprotected private key"), \ +#define BASE64_ERRORS \ + PARA_ERROR(BASE64, "base64 decode error"), \ #define CRYPT_ERRORS \ PARA_ERROR(PRIVATE_KEY, "can not read private key"), \ diff --git a/fade.c b/fade.c index e05e3173..2a001eba 100644 --- a/fade.c +++ b/fade.c @@ -67,7 +67,7 @@ static int fade(struct mixer *m, struct mixer_handle *h, int new_vol, int fade_t 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) { @@ -203,7 +203,7 @@ static int sweet_dreams(struct mixer *m, struct mixer_handle *h) 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) { @@ -333,6 +333,17 @@ __noreturn static void print_help_and_die(void) 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; diff --git a/fecdec_filter.c b/fecdec_filter.c index 26ea24a6..1c3a3784 100644 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@ -171,7 +171,7 @@ static struct fecdec_group *free_oldest_group(struct private_fecdec_data *pfd) 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) @@ -224,7 +224,7 @@ static int add_slice(char *buf, struct fecdec_group *fg) 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; } @@ -236,7 +236,7 @@ static int add_slice(char *buf, struct fecdec_group *fg) 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; } @@ -293,10 +293,10 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) 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) @@ -307,7 +307,7 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) 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; diff --git a/file_write.c b/file_write.c index ef25b0f5..5e66607e 100644 --- a/file_write.c +++ b/file_write.c @@ -39,7 +39,7 @@ __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/%08lu", home, + result = make_message("%s/.paraslash/%08ld", home, para_random(99999999)); free(home); return result; diff --git a/filter_common.c b/filter_common.c index 84863b39..e9b97e54 100644 --- a/filter_common.c +++ b/filter_common.c @@ -204,7 +204,7 @@ int decoder_execute(const char *cmd, unsigned sample_rate, unsigned channels, 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); diff --git a/flac_afh.c b/flac_afh.c index 2e2842b1..385d4f0c 100644 --- a/flac_afh.c +++ b/flac_afh.c @@ -468,7 +468,7 @@ static int flac_write_chain(FLAC__Metadata_Chain *chain, 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; diff --git a/gcrypt.c b/gcrypt.c index 3c6c1ad1..7c19aeb0 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -15,6 +15,7 @@ #include "crypt.h" #include "crypt_backend.h" #include "fd.h" +#include "base64.h" //#define GCRYPT_DEBUG 1 @@ -239,12 +240,11 @@ static int decode_key(const char *key_file, const char *header_str, key[j++] = begin[i]; } key[j] = '\0'; - blob_size = key_size * 2; - blob = para_malloc(blob_size); - ret = base64_decode(key, blob, blob_size); + ret = base64_decode(key, j, (char **)&blob, &blob_size); free(key); if (ret < 0) goto free_unmap; + ret = blob_size; goto unmap; free_unmap: free(blob); @@ -388,7 +388,7 @@ static int read_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn, 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", @@ -586,7 +586,7 @@ static int get_asn_public_key(const char *key_file, struct asymmetric_key **resu 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); @@ -606,13 +606,9 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result gcry_mpi_t e = NULL, n = NULL; PARA_DEBUG_LOG("decoding %d byte public rsa-ssh key\n", size); - if (size > INT_MAX / 4) - return -ERRNO_TO_PARA_ERROR(EOVERFLOW); - blob = para_malloc(2 * size); - ret = uudecode((char *)data, blob, 2 * size); + ret = uudecode((char *)data, size, (char **)&blob, &decoded_size); if (ret < 0) goto free_blob; - decoded_size = ret; end = blob + decoded_size; dump_buffer("decoded key", blob, decoded_size); ret = check_ssh_key_header(blob, decoded_size); @@ -652,7 +648,7 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result 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: diff --git a/gui.c b/gui.c index b0eae64a..3e01340a 100644 --- a/gui.c +++ b/gui.c @@ -1160,7 +1160,7 @@ static void print_scroll_msg(void) 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)); } diff --git a/mood.c b/mood.c index 940d72a1..79f47e5a 100644 --- a/mood.c +++ b/mood.c @@ -747,7 +747,7 @@ static int mood_update_audio_file(const struct osl_row *aft_row, 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); } diff --git a/mp3_afh.c b/mp3_afh.c index 70f2ec9f..2115f71c 100644 --- a/mp3_afh.c +++ b/mp3_afh.c @@ -238,7 +238,7 @@ static int replace_tag(char const *id, const char *val, struct id3_tag *id3_t, 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); diff --git a/net.c b/net.c index 13694989..fa7cd4b8 100644 --- a/net.c +++ b/net.c @@ -376,7 +376,7 @@ int lookup_address(unsigned l4type, bool passive, const char *host, 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; diff --git a/ogg_afh.c b/ogg_afh.c index 29f08965..2ddf0ee3 100644 --- a/ogg_afh.c +++ b/ogg_afh.c @@ -95,7 +95,7 @@ static void add_ogg_page(ogg_page *og, struct vorbis_get_header_data *vghd) 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); } diff --git a/ogg_afh_common.c b/ogg_afh_common.c index e49b803b..adab7f48 100644 --- a/ogg_afh_common.c +++ b/ogg_afh_common.c @@ -193,7 +193,7 @@ static int write_ogg_page(int fd, const ogg_page *op) { 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; @@ -288,7 +288,7 @@ int ogg_rewrite_tags(const char *map, size_t map_sz, int fd, 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 */ @@ -309,7 +309,7 @@ int ogg_rewrite_tags(const char *map, size_t map_sz, int fd, #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) diff --git a/oggdec_filter.c b/oggdec_filter.c index 4b801356..04be7020 100644 --- a/oggdec_filter.c +++ b/oggdec_filter.c @@ -162,7 +162,7 @@ open: 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: diff --git a/opus_afh.c b/opus_afh.c index b1469b47..64eeb03c 100644 --- a/opus_afh.c +++ b/opus_afh.c @@ -55,7 +55,7 @@ static int opus_get_comments(char *comments, int length, 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; diff --git a/oss_write.c b/oss_write.c index 12cf8b69..20186667 100644 --- a/oss_write.c +++ b/oss_write.c @@ -165,7 +165,7 @@ static int oss_init(struct writer_node *wn, unsigned sample_rate, 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; diff --git a/play.c b/play.c index d2539ee1..46e8ff7d 100644 --- a/play.c +++ b/play.c @@ -328,8 +328,7 @@ static int open_new_file(struct play_task *pt) 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; @@ -388,6 +387,7 @@ static int load_file(struct play_task *pt) /* 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) @@ -399,6 +399,8 @@ static int load_file(struct play_task *pt) .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); @@ -453,6 +455,8 @@ again: 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; @@ -784,7 +788,7 @@ static void list_file(struct play_task *pt, int num) 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); } diff --git a/portable_io.h b/portable_io.h index f1a38929..4e10c2e3 100644 --- a/portable_io.h +++ b/portable_io.h @@ -4,7 +4,7 @@ * 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) { @@ -18,6 +18,18 @@ 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); @@ -38,13 +50,35 @@ static inline uint8_t read_u8(const char *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; } } @@ -68,3 +102,18 @@ static inline void write_u8(char *buf, uint8_t val) { 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); +} diff --git a/resample_filter.c b/resample_filter.c index 6a285ec3..1699ed2c 100644 --- a/resample_filter.c +++ b/resample_filter.c @@ -128,13 +128,7 @@ static int resample_init(struct filter_node *fn) 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; @@ -216,14 +210,14 @@ static int resample_post_select(__a_unused struct sched *s, void *context) 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 diff --git a/sched.c b/sched.c index 1db9169b..bc301778 100644 --- a/sched.c +++ b/sched.c @@ -66,7 +66,10 @@ static void sched_preselect(struct sched *s) 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); diff --git a/server.c b/server.c index 088cc8b1..1f931944 100644 --- a/server.c +++ b/server.c @@ -411,8 +411,9 @@ static int init_afs(int argc, char **argv) { 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, @@ -422,6 +423,7 @@ static int init_afs(int argc, char **argv) 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)"); @@ -430,6 +432,10 @@ static int init_afs(int argc, char **argv) } 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); @@ -457,7 +463,7 @@ static void server_init(int argc, char **argv) .check_ambiguity = 0, .print_errors = 1 }; - int afs_socket; + int afs_socket, daemon_pipe = -1; valid_fd_012(); init_random_seed_or_die(); @@ -477,7 +483,7 @@ static void server_init(int argc, char **argv) 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(); @@ -503,8 +509,13 @@ static void server_init(int argc, char **argv) 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"); } @@ -526,7 +537,7 @@ out: 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); } diff --git a/spx_afh.c b/spx_afh.c index b780635b..4e318af1 100644 --- a/spx_afh.c +++ b/spx_afh.c @@ -88,7 +88,7 @@ static int spx_get_comments(unsigned char *comments, int length, 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; diff --git a/string.h b/string.h index aa8292fd..52f98941 100644 --- a/string.h +++ b/string.h @@ -63,7 +63,7 @@ int for_each_line(unsigned flags, char *buf, size_t size, #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__); \ diff --git a/t/t0004-server.sh b/t/t0004-server.sh index c2e809cb..1963748f 100755 --- a/t/t0004-server.sh +++ b/t/t0004-server.sh @@ -45,7 +45,7 @@ bad[$i]='.' 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++ @@ -69,7 +69,7 @@ bad[$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++ diff --git a/vss.c b/vss.c index 2acff1cb..5484db9d 100644 --- a/vss.c +++ b/vss.c @@ -611,7 +611,7 @@ static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst) 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 ); @@ -1027,7 +1027,7 @@ static void vss_send(struct vss_task *vsst) } 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); diff --git a/wav_filter.c b/wav_filter.c index 07423a14..88047adb 100644 --- a/wav_filter.c +++ b/wav_filter.c @@ -31,7 +31,7 @@ static void make_wav_header(unsigned int channels, unsigned int sample_rate, 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); diff --git a/web/documentation.in.html b/web/documentation.in.html index f292af25..b226943b 100644 --- a/web/documentation.in.html +++ b/web/documentation.in.html @@ -36,10 +36,5 @@

Source code documentation

diff --git a/web/download.in.html b/web/download.in.html index dd0b9c78..a09fd1c8 100644 --- a/web/download.in.html +++ b/web/download.in.html @@ -19,7 +19,7 @@ provided at this point. There are several ways to download the source: check out any of the four integration branches maint, master, next, pu (see the - git_branches + Git branches section of the manual). All previous releases correspond to tagged commits and may be checked out diff --git a/wma.h b/wma.h index 15b9c5d4..b260feb9 100644 --- a/wma.h +++ b/wma.h @@ -28,6 +28,8 @@ struct asf_header_info { 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 */ diff --git a/wma_afh.c b/wma_afh.c index 929e732b..4c9d87e0 100644 --- a/wma_afh.c +++ b/wma_afh.c @@ -18,22 +18,22 @@ #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++; } @@ -192,7 +192,7 @@ static void set_chunk_tv(int frames_per_chunk, int frequency, } /* 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; @@ -204,7 +204,7 @@ static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align, 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) @@ -214,7 +214,7 @@ static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align, 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++; @@ -224,7 +224,8 @@ static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align, 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; @@ -262,7 +263,7 @@ static int wma_get_file_info(char *map, size_t numbytes, __a_unused int fd, 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; } diff --git a/wma_common.c b/wma_common.c index 8886a061..6d57c00b 100644 --- a/wma_common.c +++ b/wma_common.c @@ -42,6 +42,17 @@ const char *search_pattern(const char *pattern, int pattern_len, 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 */ @@ -52,7 +63,7 @@ static int find_audio_stream_info(const char *buf, int len) 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; } @@ -100,18 +111,33 @@ int read_asf_header(const char *buf, int loaded, struct asf_header_info *ahi) 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; } diff --git a/wmadec_filter.c b/wmadec_filter.c index 0dff2b79..4c7c047a 100644 --- a/wmadec_filter.c +++ b/wmadec_filter.c @@ -371,8 +371,8 @@ static int wma_init(struct private_wmadec_data *pwd) 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 " @@ -1028,7 +1028,7 @@ static inline int16_t av_clip_int16(int a) /* 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; @@ -1043,15 +1043,13 @@ static int wma_decode_frame(struct private_wmadec_data *pwd, int16_t *samples) } /* 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], @@ -1068,10 +1066,13 @@ static int wma_decode_superframe(struct private_wmadec_data *pwd, void *data, 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); @@ -1209,7 +1210,7 @@ next_buffer: 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; @@ -1221,12 +1222,12 @@ next_buffer: 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; @@ -1237,10 +1238,12 @@ next_buffer: 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;