A single patch which removes a long standing issue of para_gui.
Cooking for half a year.
* refs/heads/t/gui-sigwinch:
gui: Catch SIGWINCH.
# Note that relative paths are relative to the directory from which doxygen is
# run.
-EXCLUDE =
+EXCLUDE = config.h
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
uname_rs := $(shell uname -rs)
cc_version := $(shell $(CC) --version | head -n 1)
GIT_VERSION := $(shell ./GIT-VERSION-GEN git-version.h)
-COPYRIGHT_YEAR := 2017
+COPYRIGHT_YEAR := 2018
ifeq ("$(origin O)", "command line")
build_dir := $(O)
NEWS
====
+-------------------------------------------
+0.6.2 (to be accounced) "elastic diversity"
+-------------------------------------------
+
+- para_gui no longer waits up to one second to update the screen when
+the geometry of the terminal changes.
+
----------------------------------------
0.6.1 (2017-09-23) "segmented iteration"
----------------------------------------
struct lls_parse_result *lpr = rn->lpr;
struct private_afh_recv_data *pard;
struct afh_info *afhi;
- const char *fn = RECV_CMD_OPT_STRING_VAL(AFH, FILENAME, lpr);
+ const char *fn = RECV_CMD_OPT_STRING_VAL(AFH, FILENAME, lpr), *msg;
int32_t bc = RECV_CMD_OPT_INT32_VAL(AFH, BEGIN_CHUNK, lpr);
const struct lls_opt_result *r_e = RECV_CMD_OPT_RESULT(AFH, END_CHUNK, lpr);
int ret;
goto out_unmap;
pard->audio_format_num = ret;
ret = -ERRNO_TO_PARA_ERROR(EINVAL);
+ msg = "no data chunks";
if (afhi->chunks_total == 0)
goto out_clear_afhi;
+ msg = "invalid begin chunk";
if (PARA_ABS(bc) >= afhi->chunks_total)
goto out_clear_afhi;
if (bc >= 0)
if (lls_opt_given(r_e)) {
int32_t ec = lls_int32_val(0, r_e);
ret = -ERRNO_TO_PARA_ERROR(EINVAL);
+ msg = "invalid end chunk";
if (PARA_ABS(ec) > afhi->chunks_total)
goto out_clear_afhi;
if (ec >= 0)
} else
pard->last_chunk = afhi->chunks_total - 1;
ret = -ERRNO_TO_PARA_ERROR(EINVAL);
+ msg = "begin chunk >= end chunk!?";
if (pard->first_chunk >= pard->last_chunk)
goto out_clear_afhi;
pard->current_chunk = pard->first_chunk;
return pard->audio_format_num;
out_clear_afhi:
clear_afhi(afhi);
+ PARA_ERROR_LOG("%s: %s\n", fn, msg);
out_unmap:
para_munmap(pard->map, pard->map_size);
close(pard->fd);
#include "string.h"
#include "afh.h"
#include "afs.h"
-#include "server.h"
#include "net.h"
+#include "server.h"
#include "ipc.h"
#include "list.h"
#include "sched.h"
struct command_task {
/** The file descriptor for the local socket. */
int fd;
- /**
- * Value sent by the command handlers to identify themselves as
- * children of the running para_server.
- */
- uint32_t cookie;
/** The associated task structure. */
struct task *task;
};
static enum play_mode current_play_mode;
static char *current_mop; /* mode or playlist specifier. NULL means dummy mood */
-/**
- * A random number used to "authenticate" the connection.
- *
- * para_server picks this number by random before it forks the afs process. The
- * command handlers know this number as well and write it to the afs socket,
- * together with the id of the shared memory area which contains the payload of
- * the afs command. A local process has to know this number to abuse the afs
- * service provided by the local socket.
- */
extern uint32_t afs_socket_cookie;
/**
ret = afs_tables[i].open(database_dir);
if (ret >= 0)
continue;
- PARA_ERROR_LOG("%s init: %s\n", afs_tables[i].name,
- para_strerror(-ret));
+ PARA_ERROR_LOG("could not open %s\n", afs_tables[i].name);
break;
}
if (ret >= 0)
}
/* returns 0 if no data available, 1 else */
-static int execute_afs_command(int fd, fd_set *rfds, uint32_t expected_cookie)
+static int execute_afs_command(int fd, fd_set *rfds)
{
uint32_t cookie;
int query_shmid;
return 1;
}
cookie = *(uint32_t *)buf;
- if (cookie != expected_cookie) {
+ if (cookie != afs_socket_cookie) {
PARA_NOTICE_LOG("received invalid cookie (got %u, expected %u)\n",
- (unsigned)cookie, (unsigned)expected_cookie);
+ (unsigned)cookie, (unsigned)afs_socket_cookie);
return 1;
}
query_shmid = *(int *)(buf + sizeof(cookie));
}
/* Check the list of connected clients. */
list_for_each_entry_safe(client, tmp, &afs_client_list, node) {
- ret = execute_afs_command(client->fd, &s->rfds, ct->cookie);
+ ret = execute_afs_command(client->fd, &s->rfds);
if (ret == 0) { /* prevent bogus connection flooding */
struct timeval diff;
tv_diff(now, &client->connect_time, &diff);
return 0;
}
-static void register_command_task(uint32_t cookie, struct sched *s)
+static void register_command_task(struct sched *s)
{
struct command_task *ct = &command_task_struct;
ct->fd = setup_command_socket_or_die();
- ct->cookie = cookie;
ct->task = task_register(&(struct task_info) {
.name = "afs command",
/**
* Initialize the audio file selector process.
*
- * \param cookie The value used for "authentication".
* \param socket_fd File descriptor used for communication with the server.
*/
-__noreturn void afs_init(uint32_t cookie, int socket_fd)
+__noreturn void afs_init(int socket_fd)
{
static struct sched s;
int i, ret;
ret = mark_fd_nonblocking(server_socket);
if (ret < 0)
goto out_close;
- PARA_INFO_LOG("server_socket: %d, afs_socket_cookie: %u\n",
- server_socket, (unsigned) cookie);
+ PARA_INFO_LOG("server_socket: %d\n", server_socket);
init_admissible_files(OPT_STRING_VAL(AFS_INITIAL_MODE));
- register_command_task(cookie, &s);
+ register_command_task(&s);
s.default_timeout.tv_sec = 0;
s.default_timeout.tv_usec = 999 * 1000;
ret = write(socket_fd, "\0", 1);
struct osl_object query;
/** Will be written on band SBD_OUTPUT, fully buffered. */
struct para_buffer pbout;
+ /**
+ * Convenience pointer for the deserialized parse result.
+ *
+ * Most afs command handlers call \ref send_lls_callback_request() to
+ * serialize the parse result of the subcommand and pass it to the
+ * callback. In afs context a pointer to the deserialized parse result
+ * is stored here.
+ */
struct lls_parse_result *lpr;
};
return pass_buffer_as_shm(amshd->fd, amshd->band, buf, size);
}
-__noreturn void afs_init(uint32_t cookie, int socket_fd);
+__noreturn void afs_init(int socket_fd);
__must_check int afs_event(enum afs_events event, struct para_buffer *pb,
void *data);
int send_callback_request(afs_callback *f, struct osl_object *query,
#include "sideband.h"
#include "command.h"
-static struct osl_table *audio_file_table;
+/* Data about one audio file. Needed for ls and stat output. */
+struct ls_data {
+ /* Usual audio format handler information. */
+ struct afh_info afhi;
+ /* Audio file selector information. */
+ struct afs_info afsi;
+ /* The full path of the audio file. */
+ char *path;
+ /* The score value (if -a was given). */
+ long score;
+ /* The hash value of the audio file data. */
+ unsigned char *hash;
+};
+
+/*
+ * The internal state of the audio file table is described by the following
+ * variables which are private to aft.c.
+ */
+static struct osl_table *audio_file_table; /* NULL if table not open */
+static struct osl_row *current_aft_row; /* NULL if no audio file open */
+
static char *status_items;
static char *parser_friendly_status_items;
+static struct ls_data status_item_ls_data;
/** The different sorting methods of the ls command. */
enum ls_sorting_method {
LS_MODE_PARSER,
};
-/* Data about one audio file. Needed for ls and stat output. */
-struct ls_data {
- /* Usual audio format handler information. */
- struct afh_info afhi;
- /* Audio file selector information. */
- struct afs_info afsi;
- /* The full path of the audio file. */
- char *path;
- /* The score value (if -a was given). */
- long score;
- /* The hash value of the audio file data. */
- unsigned char *hash;
-};
-
/**
* The size of the individual output fields of the ls command.
*
return ret;
}
-static struct ls_data status_item_ls_data;
-static struct osl_row *current_aft_row;
-
static void make_inode_status_items(struct para_buffer *pb)
{
struct stat statbuf = {.st_size = 0};
+----+----+---+------+---------------------------------------------------+
| N | N | Y | Y | (new file) create new entry (force has no effect)
+----+----+---+------+---------------------------------------------------+
-| N | N | N | Y | (new file) create new entry
+| N | N | N | Y | (new file) create new entry
+----+----+---+------+---------------------------------------------------+
Notes:
* every time.
*/
make_status_items();
+ return 0;
} default:
return 0;
}
+/* Copyright (C) 2016 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
+
+/** \file base64.h uudecode/base64 API. */
+
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,
local line="$COMP_LINE" OLD_IFS="$IFS"
local opts n
- if [[ "$COMP_WORDBREAKS" != ' ' ]]; then
- COMP_WORDBREAKS=' '
- return 124 # try again with proper value
- fi
# This extracts short and long options from the help output
local script='{
if ($1 ~ "-[a-zA-Z]," && $2 ~ "--[a-zA-Z]") {
unsigned char *challenge_hash;
/** The parsed command line (including the command). */
struct lls_parse_result *lpr;
- /** The config file for client options. */
- char *config_file;
/** The RSA private key. */
char *key_file;
/** Paraslash user name. */
if (!ct)
return;
free(ct->user);
- free(ct->config_file);
free(ct->key_file);
lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR);
free(ct->challenge_hash);
ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx));
if (ret < 0)
goto out;
- ll = CLIENT_OPT_UINT32_VAL(LOGLEVEL, lpr);
version_handle_flag("client", CLIENT_OPT_GIVEN(VERSION, lpr));
handle_help_flag(lpr);
lpr = merged_lpr;
}
/* success */
+ ll = CLIENT_OPT_UINT32_VAL(LOGLEVEL, lpr);
+ if (loglevel)
+ *loglevel = ll;
user = CLIENT_OPT_GIVEN(USER, lpr)?
para_strdup(CLIENT_OPT_STRING_VAL(USER, lpr)) : para_logname();
ct->scc.fd = -1;
ct->lpr = lpr;
ct->key_file = kf;
- ct->config_file = cf;
ct->user = user;
*ct_ptr = ct;
- if (loglevel)
- *loglevel = ll;
ret = lls_num_inputs(lpr);
out:
free(home);
+ free(cf);
if (ret < 0) {
if (errctx)
PARA_ERROR_LOG("%s\n", errctx);
free(errctx);
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
lls_free_parse_result(lpr, cmd);
- free(cf);
free(kf);
*ct_ptr = NULL;
}
#include "string.h"
#include "afh.h"
#include "afs.h"
+#include "net.h"
#include "server.h"
#include "list.h"
#include "send.h"
#include "sched.h"
#include "vss.h"
-#include "net.h"
#include "daemon.h"
#include "fd.h"
#include "ipc.h"
* permissions to execute that command, the function calls the corresponding
* command handler which does argument checking and further processing.
*
- * In order to cope with a DOS attacks, a timeout is set up which terminates
+ * In order to cope with DOS attacks, a timeout is set up which terminates
* the function if the connection was not authenticated when the timeout
* expires.
*
AC_SUBST($1_cppflags)
AC_SUBST($1_ldflags)
])
+AC_DEFUN([REQUIRE_EXECUTABLE], [
+ AC_PATH_PROG(m4_toupper([$1]), [$1])
+ test -z "$m4_toupper([$1])" && AC_MSG_ERROR(
+ [$1 is required to build this package])
+])
AC_USE_SYSTEM_EXTENSIONS
AC_C_BIGENDIAN()
-
-AC_PATH_PROG([BISON], [bison])
-AC_PATH_PROG([FLEX], [flex])
-
-AC_PATH_PROG([M4], [m4])
-test -z "$M4" && AC_MSG_ERROR(
- [The m4 macro processor is required to build this package])
-
AC_PROG_CC
AC_PROG_CPP
+REQUIRE_EXECUTABLE([bison])
+REQUIRE_EXECUTABLE([flex])
+REQUIRE_EXECUTABLE([m4])
+
executables="recv filter audioc write afh play"
########################################################################### osl
STASH_FLAGS
}
/*
- * Read 64 bytes from /dev/urandom and adds them to the SSL PRNG. Seed the PRNG
- * used by random() with a random seed obtained from SSL. If /dev/random is not
- * readable the function calls exit().
+ * Read 64 bytes from /dev/urandom and add them to the SSL PRNG. Seed the PRNG
+ * used by random(3) with a random seed obtained from SSL. If /dev/urandom is
+ * not readable, the function calls exit().
*
* \sa RAND_load_file(3), \ref get_random_bytes_or_die(), srandom(3),
* random(3), \ref para_random().
goto out;
ret = is_ssh_rsa_key(map, map_size);
if (!ret) {
- para_munmap(map, map_size);
- return -E_SSH_PARSE;
+ ret = -E_SSH_PARSE;
+ goto out_unmap;
}
cp = map + ret;
encoded_size = map_size - ret;
char *hostname;
/** Used for colored log messages. */
char log_colors[NUM_LOGLEVELS][COLOR_MAXLEN];
+ char *old_cwd;
};
static struct daemon the_daemon, *me = &the_daemon;
{
free(me->logfile_name);
me->logfile_name = NULL;
- if (logfile_name)
+ if (!logfile_name)
+ return;
+ if (me->old_cwd && logfile_name[0] != '/')
+ me->logfile_name = make_message("%s/%s", me->old_cwd,
+ logfile_name);
+ else
me->logfile_name = para_strdup(logfile_name);
}
/* become session leader */
if (setsid() < 0)
goto err;
+ me->old_cwd = getcwd(NULL, 0);
if (chdir("/") < 0)
goto err;
null = open("/dev/null", O_RDWR);
*/
void daemon_open_log_or_die(void)
{
- daemon_close_log();
+ FILE *new_log;
+
if (!me->logfile_name)
return;
- me->logfile = fopen(me->logfile_name, "a");
- if (!me->logfile) {
+ new_log = fopen(me->logfile_name, "a");
+ if (!new_log) {
PARA_EMERG_LOG("can not open %s: %s\n", me->logfile_name,
strerror(errno));
exit(EXIT_FAILURE);
}
+ daemon_close_log();
+ me->logfile = new_log;
/* equivalent to setlinebuf(), but portable */
setvbuf(me->logfile, NULL, _IOLBF, 0);
}
#include "error.h"
#include "string.h"
#include "afh.h"
-#include "server.h"
#include "net.h"
+#include "server.h"
#include "list.h"
#include "send.h"
#include "sched.h"
static int dccp_com_on(__a_unused struct sender_command_data *scd)
{
- return generic_com_on(dss, IPPROTO_DCCP);
+ generic_com_on(dss, IPPROTO_DCCP);
+ return 1;
}
static int dccp_com_off(__a_unused struct sender_command_data *scd)
*/
void dccp_send_init(struct sender *s)
{
- int ret;
-
s->status = dccp_status;
s->send = NULL;
s->pre_select = dccp_pre_select;
init_sender_status(dss, OPT_RESULT(DCCP_ACCESS),
OPT_UINT32_VAL(DCCP_PORT), OPT_UINT32_VAL(DCCP_MAX_CLIENTS),
OPT_GIVEN(DCCP_DEFAULT_DENY));
- ret = generic_com_on(dss, IPPROTO_DCCP);
- if (ret < 0)
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+ generic_com_on(dss, IPPROTO_DCCP);
}
* \param rfds An optional fd set pointer.
* \param num_bytes Result pointer. Contains the number of bytes read from \a fd.
*
- * If \a rfds is not \p NULL and the (non-blocking) file descriptor \a fd is
- * not set in \a rfds, this function returns early without doing anything.
- * Otherwise The function tries to read up to \a sz bytes from \a fd, where \a
- * sz is the sum of the lengths of all vectors in \a iov. As for xwrite(),
- * \p EAGAIN is not considered an error condition. However, \p EOF is.
+ * If rfds is not NULL and the (non-blocking) file descriptor fd is not set in
+ * rfds, this function returns early without doing anything. Otherwise it tries
+ * to read up to sz bytes from fd, where sz is the sum of the lengths of all
+ * vectors in iov. Like \ref xwrite(), EAGAIN and EINTR are not considered
+ * error conditions. However, EOF is.
*
* \return Zero or a negative error code. If the underlying call to readv(2)
* returned zero (indicating an end of file condition) or failed for some
- * reason other than \p EAGAIN, a negative error code is returned.
+ * reason other than EAGAIN or EINTR, a negative error code is returned.
*
* In any case, \a num_bytes contains the number of bytes that have been
* successfully read from \a fd (zero if the first readv() call failed with
if (ret == 0)
return -E_EOF;
if (ret < 0) {
- if (errno == EAGAIN)
+ if (errno == EAGAIN || errno == EINTR)
return 0;
return -ERRNO_TO_PARA_ERROR(errno);
}
* PROT_EXEC PROT_READ PROT_WRITE.
* \param flags Exactly one of MAP_SHARED and MAP_PRIVATE.
* \param fd The file to mmap from.
- * \param offset Mmap start.
* \param map Result pointer.
*
* \return Standard.
*
* \sa mmap(2).
*/
-int para_mmap(size_t length, int prot, int flags, int fd, off_t offset,
- void *map)
+int para_mmap(size_t length, int prot, int flags, int fd, void *map)
{
void **m = map;
errno = EINVAL;
if (!length)
goto err;
- *m = mmap(NULL, length, prot, flags, fd, offset);
+ *m = mmap(NULL, length, prot, flags, fd, (off_t)0);
if (*m != MAP_FAILED)
return 1;
err:
if (S_ISDIR(file_status.st_mode))
goto out;
- ret = para_mmap(*size, mmap_prot, mmap_flags, fd, 0, map);
+ ret = para_mmap(*size, mmap_prot, mmap_flags, fd, map);
out:
if (ret < 0 || !fd_ptr)
close(fd);
__must_check int mark_fd_blocking(int fd);
void para_fd_set(int fd, fd_set *fds, int *max_fileno);
__must_check int para_fgets(char *line, int size, FILE *f);
-int para_mmap(size_t length, int prot, int flags, int fd, off_t offset,
- void *map);
+int para_mmap(size_t length, int prot, int flags, int fd, void *map);
int para_open(const char *path, int flags, mode_t mode);
int para_mkdir(const char *path, mode_t mode);
int para_chdir(const char *path);
}
/*
- * This is called at the beginning of every program that uses libgcrypt. We
- * don't have to initialize any random seed here, but we must initialize the
- * gcrypt library. This task is performed by gcry_check_version() which can
- * also check that the gcrypt library version is at least the minimal required
- * version.
+ * This is called at the beginning of every program that uses libgcrypt. The
+ * call to gcry_check_version() initializes the gcrypt library and checks that
+ * we have at least the minimal required version.
*/
void init_random_seed_or_die(void)
{
const char *req_ver = "1.5.0";
+ int seed;
- if (gcry_check_version(req_ver))
- return;
- PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n",
- req_ver, gcry_check_version(NULL));
- exit(EXIT_FAILURE);
+ if (!gcry_check_version(req_ver)) {
+ PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n",
+ req_ver, gcry_check_version(NULL));
+ exit(EXIT_FAILURE);
+ }
+ get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed));
+ srandom(seed);
}
/** S-expression for the public part of an RSA key. */
}
if (phd->status == HTTP_SENT_GET_REQUEST) {
ret = read_pattern(rn->fd, HTTP_OK_MSG, strlen(HTTP_OK_MSG), &s->rfds);
- if (ret < 0)
+ if (ret < 0) {
+ PARA_ERROR_LOG("did not receive HTTP OK message\n");
goto out;
+ }
if (ret == 0)
return 0;
PARA_INFO_LOG("received ok msg, streaming\n");
btr_add_output_pool(rn->btrp, num_bytes - iov[0].iov_len, btrn);
}
out:
- if (ret < 0)
+ if (ret < 0) {
+ PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
btr_remove_node(&rn->btrn);
+ }
return ret;
}
#include "error.h"
#include "string.h"
#include "afh.h"
+#include "net.h"
#include "server.h"
#include "http.h"
#include "list.h"
#include "sched.h"
#include "vss.h"
#include "close_on_fork.h"
-#include "net.h"
#include "fd.h"
#include "chunk_queue.h"
#include "acl.h"
static int http_com_on(__a_unused struct sender_command_data *scd)
{
- return generic_com_on(hss, IPPROTO_TCP);
+ generic_com_on(hss, IPPROTO_TCP);
+ return 1;
}
static int http_com_off(__a_unused struct sender_command_data *scd)
*/
void http_send_init(struct sender *s)
{
- int ret;
s->status = http_status;
s->send = http_send;
s->pre_select = http_pre_select;
OPT_GIVEN(HTTP_DEFAULT_DENY));
if (OPT_GIVEN(HTTP_NO_AUTOSTART))
return;
- ret = generic_com_on(hss, IPPROTO_TCP);
- if (ret < 0)
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+ generic_com_on(hss, IPPROTO_TCP);
}
arg_info = required_arg
arg_type = string
typestr = mood_spec
- default_val = m/fade
[help]
This mood (or playlist) is selected right after setting the initial
volume.
arg_info = required_arg
arg_type = string
typestr = mood_spec
- default_val = m/sleep
[help]
Select the given mood or playlist after the fade-out. If unset,
playback is stopped until fade-in starts.
arg_info = required_arg
arg_type = string
typestr = mood_spec
- default_val = m/wake
[help]
This mood or playlist is selected right before fade-in begins.
[/help]
[suite recv]
version-string = GIT_VERSION()
[supercommand para_recv]
- purpose = a command line HTTP/DCCP/UDP stream grabber
+ purpose = receive an audio stream
+ [description]
+ para_recv starts one paraslash receiver (http, dccp, udp or afh)
+ to produce an audio stream in the same way para_audiod would download
+ the stream from para_server (http, dccp or udp) or para_server makes a
+ stream out of an audio file (afh). This is mostly useful for debugging.
+
+ Regardless of which receiver was started, the audio stream is written
+ to stdout.
+ [/description]
m4_include(common-option-section.m4)
m4_include(help.m4)
m4_include(detailed-help.m4)
Any options for the selected receiver must be quoted. Example:
-r 'http -i www.paraslash.org -p 8009'
+
+ If no receiver is given, http is assumed.
[/help]
The request is reconciled with the CCIDs on the server through the
'server-priority' mechanism of RFC 4340 6.3.1/10. The server CCIDs
- can be listed by calling 'para_client si'.
+ can be listed by calling 'para_client sender dccp status'.
[/help]
[subcommand udp]
purpose = receive an audio stream over UDP
{
char *cmd;
- client_cmd("stop");
- if (!afs_mode)
- return;
cmd = make_message("select %s", afs_mode);
client_cmd(cmd);
free(cmd);
PARA_INFO_LOG("waketime: %d:%02d\n", tm->tm_hour, tm->tm_min);
client_cmd("stop");
sleep(1);
- if (fot) {
+ if (fot && fo_mood) {
ret = set_initial_volume(m, h);
if (ret < 0)
return ret;
if (ret < 0)
return ret;
}
- if (OPT_GIVEN(SLEEP, SLEEP_MOOD)) {
+ if (sleep_mood) {
change_afs_mode(sleep_mood);
- client_cmd("play");
- } else
+ if (!fot || !fo_mood) /* currently stopped */
+ client_cmd("play");
+ } else if (fot && fo_mood) /* currently playing */
client_cmd("stop");
- if (!fit)
+ if (!fit || !fi_mood) /* nothing to do */
return 1;
change_afs_mode(fi_mood);
for (;;) {
*m = NULL;
ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def);
- if (ret < 0)
+ if (ret < 0) {
+ if (errmsg)
+ *errmsg = make_message(
+ "could not read mood definition");
return ret;
- if (!*mood_name)
- return -E_DUMMY_ROW;
+ }
+ assert(*mood_name);
mlpd.m = alloc_new_mood(mood_name);
ret = for_each_line(FELF_READ_ONLY, mood_def.data, mood_def.size,
parse_mood_line, &mlpd);
};
ret = osl(osl_get_row(moods_table, BLOBCOL_NAME, &obj, &row));
if (ret < 0) {
- PARA_NOTICE_LOG("no such mood: %s\n", mood_name);
+ if (errmsg)
+ *errmsg = make_message("no such mood: %s",
+ mood_name);
return ret;
}
ret = load_mood(row, &m, errmsg);
aa.m = current_mood;
PARA_NOTICE_LOG("computing statistics of admissible files\n");
ret = audio_file_loop(&aa, add_if_admissible);
- if (ret < 0)
+ if (ret < 0) {
+ if (errmsg)
+ *errmsg = make_message("audio file loop failed");
return ret;
+ }
for (i = 0; i < statistics.num; i++) {
struct admissible_file_info *a = aa.array + i;
ret = add_to_score_table(a->aft_row, a->score);
- if (ret < 0)
+ if (ret < 0) {
+ if (errmsg)
+ *errmsg = make_message(
+ "could not add row to score table");
goto out;
+ }
}
log_statistics();
ret = statistics.num;
* The public API (at the bottom of the file) allows to parse the same mood
* definition many times in an efficient manner.
*
- * The first function to all is \ref mp_init(), which analyzes the given mood
+ * The first function to call is \ref mp_init(), which analyzes the given mood
* definition syntactically. It returns the abstract syntax tree of the mood
* definition and pre-compiles all regular expression patterns to make later
* pattern matching efficient.
for (; ai; ai = ai->ai_next) {
int fd;
ret = socket(ai->ai_family, sock_type(l4type), l4type);
- if (ret < 0)
+ if (ret < 0) {
+ PARA_NOTICE_LOG("socket(): %s\n", strerror(errno));
continue;
+ }
fd = ret;
flowopt_setopts(fd, fo);
if (!passive) {
- if (connect(fd, ai->ai_addr, ai->ai_addrlen) == 0)
- return fd;
- close(fd);
- continue;
+ if (connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
+ PARA_NOTICE_LOG("connect(): %s\n",
+ strerror(errno));
+ close(fd);
+ continue;
+ }
+ return fd;
}
/*
* Reuse the address on passive sockets to avoid failure on
*/
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)) == -1) {
+ PARA_NOTICE_LOG("setsockopt(): %s\n", strerror(errno));
close(fd);
continue;
}
if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
+ PARA_NOTICE_LOG("bind(): %s\n", strerror(errno));
close(fd);
continue;
}
*
* \param l4type The transport-layer type (\p IPPROTO_xxx).
* \param port The decimal port number to listen on.
- * \param fo Flowopts (if any) to set before starting to listen.
*
* \return Positive integer (socket descriptor) on success, negative value
* otherwise.
*
* \sa \ref makesock(), ip(7), ipv6(7), bind(2), listen(2).
*/
-int para_listen(unsigned l4type, uint16_t port, struct flowopts *fo)
+int para_listen_simple(unsigned l4type, uint16_t port)
{
- int ret, fd = makesock(l4type, 1, NULL, port, fo);
+ int ret, fd = makesock(l4type, 1, NULL, port, NULL);
if (fd > 0) {
ret = listen(fd, BACKLOG);
#define DCCP_SOCKOPT_TX_CCID 14 /**< Set/get the TX CCID. */
#endif
+/** The maximum length of the host component in an URL. */
+#define MAX_HOSTLEN 256
+
/**
* Flowopts: Transport-layer independent encapsulation of socket options
* that need to be registered prior to setting up a connection.
*/
/** How many pending connections queue of a listening server will hold. */
#define BACKLOG 10
-extern int para_listen(unsigned l4type, uint16_t port, struct flowopts *fo);
-static inline int para_listen_simple(unsigned l4type, uint16_t port)
-{
- return para_listen(l4type, port, NULL);
-}
+int para_listen_simple(unsigned l4type, uint16_t port);
/** Pretty-printing of IPv4/6 socket addresses */
extern char *remote_name(int sockfd);
afhi->seconds_total = num_frames / afhi->frequency;
/* use roughly one page per chunk */
frames_per_chunk = num_frames / i;
- PARA_INFO_LOG("%" PRIu32 "seconds, %d frames/chunk\n",
+ PARA_INFO_LOG("%" PRIu32 " seconds, %d frames/chunk\n",
afhi->seconds_total, frames_per_chunk);
ct_size = 250;
afhi->chunk_table = para_malloc(ct_size * sizeof(uint32_t));
if (OPT_GIVEN(DETAILED_HELP))
help = lls_long_help(CMD_PTR);
- else if (OPT_GIVEN(HELP))
+ else if (OPT_GIVEN(HELP) || lls_num_inputs(play_lpr) == 0)
help = lls_short_help(CMD_PTR);
else
return;
goto fail;
loglevel = OPT_UINT32_VAL(LOGLEVEL);
version_handle_flag("play", OPT_GIVEN(VERSION));
- handle_help_flags();
+ handle_help_flags(); /* also handles the zero-arg case */
if (OPT_GIVEN(CONFIG_FILE))
cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE));
else {
if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && OPT_GIVEN(CONFIG_FILE))
goto free_cf;
ret = 0;
- goto free_cf;
+ goto setup_keymap;
}
ret = lls(lls_convert_config(map, sz, NULL, &cf_argv, &errctx));
para_munmap(map, sz);
lls_free_parse_result(play_lpr, cmd);
play_lpr = merged_lpr;
loglevel = OPT_UINT32_VAL(LOGLEVEL);
-
- ret = lls(lls_check_arg_count(play_lpr, 1, INT_MAX, &errctx));
- if (ret < 0)
- goto free_cf;
+setup_keymap:
num_kmas = OPT_GIVEN(KEY_MAP);
for (i = 0; i < num_kmas; i++) {
const char *kma = lls_string_val(i, OPT_RESULT(KEY_MAP));
size_t *result_frames)
{
int ret, num_samples, out_samples;
+ float *in_float;
int16_t *out;
SRC_DATA data;
data.output_frames = num_frames * ctx->ratio + 1;
out_samples = data.output_frames * ctx->channels;
- data.data_in = para_malloc(num_samples * sizeof(float));
- src_short_to_float_array(in, data.data_in, num_samples);
+ in_float = para_malloc(num_samples * sizeof(float));
+ src_short_to_float_array(in, in_float, num_samples);
+ data.data_in = in_float;
data.data_out = para_malloc(out_samples * sizeof(float));
ret = src_process(ctx->src_state, &data);
- free(data.data_in);
+ free(in_float);
if (ret != 0) {
PARA_ERROR_LOG("%s\n", src_strerror(ret));
free(data.data_out);
struct sender_status *ss);
void generic_com_deny(struct sender_command_data *scd,
struct sender_status *ss);
-int generic_com_on(struct sender_status *ss, unsigned protocol);
+void generic_com_on(struct sender_status *ss, unsigned protocol);
void generic_com_off(struct sender_status *ss);
char *generic_sender_help(void);
struct sender_client *accept_sender_client(struct sender_status *ss, fd_set *rfds);
/** Clients will be kicked if there are more than that many bytes pending. */
#define MAX_CQ_BYTES 40000
-/**
- * Open a passive socket of given layer4 type.
- *
- * Set the resulting file descriptor to nonblocking mode and add it to the list
- * of fds that are being closed in the child process when the server calls
- * fork().
- *
- * \param l4type The transport-layer protocol.
- * \param port The port number.
- *
- * \return The listening fd on success, negative on errors.
- */
-static int open_sender(unsigned l4type, int port)
-{
- int fd, ret = para_listen_simple(l4type, port);
-
- if (ret < 0)
- return ret;
- fd = ret;
- ret = mark_fd_nonblocking(fd);
- if (ret < 0) {
- close(fd);
- return ret;
- }
- add_close_on_fork_list(fd);
- return fd;
-}
-
/**
* Shut down a client connected to a paraslash sender.
*
* Activate a paraslash sender.
*
* \param ss The sender to activate.
- * \param protocol The symbolic name of the transport-layer protocol.
+ * \param protocol layer4 type (IPPROTO_TCP or IPPROTO_DCCP).
*
- * \return Standard.
+ * This opens a passive socket of given layer4 type, sets the resulting file
+ * descriptor to nonblocking mode and adds it to the close on fork list.
+ *
+ * Errors are logged but otherwise ignored.
*/
-int generic_com_on(struct sender_status *ss, unsigned protocol)
+void generic_com_on(struct sender_status *ss, unsigned protocol)
{
- int ret;
+ int fd, ret;
if (ss->listen_fd >= 0)
- return 1;
- ret = open_sender(protocol, ss->port);
- if (ret < 0)
- return ret;
- ss->listen_fd = ret;
- return 1;
+ return;
+ ret = para_listen_simple(protocol, ss->port);
+ if (ret < 0) {
+ PARA_ERROR_LOG("could not listen on port %d: %s\n", ss->port,
+ para_strerror(-ret));
+ return;
+ }
+ fd = ret;
+ ret = mark_fd_nonblocking(fd);
+ if (ret < 0) {
+ PARA_ERROR_LOG("could not set %s socket fd for port %d to "
+ "nonblocking mode: %s\n",
+ protocol == IPPROTO_TCP? "TCP" : "DCCP", ss->port,
+ para_strerror(-ret));
+ close(fd);
+ return;
+ }
+ add_close_on_fork_list(fd);
+ ss->listen_fd = fd;
+ return;
}
/**
* \param ss The sender whose listening fd is ready for reading.
* \param rfds Passed to para_accept(),
*
- * This must be called only if the socket fd of \a ss is ready for reading. It
- * calls para_accept() to accept the connection and performs the following
- * actions on the resulting file descriptor \a fd:
+ * This calls para_accept() and performs the following actions on the resulting
+ * file descriptor fd:
*
* - Checks whether the maximal number of connections are exceeded.
* - Sets \a fd to nonblocking mode.
#include "afh.h"
#include "string.h"
#include "afs.h"
+#include "net.h"
#include "server.h"
#include "list.h"
#include "send.h"
#include "vss.h"
#include "config.h"
#include "close_on_fork.h"
-#include "net.h"
#include "daemon.h"
#include "ipc.h"
#include "fd.h"
/* Command line options (no config file options). Used in handle_sighup(). */
static struct lls_parse_result *cmdline_lpr;
-/** A random value used in child context for authentication. */
+/**
+ * A random number used to "authenticate" the afs connection.
+ *
+ * para_server picks this number by random before it forks the afs process. The
+ * command handlers know this number as well and write it to the afs socket,
+ * together with the id of the shared memory area which contains the payload of
+ * the afs command. A local process has to know this number to abuse the afs
+ * service provided by the local socket.
+ */
uint32_t afs_socket_cookie;
/** The mutex protecting the shared memory area containing the mmd struct. */
struct lls_parse_result *cf_lpr, *merged_lpr;
char *home = para_homedir();
- daemon_close_log();
if (OPT_GIVEN(CONFIG_FILE))
cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE));
else
i = argc - lls_num_inputs(cmdline_lpr) - 1;
sprintf(argv[i], "para_server (afs)");
close(afs_server_socket[0]);
- afs_init(afs_socket_cookie, afs_server_socket[1]);
+ afs_init(afs_server_socket[1]);
}
close(afs_server_socket[1]);
if (read(afs_server_socket[0], &c, 1) <= 0) {
/** Size of the selector_info and audio_file info strings of struct misc_meta_data. */
#define MMD_INFO_SIZE 16384
-/** The maximum length of the host component in an URL */
-#define MAX_HOSTLEN 256
-
-
/** Arguments for the sender command. */
struct sender_command_data {
/** Greater than zero indicates that a sender cmd is already queued. */
#include "error.h"
#include "string.h"
#include "afh.h"
+#include "net.h"
#include "server.h"
#include "list.h"
#include "send.h"
#include "sched.h"
#include "vss.h"
#include "portable_io.h"
-#include "net.h"
#include "fd.h"
#include "close_on_fork.h"
#include "string.h"
#include "afh.h"
#include "afs.h"
-#include "server.h"
#include "net.h"
+#include "server.h"
#include "list.h"
#include "send.h"
#include "sched.h"
goto err;
}
ret = para_mmap(statbuf.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE,
- passed_fd, 0, &vsst->map);
+ passed_fd, &vsst->map);
if (ret < 0)
goto err;
vsst->mapsize = statbuf.st_size;