- mandatory rc4 encryption
- major audio format handler cleanups
- improved tag handling
+ - lots of new mood methods
-------------------------------------------------
0.3.5 (to be announced) "symplectic separability"
- --log_color actually works
- new ls option: -d (print dates as seconds after the epoch)
- update to gengetopt 2.22.2
+ - support for RSA keys of size > 512 bits
-----------------------------------------
0.3.4 (2009-05-07) "elliptic inheritance"
bitrate ~ <num>
frequency ~ <num>
channels ~ <num>
+ num_played ~ <num>
Takes a comparator ~ of the set {<, =, <=, >, >=, !=} and a number
<num>. Matches an audio file iff the condition <val> ~ <num> is
satisfied where val is the corresponding value of the audio file
-(bitrate in kbit/s, frequency in Hz, channel count, value of the
-year tag).
+(value of the year tag, bitrate in kbit/s, frequency in Hz, channel
+count, play count).
The year tag is special as its value is undefined if the audio file
has no year tag or the content of the year tag is not a number. Such
audio files never match. Another difference is the special treatment
if the year tag is a two-digit number. In this case either 1900 or
-2000 are added to the tag value, depending on whether the number is
+2000 are added to the tag value depending on whether the number is
greater than 2000 plus the current year.
/** \file aac_afh.c para_server's aac audio format handler */
#include <regex.h>
-#include <osl.h>
#include "para.h"
#include "error.h"
.short_help = alsa_write_args_info_help,
.detailed_help = alsa_write_args_info_detailed_help
};
+ alsa_cmdline_parser_free(&dummy);
}
static ssize_t amp_convert(char *inbuf, size_t inbuf_len, struct filter_node *fn)
{
- size_t i, length = PARA_MIN((inbuf_len / 2) * 2,
- (fn->bufsize - fn->loaded) / 2 * 2);
+ size_t i, length = PARA_MIN((inbuf_len / 2),
+ (fn->bufsize - fn->loaded) / 2);
struct private_amp_data *pad = fn->private_data;
int16_t *ip = (int16_t *)inbuf, *op = (int16_t *)(fn->buf + fn->loaded);
+ int factor = 64 + pad->amp;
if (!length)
return 0;
- for (i = 0; i < length / 2; i++) {
- int x = (PARA_ABS(*ip) * (64 + pad->amp)) >> 6;
- *op++ = *ip++ > 0? PARA_MIN(x, 32767) : PARA_MAX(-x, -32768);
+
+ if (pad->amp == 0) {
+ memcpy(op, ip, length * 2);
+ goto out;
+ }
+ for (i = 0; i < length; i++) {
+ int x = (ip[i] * factor) >> 6;
+
+ op[i] = x;
+ if (op[i] != x)
+ op[i] = (x >= 32768)? 32767 : -32768;
}
- fn->loaded += length;
- return length;
+out:
+ fn->loaded += length * 2;
+ return length * 2;
}
static void amp_close(struct filter_node *fn)
{
int ret;
struct command_task *ct = container_of(t, struct command_task, task);
+ static struct timeval last_status_dump;
+ struct timeval tmp;
+
+ tv_add(&last_status_dump, &(struct timeval){0, 500 * 1000}, &tmp);
+ if (tv_diff(&tmp, now, NULL) < 0) {
+ audiod_status_dump();
+ last_status_dump = *now;
+ }
- audiod_status_dump();
if (!FD_ISSET(ct->fd, &s->rfds))
return;
ret = handle_connect(ct->fd);
register_task(&cmd_task->task);
register_task(&stat_task->task);
s.default_timeout.tv_sec = 0;
- s.default_timeout.tv_usec = 99 * 1000;
+ s.default_timeout.tv_usec = 999 * 1000;
ret = schedule(&s);
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
void audiod_status_dump(void);
char *get_time_string(int slot_num);
+void stat_client_write_item(int item_num);
+void clear_and_dump_items(void);
+
/** iterate over all slots */
#define FOR_EACH_SLOT(_slot) for (_slot = 0; _slot < MAX_STREAM_SLOTS; _slot++)
#include "para.h"
#include "audiod.cmdline.h"
#include "list.h"
-#include "close_on_fork.h"
#include "sched.h"
#include "ggo.h"
#include "filter.h"
extern char *stat_item_values[NUM_STAT_ITEMS];
-
-/** iterate over the array of all audiod commands */
+/** Iterate over the array of all audiod commands. */
#define FOR_EACH_COMMAND(c) for (c = 0; audiod_cmds[c].name; c++)
+/** The maximal number of simultaneous connections. */
+#define MAX_STAT_CLIENTS 50
+
+/** Flags used for the stat command of para_audiod. */
+enum stat_client_flags {
+ /** Enable parser-friendly output. */
+ SCF_PARSER_FRIENDLY = 1,
+};
+
+/**
+ * Describes a status client of para_audiod.
+ *
+ * There's one such structure per audiod client that sent the 'stat' command.
+ *
+ * A status client is identified by its file descriptor. para_audiod
+ * keeps a list of connected status clients.
+ */
+struct stat_client {
+ /** The stat client's file descriptor. */
+ int fd;
+ /** Bitmask of those status items the client is interested in. */
+ uint64_t item_mask;
+ /** See \ref stat_client flags. s*/
+ unsigned flags;
+ /** Its entry in the list of stat clients. */
+ struct list_head node;
+};
+
+static LIST_HEAD(client_list);
+static int num_clients;
+
+/** The list of all status items used by para_{server,audiod,gui}. */
+const char *status_item_list[] = {STATUS_ITEM_ARRAY};
+
+static void dump_stat_client_list(void)
+{
+ struct stat_client *sc;
+
+ list_for_each_entry(sc, &client_list, node)
+ PARA_INFO_LOG("stat client on fd %d\n", sc->fd);
+}
+/**
+ * Add a status client to the list.
+ *
+ * \param fd The file descriptor of the client.
+ * \param mask Bitfield of status items for this client.
+ * \param parser_friendly Enable parser-friendly output mode.
+ *
+ * Only those status items having the bit set in \a mask will be
+ * sent to the client.
+ *
+ * \return Positive value on success, or -E_TOO_MANY_CLIENTS if
+ * the number of connected clients exceeds #MAX_STAT_CLIENTS.
+ */
+static int stat_client_add(int fd, uint64_t mask, int parser_friendly)
+{
+ struct stat_client *new_client;
+
+ if (num_clients >= MAX_STAT_CLIENTS) {
+ PARA_ERROR_LOG("maximal number of stat clients (%d) exceeded\n",
+ MAX_STAT_CLIENTS);
+ return -E_TOO_MANY_CLIENTS;
+ }
+ PARA_INFO_LOG("adding client on fd %d\n", fd);
+ new_client = para_calloc(sizeof(struct stat_client));
+ new_client->fd = fd;
+ new_client->item_mask = mask;
+ if (parser_friendly)
+ new_client->flags = SCF_PARSER_FRIENDLY;
+ para_list_add(&new_client->node, &client_list);
+ dump_stat_client_list();
+ num_clients++;
+ return 1;
+}
+/**
+ * Write a message to all connected status clients.
+ *
+ * \param item_num The number of the status item of \a msg.
+ *
+ * On write errors, remove the status client from the client list and close its
+ * file descriptor.
+ */
+void stat_client_write_item(int item_num)
+{
+ struct stat_client *sc, *tmp;
+ struct para_buffer pb = {.flags = 0};
+ struct para_buffer pfpb = {.flags = PBF_SIZE_PREFIX};
+ const uint64_t one = 1;
+
+ list_for_each_entry_safe(sc, tmp, &client_list, node) {
+ int fd = sc->fd, ret;
+
+ if (!((one << item_num) & sc->item_mask))
+ continue;
+ if (write_ok(fd) > 0) {
+ struct para_buffer *b =
+ (sc->flags & SCF_PARSER_FRIENDLY)? &pfpb : &pb;
+ char *msg = stat_item_values[item_num];
+ if (!b->buf)
+ WRITE_STATUS_ITEM(b, item_num, "%s\n",
+ msg? msg : "");
+ ret = write(fd, b->buf, b->offset);
+ if (ret == b->offset)
+ continue;
+ }
+ /* write error or fd not ready for writing */
+ close(fd);
+ num_clients--;
+ PARA_INFO_LOG("deleting client on fd %d\n", fd);
+ list_del(&sc->node);
+ free(sc);
+ dump_stat_client_list();
+ }
+ free(pb.buf);
+ free(pfpb.buf);
+// if (num_clients)
+// PARA_DEBUG_LOG("%d client(s)\n", num_clients);
+}
+
+/**
+ * Check if string is a known status item.
+ *
+ * \param item Buffer containing the text to check.
+ *
+ * \return If \a item is a valid status item, the number of that status item is
+ * returned. Otherwise, this function returns \p -E_UNKNOWN_STAT_ITEM.
+ */
+static int stat_item_valid(const char *item)
+{
+ int i;
+ if (!item || !*item) {
+ PARA_ERROR_LOG("%s\n", "no item");
+ return -E_UNKNOWN_STAT_ITEM;
+ }
+ FOR_EACH_STATUS_ITEM(i)
+ if (!strcmp(status_item_list[i], item))
+ return i;
+ PARA_ERROR_LOG("invalid stat item: %s\n", item);
+ return -E_UNKNOWN_STAT_ITEM;
+}
+
static int client_write(int fd, const char *buf)
{
size_t len;
int check_r;
/** non-zero if the pre_select hook added \p fd to the write fd set */
int check_w;
- /** the decrypted challenge */
- long unsigned challenge_nr;
/** pointer to the data to be sent to para_server */
char *inbuf;
/** number of bytes loaded in \p inbuf */
static void client_post_select(struct sched *s, struct task *t)
{
struct client_task *ct = container_of(t, struct client_task, task);
- unsigned char crypt_buf[1024];
t->error = 0;
if (ct->rc4c.fd < 0)
t->error = client_recv_buffer(ct);
if (t->error < 0)
goto err;
- PARA_INFO_LOG("<-- [challenge] (%d bytes)\n", t->error);
- /* decrypt challenge/rc4 buffer */
+ ct->loaded = t->error;
+ PARA_INFO_LOG("<-- [challenge] (%d bytes)\n", ct->loaded);
+ ct->status = CL_RECEIVED_CHALLENGE;
+ return;
+ case CL_RECEIVED_CHALLENGE:
+ {
+ /* decrypted challenge/rc4 buffer */
+ unsigned char crypt_buf[1024];
+ /* the SHA1 of the decrypted challenge */
+ unsigned char challenge_sha1[HASH_SIZE];
+
t->error = para_decrypt_buffer(ct->key_file, crypt_buf,
- (unsigned char *)ct->buf, t->error);
+ (unsigned char *)ct->buf, ct->loaded);
if (t->error < 0)
goto err;
- ct->status = CL_RECEIVED_CHALLENGE;
+ sha1_hash((char *)crypt_buf, CHALLENGE_SIZE, challenge_sha1);
RC4_set_key(&ct->rc4c.send_key, RC4_KEY_LEN,
crypt_buf + CHALLENGE_SIZE);
RC4_set_key(&ct->rc4c.recv_key, RC4_KEY_LEN,
crypt_buf + CHALLENGE_SIZE + RC4_KEY_LEN);
- return;
- case CL_RECEIVED_CHALLENGE:
- {
- unsigned char challenge_sha1[HASH_SIZE];
- /* send sha1 of decrypted challenge */
- sha1_hash((char *)crypt_buf, CHALLENGE_SIZE, challenge_sha1);
hash_to_asc(challenge_sha1, ct->buf);
PARA_INFO_LOG("--> %s\n", ct->buf);
t->error = send_bin_buffer(ct->rc4c.fd, (char *)challenge_sha1,
/* be careful in that heat, my dear */
int sample = *ip++, adjusted_sample = (PARA_ABS(sample) *
pcd->current_gain) >> gain_shift;
- if (unlikely(adjusted_sample > 32767)) { /* clip */
+ if (adjusted_sample > 32767) { /* clip */
PARA_NOTICE_LOG("clip: sample: %d, adjusted sample: %d\n",
sample, adjusted_sample);
adjusted_sample = 32767;
} else
pcd->peak = PARA_MAX(pcd->peak, adjusted_sample);
*op++ = sample >= 0? adjusted_sample : -adjusted_sample;
- if (likely(++pcd->num_samples & mask))
+ if (++pcd->num_samples & mask)
continue;
// PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain,
// pcd->peak);
.short_help = dccp_recv_args_info_help,
.detailed_help = dccp_recv_args_info_detailed_help
};
+ dccp_recv_cmdline_parser_free(&dummy);
}
PARA_ERROR(AUDIOD_SYNTAX, "syntax error"), \
PARA_ERROR(UCRED_PERM, "permission denied"), \
PARA_ERROR(INVALID_AUDIOD_CMD, "invalid command"), \
+ PARA_ERROR(TOO_MANY_CLIENTS, "maximal number of stat clients exceeded"), \
+ PARA_ERROR(UNKNOWN_STAT_ITEM, "status item not recognized"), \
#define FILTER_COMMON_ERRORS \
#define STAT_ERRORS \
- PARA_ERROR(TOO_MANY_CLIENTS, "maximal number of stat clients exceeded"), \
- PARA_ERROR(UNKNOWN_STAT_ITEM, "status item not recognized"), \
PARA_ERROR(STAT_ITEM_PARSE, "failed to parse status item"), \
.short_help = file_write_args_info_help,
.detailed_help = file_write_args_info_detailed_help
};
+ file_cmdline_parser_free(&dummy);
}
}
}
+static void free_filter_confs(void)
+{
+ int i;
+ struct filter_node *fn;
+
+ FOR_EACH_FILTER_NODE(fn, fc, i)
+ free(fn->conf);
+}
+
static int init_filter_chain(void)
{
int i, ret;
if (!conf.filter_given)
return -E_NO_FILTERS;
fc->num_filters = conf.filter_given;
- fc->filter_nodes = para_malloc(fc->num_filters * sizeof(struct filter_node));
+ fc->filter_nodes = para_calloc(fc->num_filters * sizeof(struct filter_node));
fc->inbufp = &sit->buf;
fc->in_loaded = &sit->loaded;
fc->input_error = &sit->task.error;
open_filters();
return 1;
err:
+ free_filter_confs();
free(fc->filter_nodes);
return ret;
}
s.default_timeout.tv_sec = 1;
s.default_timeout.tv_usec = 0;
ret = schedule(&s);
+ free_filter_confs();
close_filters(fc);
out:
free(sit->buf);
# define __noreturn __attribute__ ((noreturn))
# define __malloc __attribute__ ((malloc))
# define __a_unused __attribute__ ((unused))
-# define likely(x) __builtin_expect (!!(x), 1)
-# define unlikely(x) __builtin_expect (!!(x), 0)
-/*
- * p is the number of the "format string" parameter, and q is
- * the number of the first variadic parameter
+/*
+ * p is the number of the "format string" parameter, and q is
+ * the number of the first variadic parameter.
*/
# define __printf(p,q) __attribute__ ((format (printf, p, q)))
/*
string default="224.0.1.38"
optional
details="
- The default address resoves to DANTZ.MCAST.NET and activates
+ The default address resolves to DANTZ.MCAST.NET and activates
multicast.
"
.short_help = http_recv_args_info_help,
.detailed_help = http_recv_args_info_detailed_help
};
+ http_recv_cmdline_parser_free(&dummy);
}
struct list_head *prev;
};
+/** Define an initialized list head. */
+#define LIST_HEAD(name) struct list_head name = { &(name), &(name) }
+
+
/** must be called before using any other list functions */
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
return mm_compare_num_score_function(afhi->channels, private);
}
+static int mm_num_played_score_function(__a_unused const char *path,
+ const struct afs_info *afsi,
+ __a_unused const struct afh_info *afhi,
+ const void *private)
+{
+ return mm_compare_num_score_function(afsi->num_played, private);
+}
+
struct mm_year_data {
/** Comparator and year given at the mood line. */
struct mm_compare_num_data *cnd;
{DEFINE_COMPARE_NUM_MOOD_METHOD(bitrate)},
{DEFINE_COMPARE_NUM_MOOD_METHOD(frequency)},
{DEFINE_COMPARE_NUM_MOOD_METHOD(channels)},
+ {DEFINE_COMPARE_NUM_MOOD_METHOD(num_played)},
{.parser = NULL}
};
*/
#include <regex.h>
-#include <osl.h>
#include "para.h"
#include "error.h"
#include <ogg/ogg.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
-#include <osl.h>
#include "para.h"
#include "error.h"
.short_help = oss_write_args_info_help,
.detailed_help = oss_write_args_info_detailed_help
};
+ oss_cmdline_parser_free(&dummy);
}
extern const char *status_item_list[];
/** Loop over each status item. */
#define FOR_EACH_STATUS_ITEM(i) for (i = 0; i < NUM_STAT_ITEMS; i++)
-int stat_item_valid(const char *item);
-void stat_client_write_item(int item_num);
-int stat_client_add(int fd, uint64_t mask, int parser_friendly);
int for_each_stat_item(char *item_buf, size_t num_bytes,
int (*item_handler)(int, char *));
-void clear_and_dump_items(void);
__printf_2_3 void para_log(int, const char*, ...);
*/
#include <regex.h>
-#include <sys/types.h>
-#include <dirent.h>
#include "para.h"
-#include "close_on_fork.h"
-#include "list.h"
#include "error.h"
#include "string.h"
-#include "fd.h"
-/** The maximal number of simultaneous connections. */
-#define MAX_STAT_CLIENTS 50
-
-extern char *stat_item_values[NUM_STAT_ITEMS];
-
-/** Flags used for the stat command of para_audiod. */
-enum stat_client_flags {
- /** Enable parser-friendly output. */
- SCF_PARSER_FRIENDLY = 1,
-};
-
-/**
- * Describes a status client of para_audiod.
- *
- * There's one such structure per audiod client that sent the 'stat' command.
- *
- * A status client is identified by its file descriptor. para_audiod
- * keeps a list of connected status clients.
- */
-struct stat_client {
- /** The stat client's file descriptor. */
- int fd;
- /** Bitmask of those status items the client is interested in. */
- uint64_t item_mask;
- /** See \ref stat_client flags. s*/
- unsigned flags;
- /** Its entry in the list of stat clients. */
- struct list_head node;
-};
-
-static struct list_head client_list;
-static int initialized;
-static int num_clients;
-
-/** The list of all status items used by para_{server,audiod,gui}. */
-const char *status_item_list[] = {STATUS_ITEM_ARRAY};
-
-static void dump_stat_client_list(void)
-{
- struct stat_client *sc;
-
- if (!initialized)
- return;
- list_for_each_entry(sc, &client_list, node)
- PARA_INFO_LOG("stat client on fd %d\n", sc->fd);
-}
-/**
- * Add a status client to the list.
- *
- * \param fd The file descriptor of the client.
- * \param mask Bitfield of status items for this client.
- * \param parser_friendly Enable parser-friendly output mode.
- *
- * Only those status items having the bit set in \a mask will be
- * sent to the client.
- *
- * \return Positive value on success, or -E_TOO_MANY_CLIENTS if
- * the number of connected clients exceeds #MAX_STAT_CLIENTS.
- */
-int stat_client_add(int fd, uint64_t mask, int parser_friendly)
-{
- struct stat_client *new_client;
-
- if (num_clients >= MAX_STAT_CLIENTS) {
- PARA_ERROR_LOG("maximal number of stat clients (%d) exceeded\n",
- MAX_STAT_CLIENTS);
- return -E_TOO_MANY_CLIENTS;
- }
- if (!initialized) {
- INIT_LIST_HEAD(&client_list);
- initialized = 1;
- }
- PARA_INFO_LOG("adding client on fd %d\n", fd);
- new_client = para_calloc(sizeof(struct stat_client));
- new_client->fd = fd;
- new_client->item_mask = mask;
- if (parser_friendly)
- new_client->flags = SCF_PARSER_FRIENDLY;
- para_list_add(&new_client->node, &client_list);
- dump_stat_client_list();
- num_clients++;
- return 1;
-}
-/**
- * Write a message to all connected status clients.
- *
- * \param item_num The number of the status item of \a msg.
- *
- * On write errors, remove the status client from the client list and close its
- * file descriptor.
- */
-void stat_client_write_item(int item_num)
-{
- struct stat_client *sc, *tmp;
- struct para_buffer pb = {.flags = 0};
- struct para_buffer pfpb = {.flags = PBF_SIZE_PREFIX};
- const uint64_t one = 1;
-
- if (!initialized)
- return;
- list_for_each_entry_safe(sc, tmp, &client_list, node) {
- int fd = sc->fd, ret;
-
- if (!((one << item_num) & sc->item_mask))
- continue;
- if (write_ok(fd) > 0) {
- struct para_buffer *b =
- (sc->flags & SCF_PARSER_FRIENDLY)? &pfpb : &pb;
- char *msg = stat_item_values[item_num];
- if (!b->buf)
- WRITE_STATUS_ITEM(b, item_num, "%s\n",
- msg? msg : "");
- ret = write(fd, b->buf, b->offset);
- if (ret == b->offset)
- continue;
- }
- /* write error or fd not ready for writing */
- close(fd);
- num_clients--;
- PARA_INFO_LOG("deleting client on fd %d\n", fd);
- list_del(&sc->node);
- free(sc);
- dump_stat_client_list();
- }
- free(pb.buf);
- free(pfpb.buf);
-// if (num_clients)
-// PARA_DEBUG_LOG("%d client(s)\n", num_clients);
-}
-
-/**
- * Check if string is a known status item.
- *
- * \param item Buffer containing the text to check.
- *
- * \return If \a item is a valid status item, the number of that status item is
- * returned. Otherwise, this function returns \p -E_UNKNOWN_STAT_ITEM.
- */
-int stat_item_valid(const char *item)
-{
- int i;
- if (!item || !*item) {
- PARA_ERROR_LOG("%s\n", "no item");
- return -E_UNKNOWN_STAT_ITEM;
- }
- FOR_EACH_STATUS_ITEM(i)
- if (!strcmp(status_item_list[i], item))
- return i;
- PARA_ERROR_LOG("invalid stat item: %s\n", item);
- return -E_UNKNOWN_STAT_ITEM;
-}
/** The minimal length of a status item buffer. */
#define MIN_STAT_ITEM_LEN 9 /* 5 + 2 + 2, e.g. '0005 00:\n' */
.short_help = udp_recv_args_info_help,
.detailed_help = udp_recv_args_info_detailed_help
};
+ udp_recv_cmdline_parser_free(&dummy);
}