-------------------------------------------
-0.?.? (to be announced) "spectral gravity"
-------------------------------------------
+---------------------------------------------
- 0.?.? (to be announced) "invertible validity"
++0.5.0 (to be announced) "invertible validity"
+---------------------------------------------
+
++ - The sideband compatibility code has been removed, hence
++ sideband connections (introduced in 0.4.11) are now mandatory.
++ - Addblob commands can produce output.
++ - The stat command no longer sends garbage when para_server was
++ compiled against libgcrypt.
++
+--------------------------------------
+0.4.13 (2013-07-29) "spectral gravity"
+--------------------------------------
+
+One more 0.4.x release before the API-breaking changes for 0.5.0 go
+in. The main features of this release are the ogg/opus audio format,
+and UTF-8 support, but it includes also tons of other improvements
+and fixes all over the place.
+
+ - New audio format: ogg/opus.
+ - UTF8 support for para_gui and the mp3 audio format handler.
+ - Scheduler improvements and fixes.
+ - The obsolete gettimeofday() function has been replaced
+ by clock_gettime() on systems which support it.
+ - Speed and usability improvements for para_gui.
+ - para_client now restores the fd flags of stdin and stdout
+ on shutdown.
+ - Improved manual pages.
+ - Consistent version strings for all executables.
+ - Reduced dependencies on generated files result in fewer
+ recompilations on changes.
+ - Performance improvements for the compress filter.
+ - Improved downloads web page.
-----------------------------------------
0.4.12 (2012-12-20) "volatile relativity"
return 1;
}
- if (cc->use_sideband)
- return send_sb(&cc->scc, result->data, result->size, band,
- true);
- return sc_send_bin_buffer(&cc->scc, result->data, result->size);
+/**
+ * Result handler for sending data to the para_client process.
+ *
+ * \param result The data to be sent.
+ * \param band The band designator.
+ * \param private Pointer to the command context.
+ *
+ * \return The return value of the underlying call to \ref command.c::send_sb.
+ *
+ * \sa \ref callback_result_handler, \ref command.c::send_sb.
+ */
+int afs_cb_result_handler(struct osl_object *result, uint8_t band,
+ void *private)
+{
+ struct command_context *cc = private;
+
+ assert(cc);
+ if (!result->size)
+ return 1;
++ return send_sb(&cc->scc, result->data, result->size, band, true);
+}
+
static void com_select_callback(int fd, const struct osl_object *query)
{
struct para_buffer pb = {
free(pb.buf);
}
-/**
- * Result handler for sending data to the para_client process.
- *
- * \param result The data to be sent.
- * \param band The band designator.
- * \param private Pointer to the command context.
- *
- * \return The return value of the underlying call to \ref command.c::send_sb.
- *
- * \sa \ref callback_result_handler, \ref command.c::send_sb.
- */
-int afs_cb_result_handler(struct osl_object *result, uint8_t band,
- void *private)
-{
- struct command_context *cc = private;
-
- assert(cc);
- if (!result->size)
- return 1;
- return send_sb(&cc->scc, result->data, result->size, band, true);
-}
-
int com_select(struct command_context *cc)
{
struct osl_object query;
para_fd_set(st->fd, &s->rfds, &s->max_fileno);
}
-static void afs_signal_post_select(struct sched *s, struct task *t)
+static int afs_signal_post_select(struct sched *s, __a_unused struct task *t)
{
- int signum;
+ int signum, ret;
if (getppid() == 1) {
PARA_EMERG_LOG("para_server died\n");
}
signum = para_next_signal(&s->rfds);
if (signum == 0)
- return;
+ return 0;
if (signum == SIGHUP) {
close_afs_tables();
parse_config_or_die(1);
- t->error = open_afs_tables();
- if (t->error < 0)
- return;
+ ret = open_afs_tables();
+ if (ret < 0)
+ return ret;
init_admissible_files(current_mop);
- return;
+ return 0;
}
PARA_EMERG_LOG("terminating on signal %d\n", signum);
shutdown:
task_notify_all(s, E_AFS_SIGNAL);
- t->error = -E_AFS_SIGNAL;
+ return -E_AFS_SIGNAL;
}
static void register_signal_task(struct sched *s)
/** Shutdown connection if query has not arrived until this many seconds. */
#define AFS_CLIENT_TIMEOUT 3
-static void command_post_select(struct sched *s, struct task *t)
+static int command_post_select(struct sched *s, struct task *t)
{
struct command_task *ct = container_of(t, struct command_task, task);
struct sockaddr_un unix_addr;
int fd, ret;
ret = task_get_notification(t);
- if (ret < 0) {
- t->error = ret;
- return;
- }
+ if (ret < 0)
+ return ret;
ret = execute_server_command(&s->rfds);
if (ret < 0) {
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
task_notify_all(s, -ret);
- t->error = ret;
- return;
+ return ret;
}
/* Check the list of connected clients. */
list_for_each_entry_safe(client, tmp, &afs_client_list, node) {
if (ret < 0)
PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
if (ret <= 0)
- return;
+ return 0;
ret = mark_fd_nonblocking(fd);
if (ret < 0) {
PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
close(fd);
- return;
+ return 0;
}
client = para_malloc(sizeof(*client));
client->fd = fd;
client->connect_time = *now;
para_list_add(&client->node, &afs_client_list);
+ return 0;
}
static void register_command_task(uint32_t cookie, struct sched *s)
}
ret = send_callback_request(create_tables_callback, &query,
afs_cb_result_handler, cc);
- if (ret < 0 && !cc->use_sideband)
- /* ignore return value */
- sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
return ret;
}
.column_descriptions = aft_cols
};
-/* We don't want * dot or dot-dot anywhere. */
+/* We don't want dot or dot-dot anywhere. */
static int verify_dotfile(const char *rest)
{
/*
uint16_t afhi_offset, chunks_offset;
hash = (unsigned char *)buf + CAB_HASH_OFFSET;
- hash_to_asc(hash, asc);;
+ hash_to_asc(hash, asc);
objs[AFTCOL_HASH].data = buf + CAB_HASH_OFFSET;
objs[AFTCOL_HASH].size = HASH_SIZE;
ret = 1;
if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */
if (pad->flags & ADD_FLAG_VERBOSE)
- send_ret = pad->cc->use_sideband?
- send_sb_va(&pad->cc->scc, SBD_OUTPUT,
- "lazy-ignore: %s\n", path)
- :
- sc_send_va_buffer(&pad->cc->scc,
- "lazy-ignore: %s\n", path);
+ send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
+ "lazy-ignore: %s\n", path);
goto out_free;
}
/* We still want to add this file. Compute its hash. */
ret = 1;
if (pb && hs && hs == pb && !(pad->flags & ADD_FLAG_FORCE)) {
if (pad->flags & ADD_FLAG_VERBOSE)
- send_ret = pad->cc->use_sideband?
- send_sb_va(&pad->cc->scc, SBD_OUTPUT,
- "%s exists, not forcing update\n", path)
- :
- sc_send_va_buffer(&pad->cc->scc,
- "%s exists, not forcing update\n", path);
+ send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
+ "%s exists, not forcing update\n", path);
goto out_unmap;
}
/*
munmap(map.data, map.size);
close(fd);
if (pad->flags & ADD_FLAG_VERBOSE) {
- send_ret = pad->cc->use_sideband?
- send_sb_va(&pad->cc->scc, SBD_OUTPUT,
- "adding %s\n", path)
- :
- sc_send_va_buffer(&pad->cc->scc,
- "adding %s\n", path);
+ send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
+ "adding %s\n", path);
if (send_ret < 0)
goto out_free;
}
munmap(map.data, map.size);
out_free:
if (ret < 0 && send_ret >= 0)
- send_ret = pad->cc->use_sideband?
- send_sb_va(&pad->cc->scc, SBD_ERROR_LOG,
- "failed to add %s (%s)\n", path,
- para_strerror(-ret))
- :
- sc_send_va_buffer(&pad->cc->scc,
- "failed to add %s (%s)\n", path,
- para_strerror(-ret));
+ send_ret = send_sb_va(&pad->cc->scc, SBD_ERROR_LOG,
+ "failed to add %s (%s)\n", path, para_strerror(-ret));
free(obj.data);
clear_afhi(afhi_ptr);
/* Stop adding files only on send errors. */
char *path;
ret = verify_path(cc->argv[i], &path);
if (ret < 0) {
- ret = cc->use_sideband?
- send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s: %s\n",
- cc->argv[i], para_strerror(-ret))
- :
- sc_send_va_buffer(&cc->scc, "%s: %s\n",
+ ret = send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s: %s\n",
cc->argv[i], para_strerror(-ret));
if (ret < 0)
return ret;
}
ret = stat(path, &statbuf);
if (ret < 0) {
- ret = cc->use_sideband?
- send_sb_va(&cc->scc, SBD_ERROR_LOG,
- "failed to stat %s (%s)\n", path,
- strerror(errno))
- :
- sc_send_va_buffer(&cc->scc,
- "failed to stat %s (%s)\n", path,
- strerror(errno));
+ ret = send_sb_va(&cc->scc, SBD_ERROR_LOG,
+ "failed to stat %s (%s)\n", path,
+ strerror(errno));
free(path);
if (ret < 0)
return ret;
else
ret = add_one_audio_file(path, &pad);
if (ret < 0) {
- if (cc->use_sideband)
- send_sb_va(&cc->scc, SBD_OUTPUT, "%s: %s\n", path,
- para_strerror(-ret));
- else
- sc_send_va_buffer(&cc->scc, "%s: %s\n", path,
- para_strerror(-ret));
+ send_sb_va(&cc->scc, SBD_OUTPUT, "%s: %s\n", path,
+ para_strerror(-ret));
free(path);
return ret;
}
PARA_EMERG_LOG("can not read config file %s\n", config_file);
goto err;
}
- if (ret)
+ if (ret) {
audiod_cmdline_parser_config_file(config_file, &conf, ¶ms);
+ daemon_set_loglevel(conf.loglevel_arg);
+ }
free(config_file);
- daemon_set_loglevel(conf.loglevel_arg);
return;
err:
free(config_file);
struct audio_format_info *a = afi + s->format;
if (a->num_filters == 0)
return;
- for (i = 0; i < a->num_filters; i++) {
+ for (i = a->num_filters - 1; i >= 0; i--) {
struct filter_node *fn = s->fns + i;
struct filter *f;
fn->conf = a->filter_conf[i];
fn->task.pre_select = f->pre_select;
fn->task.post_select = f->post_select;
-
fn->btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = f->name, .parent = parent,
.handler = f->execute, .context = fn));
para_fd_set(st->fd, &s->rfds, &s->max_fileno);
}
-static void signal_post_select(struct sched *s, __a_unused struct task *t)
+static int signal_post_select(struct sched *s, __a_unused struct task *t)
{
int signum;
PARA_EMERG_LOG("terminating on signal %d\n", signum);
clean_exit(EXIT_FAILURE, "caught deadly signal");
}
+ return 0;
}
static void signal_setup_default(struct signal_task *st)
para_fd_set(ct->fd, &s->rfds, &s->max_fileno);
}
-static void command_post_select(struct sched *s, struct task *t)
+static int command_post_select(struct sched *s, struct task *t)
{
int ret;
struct command_task *ct = container_of(t, struct command_task, task);
if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
audiod_status_dump();
+ return 0;
}
static void init_command_task(struct command_task *ct)
tv_add(now, &delay, &stat_task->restart_barrier);
}
-static void try_to_close_slot(int slot_num)
+static bool must_close_slot(int slot_num)
{
struct slot_info *s = &slot[slot_num];
struct audio_format_info *a = afi + s->format;
int i;
if (s->format < 0)
- return;
+ return false;
if (s->receiver_node && s->receiver_node->task.error >= 0)
- return;
+ return false;
for (i = 0; i < a->num_filters; i++)
if (s->fns && s->fns[i].task.error >= 0)
- return;
+ return false;
if (a->num_writers > 0) {
for (i = 0; i < a->num_writers; i++)
if (s->wns && s->wns[i].task.error >= 0)
- return;
+ return false;
} else {
if (s->wns && s->wns[0].task.error >= 0)
- return;
+ return false;
+ }
+ return true;
+}
+
+static void close_unused_slots(void)
+{
+ int i;
+
+ FOR_EACH_SLOT(i) {
+ struct slot_info *s = slot + i;
+ if (!must_close_slot(i))
+ continue;
+ PARA_INFO_LOG("closing slot %d\n", i);
+ close_writers(s);
+ close_filters(s);
+ close_receiver(i);
+ clear_slot(i);
}
- PARA_INFO_LOG("closing slot %d\n", slot_num);
- close_writers(s);
- close_filters(s);
- close_receiver(slot_num);
- clear_slot(slot_num);
}
/*
*/
static void start_stop_decoders(void)
{
- int i, ret;
+ int ret;
struct slot_info *sl;
struct audio_format_info *a;
- FOR_EACH_SLOT(i)
- try_to_close_slot(i);
+ close_unused_slots();
if (audiod_status != AUDIOD_ON ||
!(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING))
return notify_receivers(E_NOT_PLAYING);
static void status_pre_select(struct sched *s, struct task *t)
{
struct status_task *st = container_of(t, struct status_task, task);
- int ret, cafn = stat_task->current_audio_format_num;
+ int i, ret, cafn = stat_task->current_audio_format_num;
if (must_start_decoder())
goto min_delay;
+ FOR_EACH_SLOT(i)
+ if (must_close_slot(i))
+ goto min_delay;
ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF);
if (ret > 0)
goto min_delay;
}
/* restart the client task if necessary */
-static void status_post_select(struct sched *s, struct task *t)
+static int status_post_select(struct sched *s, struct task *t)
{
struct status_task *st = container_of(t, struct status_task, task);
close_stat_pipe();
goto out;
}
- if (st->ct->status != CL_RECEIVING)
+ if (st->ct->status != CL_EXECUTING)
goto out;
ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF);
if (ret <= 0) {
st->last_status_read = *now;
out:
start_stop_decoders();
+ return 0;
}
static void init_status_task(struct status_task *st)
__noreturn static void print_help_and_die(void)
{
- int d = conf.detailed_help_given;
- const char **p = d? audiod_args_info_detailed_help
- : audiod_args_info_help;
-
- printf_or_die("%s\n\n", AUDIOD_CMDLINE_PARSER_PACKAGE "-"
- AUDIOD_CMDLINE_PARSER_VERSION);
- printf_or_die("%s\n\n", audiod_args_info_usage);
- for (; *p; p++)
- printf_or_die("%s\n", *p);
- print_receiver_helps(d);
- print_filter_helps(d);
- print_writer_helps(d);
+ struct ggo_help h = DEFINE_GGO_HELP(audiod);
+ bool d = conf.detailed_help_given;
+ unsigned flags;
+
+ flags = d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS;
+ ggo_print_help(&h, flags);
+
+ flags = d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS;
+ print_receiver_helps(flags);
+ print_filter_helps(flags);
+ print_writer_helps(flags);
exit(0);
}
};
valid_fd_012();
- if (audiod_cmdline_parser_ext(argc, argv, &conf, ¶ms))
- exit(EXIT_FAILURE);
- HANDLE_VERSION_FLAG("audiod", conf);
+ audiod_cmdline_parser_ext(argc, argv, &conf, ¶ms);
+ daemon_set_loglevel(conf.loglevel_arg);
+ version_handle_flag("audiod", conf.version_given);
/* init receivers/filters/writers early to make help work */
recv_init();
filter_init();
sched_min_delay(s);
}
-static void exec_post_select(__a_unused struct sched *s, struct task *t)
+static int exec_post_select(__a_unused struct sched *s, struct task *t)
{
struct exec_task *et = container_of(t, struct exec_task, task);
struct btr_node *btrn = et->btrn;
int ret;
ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
- if (ret <= 0) {
- t->error = ret;
- return;
- }
+ if (ret <= 0)
+ return ret;
sz = btr_next_buffer(btrn, &buf);
if (sz <= 1)
goto out;
et->result_buf[et->result_size - 1] = '\0';
out:
btr_consume(btrn, sz);
+ return 0;
}
static int make_client_argv(const char *line)
int ret;
client_disconnect(ct);
- if (!line || !*line)
- return 0;
- PARA_DEBUG_LOG("line handler: %s\n", line);
+ PARA_DEBUG_LOG("line: %s\n", line);
ret = make_client_argv(line);
- if (ret < 0)
+ if (ret <= 0)
return ret;
ret = client_connect(ct, &sched, NULL, NULL);
if (ret < 0)
return ret;
- i9e_attach_to_stdout(ct->btrn);
+ i9e_attach_to_stdout(ct->btrn[0]);
return 1;
}
.completers = completers,
};
- PARA_NOTICE_LOG("\n%s\n", VERSION_TEXT("client"));
+ PARA_NOTICE_LOG("\n%s\n", version_text("client"));
if (ct->conf.history_file_given)
history_file = para_strdup(ct->conf.history_file_arg);
else {
#endif /* HAVE_READLINE */
- static int supervisor_post_select(struct sched *s, __a_unused struct task *t)
+ struct supervisor_task {
+ bool stdout_task_started;
+ struct task task;
+ };
+
-static void supervisor_post_select(struct sched *s, struct task *t)
++static int supervisor_post_select(struct sched *s, struct task *t)
{
- if (ct->task.error < 0) {
- t->error = ct->task.error;
- return;
- }
+ struct supervisor_task *svt = container_of(t, struct supervisor_task,
+ task);
+
- return;
+ if (ct->task.error < 0)
+ return ct->task.error;
+ if (!svt->stdout_task_started && ct->status == CL_EXECUTING) {
+ stdout_set_defaults(&sot);
+ register_task(s, &sot.task);
+ svt->stdout_task_started = true;
++ return 1;
+ }
if (ct->status == CL_SENDING) {
stdin_set_defaults(&sit);
register_task(s, &sit.task);
- t->error = -E_TASK_STARTED;
- return;
+ return -E_TASK_STARTED;
}
- if (ct->status == CL_RECEIVING) {
- stdout_set_defaults(&sot);
- register_task(s, &sot.task);
- return -E_TASK_STARTED;
- }
+ return 0;
}
- static struct task svt = {
- .post_select = supervisor_post_select,
- .status = "supervisor task"
+ static struct supervisor_task supervisor_task = {
+ .task = {
+ .post_select = supervisor_post_select,
+ .status = "supervisor task"
+ }
};
/**
if (ret < 0)
goto out;
sot.btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = "stdout", .parent = ct->btrn));
- register_task(&sched, &svt);
+ EMBRACE(.name = "stdout", .parent = ct->btrn[0]));
+ register_task(&sched, &supervisor_task.task);
ret = schedule(&sched);
if (ret >= 0 && ct->task.error < 0) {
switch(ct->task.error) {
#include "error.h"
#include "list.h"
#include "sched.h"
-#include "client.cmdline.h"
#include "crypt.h"
#include "net.h"
#include "fd.h"
#include "client.h"
#include "buffer_tree.h"
#include "version.h"
+#include "ggo.h"
/** The size of the receiving buffer. */
#define CLIENT_BUFSIZE 4000
/**
- * Close the connection to para_server and deallocate per-command ressources.
+ * Close the connection to para_server and deallocate per-command resources.
*
* \param ct The client task.
*
- * This frees all ressources of the current command but keeps the configuration
+ * This frees all resources of the current command but keeps the configuration
* in \p ct->conf.
*
* \sa \ref client_close().
ct->scc.recv = NULL;
sc_free(ct->scc.send);
ct->scc.send = NULL;
- btr_remove_node(&ct->btrn);
+ btr_remove_node(&ct->btrn[0]);
+ btr_remove_node(&ct->btrn[1]);
}
/**
free(ct->key_file);
client_cmdline_parser_free(&ct->conf);
free(ct->challenge_hash);
- sb_free(ct->sbc);
+ sb_free(ct->sbc[0]);
+ sb_free(ct->sbc[1]);
free(ct);
}
{
int ret;
struct client_task *ct = container_of(t, struct client_task, task);
- struct btr_node *btrn = ct->btrn;
if (ct->scc.fd < 0)
return;
case CL_CONNECTED:
case CL_SENT_AUTH:
case CL_SENT_CH_RESPONSE:
- case CL_SENT_COMMAND:
para_fd_set(ct->scc.fd, &s->rfds, &s->max_fileno);
return;
para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
return;
- case CL_RECEIVING:
- ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
- if (ret != 0) {
+ case CL_SENDING:
+ if (ct->btrn[1]) {
+ ret = btr_node_status(ct->btrn[1], 0, BTR_NT_LEAF);
if (ret < 0)
sched_min_delay(s);
- else
- para_fd_set(ct->scc.fd, &s->rfds,
- &s->max_fileno);
+ else if (ret > 0)
+ para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
}
- return;
- case CL_SENDING:
- ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
- if (ret != 0) {
+ /* fall though */
+ case CL_EXECUTING:
+ if (ct->btrn[0]) {
+ ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
if (ret < 0)
sched_min_delay(s);
- else
- para_fd_set(ct->scc.fd, &s->wfds,
- &s->max_fileno);
+ else if (ret > 0)
+ para_fd_set(ct->scc.fd, &s->rfds, &s->max_fileno);
}
return;
}
}
- static int client_recv_buffer(struct client_task *ct, fd_set *rfds,
- char *buf, size_t sz, size_t *n)
- {
- int ret;
-
- if (ct->status < CL_SENT_CH_RESPONSE)
- return read_nonblock(ct->scc.fd, buf, sz, rfds, n);
-
- *n = 0;
- ret = sc_recv_buffer(&ct->scc, buf, sz);
- /*
- * sc_recv_buffer is used with blocking fds elsewhere, so it
- * does not use the nonblock-API. Therefore we need to
- * check for EOF and EAGAIN.
- */
- if (ret == 0)
- return -E_SERVER_EOF;
- if (ret == -ERRNO_TO_PARA_ERROR(EAGAIN))
- return 0;
- if (ret < 0)
- return ret;
- *n = ret;
- return 0;
- }
-
- static int send_sb(struct client_task *ct, void *buf, size_t numbytes,
+ static int send_sb(struct client_task *ct, int channel, void *buf, size_t numbytes,
enum sb_designator band, bool dont_free)
{
int ret, fd = ct->scc.fd;
struct iovec iov[2];
- if (!ct->sbc) {
+ if (!ct->sbc[channel]) {
struct sb_buffer sbb;
sb_transformation trafo = ct->status < CL_RECEIVED_PROCEED?
NULL : sc_trafo;
sbb = (typeof(sbb))SBB_INIT(band, buf, numbytes);
- ct->sbc = sb_new_send(&sbb, dont_free, trafo, ct->scc.send);
+ ct->sbc[channel] = sb_new_send(&sbb, dont_free, trafo, ct->scc.send);
}
- ret = sb_get_send_buffers(ct->sbc, iov);
+ ret = sb_get_send_buffers(ct->sbc[channel], iov);
ret = xwritev(fd, iov, ret);
if (ret < 0) {
- sb_free(ct->sbc);
- ct->sbc = NULL;
+ sb_free(ct->sbc[channel]);
+ ct->sbc[channel] = NULL;
return ret;
}
- if (sb_sent(ct->sbc, ret)) {
- ct->sbc = NULL;
+ if (sb_sent(ct->sbc[channel], ret)) {
+ ct->sbc[channel] = NULL;
return 1;
}
return 0;
trafo = sc_trafo;
trafo_context = ct->scc.recv;
}
- if (!ct->sbc)
- ct->sbc = sb_new_recv(0, trafo, trafo_context);
+ if (!ct->sbc[0])
+ ct->sbc[0] = sb_new_recv(0, trafo, trafo_context);
again:
- sb_get_recv_buffer(ct->sbc, &iov);
+ sb_get_recv_buffer(ct->sbc[0], &iov);
ret = read_nonblock(ct->scc.fd, iov.iov_base, iov.iov_len, rfds, &n);
if (ret < 0) {
- sb_free(ct->sbc);
- ct->sbc = NULL;
+ sb_free(ct->sbc[0]);
+ ct->sbc[0] = NULL;
return ret;
}
if (n == 0)
return 0;
- if (!sb_received(ct->sbc, n, result))
+ if (!sb_received(ct->sbc[0], n, result))
goto again;
- ct->sbc = NULL;
+ ct->sbc[0] = NULL;
return 1;
}
PARA_DEBUG_LOG("band: %s\n", designator[sbb->band]);
switch (sbb->band) {
+ case SBD_AWAITING_DATA:
+ ct->status = CL_SENDING;
+ ret = 1;
+ goto out;
case SBD_OUTPUT:
if (iov_valid(&sbb->iov))
btr_add_output(sbb->iov.iov_base, sbb->iov.iov_len,
- ct->btrn);
+ ct->btrn[0]);
ret = 1;
goto out;
case SBD_DEBUG_LOG:
char *command, *p;
size_t len = 0;
- if (ct->sbc)
- return send_sb(ct, NULL, 0, 0, false);
+ if (ct->sbc[1])
+ return send_sb(ct, 0, NULL, 0, 0, false);
for (i = 0; i < ct->conf.inputs_num; i++)
len += strlen(ct->conf.inputs[i]) + 1;
p += strlen(ct->conf.inputs[i]) + 1;
}
PARA_DEBUG_LOG("--> %s\n", command);
- return send_sb(ct, command, len, SBD_COMMAND, false);
+ return send_sb(ct, 0, command, len, SBD_COMMAND, false);
}
/**
*
* \sa struct sched, struct task.
*/
-static void client_post_select(struct sched *s, struct task *t)
+static int client_post_select(struct sched *s, struct task *t)
{
struct client_task *ct = container_of(t, struct client_task, task);
- struct btr_node *btrn = ct->btrn;
int ret = 0;
size_t n;
char buf[CLIENT_BUFSIZE];
if (ret < 0)
goto out;
if (ct->scc.fd < 0)
- return;
+ return 0;
switch (ct->status) {
case CL_CONNECTED: /* receive welcome message */
- ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
+ ret = read_nonblock(ct->scc.fd, buf, sizeof(buf), &s->rfds, &n);
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;
+ return 0;
case CL_RECEIVED_WELCOME: /* send auth command */
if (!FD_ISSET(ct->scc.fd, &s->wfds))
- return;
+ return 0;
- if (has_feature("sideband", ct)) {
- ct->use_sideband = true;
- sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
- } else
- sprintf(buf, AUTH_REQUEST_MSG "%s", ct->user);
+ sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
PARA_INFO_LOG("--> %s\n", buf);
ret = write_buffer(ct->scc.fd, buf);
if (ret < 0)
goto out;
ct->status = CL_SENT_AUTH;
- return;
+ return 0;
case CL_SENT_AUTH:
/*
* Receive challenge and session keys, decrypt the challenge and
{
/* decrypted challenge/session key buffer */
unsigned char crypt_buf[1024];
- /* the SHA1 of the decrypted challenge */
+ struct sb_buffer sbb;
- if (ct->use_sideband) {
- struct sb_buffer sbb;
- ret = recv_sb(ct, &s->rfds, &sbb);
- if (ret <= 0)
- goto out;
- if (sbb.band != SBD_CHALLENGE) {
- ret = -E_BAD_BAND;
- free(sbb.iov.iov_base);
- goto out;
- }
- n = sbb.iov.iov_len;
- PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
- ret = priv_decrypt(ct->key_file, crypt_buf,
- sbb.iov.iov_base, n);
+ ret = recv_sb(ct, &s->rfds, &sbb);
+ if (ret <= 0)
+ goto out;
+ if (sbb.band != SBD_CHALLENGE) {
+ ret = -E_BAD_BAND;
free(sbb.iov.iov_base);
- if (ret < 0)
- goto out;
- } else {
- ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
- if (ret < 0 || n == 0)
- goto out;
- PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
- ret = priv_decrypt(ct->key_file, crypt_buf,
- (unsigned char *)buf, n);
- if (ret < 0)
goto out;
}
+ n = sbb.iov.iov_len;
+ PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
+ ret = priv_decrypt(ct->key_file, crypt_buf,
+ sbb.iov.iov_base, n);
+ free(sbb.iov.iov_base);
+ if (ret < 0)
+ goto out;
ct->challenge_hash = para_malloc(HASH_SIZE);
hash_function((char *)crypt_buf, CHALLENGE_SIZE, ct->challenge_hash);
ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
hash_to_asc(ct->challenge_hash, buf);
PARA_INFO_LOG("--> %s\n", buf);
ct->status = CL_RECEIVED_CHALLENGE;
- return;
+ return 0;
}
case CL_RECEIVED_CHALLENGE:
- if (ct->use_sideband) {
- ret = send_sb(ct, ct->challenge_hash, HASH_SIZE,
- SBD_CHALLENGE_RESPONSE, false);
- if (ret != 0)
- ct->challenge_hash = NULL;
- if (ret <= 0)
- goto out;
- } else {
- ret = write_all(ct->scc.fd, (char *)ct->challenge_hash, HASH_SIZE);
- if (ret < 0)
- goto out;
- }
+ ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
+ SBD_CHALLENGE_RESPONSE, false);
+ if (ret != 0)
+ ct->challenge_hash = NULL;
+ if (ret <= 0)
+ goto out;
ct->status = CL_SENT_CH_RESPONSE;
goto out;
case CL_SENT_CH_RESPONSE: /* read server response */
{
- if (ct->use_sideband) {
- struct sb_buffer sbb;
- ret = recv_sb(ct, &s->rfds, &sbb);
- if (ret <= 0)
- goto out;
- free(sbb.iov.iov_base);
- if (sbb.band != SBD_PROCEED)
- ret = -E_BAD_BAND;
- else
- ct->status = CL_RECEIVED_PROCEED;
- goto out;
- }
- ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
- if (ret < 0 || n == 0)
- goto out;
- /* check if server has sent "Proceed" message */
- ret = -E_CLIENT_AUTH;
- if (n < PROCEED_MSG_LEN)
- goto out;
- if (!strstr(buf, PROCEED_MSG))
+ struct sb_buffer sbb;
+ ret = recv_sb(ct, &s->rfds, &sbb);
+ if (ret <= 0)
goto out;
- ct->status = CL_RECEIVED_PROCEED;
- return 0;
+ free(sbb.iov.iov_base);
+ if (sbb.band != SBD_PROCEED)
+ ret = -E_BAD_BAND;
+ else
+ ct->status = CL_RECEIVED_PROCEED;
+ goto out;
}
case CL_RECEIVED_PROCEED: /* concat args and send command */
{
- int i;
- char *command = NULL;
if (!FD_ISSET(ct->scc.fd, &s->wfds))
- return;
+ return 0;
- if (ct->use_sideband) {
- ret = send_sb_command(ct);
- if (ret <= 0)
- goto out;
- ct->status = CL_SENT_COMMAND;
- return 0;
- }
- for (i = 0; i < ct->conf.inputs_num; i++) {
- char *tmp = command;
- command = make_message("%s\n%s", command?
- command : "", ct->conf.inputs[i]);
- free(tmp);
- }
- command = para_strcat(command, EOC_MSG "\n");
- PARA_DEBUG_LOG("--> %s\n", command);
- ret = sc_send_buffer(&ct->scc, command);
- free(command);
- if (ret < 0)
+ ret = send_sb_command(ct);
+ if (ret <= 0)
goto out;
- ct->status = CL_SENT_COMMAND;
+ ct->status = CL_EXECUTING;
- return;
+ return 0;
}
- case CL_SENT_COMMAND:
- {
- char *buf2;
- if (ct->use_sideband) {
- struct sb_buffer sbb;
- ret = recv_sb(ct, &s->rfds, &sbb);
- if (ret <= 0)
- goto out;
- if (sbb.band == SBD_AWAITING_DATA) {
- ct->status = CL_SENDING;
- free(sbb.iov.iov_base);
- goto out;
+ case CL_SENDING:
+ if (ct->btrn[1]) {
+ char *buf2;
+ size_t sz;
+ ret = btr_node_status(ct->btrn[1], 0, BTR_NT_LEAF);
+ if (ret == -E_BTR_EOF) {
+ /* empty blob data packet indicates EOF */
+ PARA_INFO_LOG("blob sent\n");
+ ret = send_sb(ct, 1, NULL, 0, SBD_BLOB_DATA, true);
+ if (ret >= 0)
+ ret = -E_BTR_EOF;
}
- ct->status = CL_RECEIVING;
- ret = dispatch_sbb(ct, &sbb);
- goto out;
- }
- /* can not use "buf" here because we need a malloced buffer */
- buf2 = para_malloc(CLIENT_BUFSIZE);
- ret = client_recv_buffer(ct, &s->rfds, buf2, CLIENT_BUFSIZE, &n);
- if (n > 0) {
- if (strstr(buf2, AWAITING_DATA_MSG)) {
- free(buf2);
- ct->status = CL_SENDING;
- return 0;
+ if (ret < 0)
+ goto close1;
+ if (ret > 0 && FD_ISSET(ct->scc.fd, &s->wfds)) {
+ sz = btr_next_buffer(ct->btrn[1], &buf2);
+ assert(sz);
+ ret = send_sb(ct, 1, buf2, sz, SBD_BLOB_DATA, true);
+ if (ret < 0)
+ goto close1;
+ if (ret > 0)
+ btr_consume(ct->btrn[1], sz);
}
- ct->status = CL_RECEIVING;
- btr_add_output(buf2, n, btrn);
- } else
- free(buf2);
- goto out;
}
- case CL_SENDING:
- {
- char *buf2;
- size_t sz;
- ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
- if (ret < 0)
- goto out;
- if (ret == 0)
- return 0;
- if (!FD_ISSET(ct->scc.fd, &s->wfds))
- return 0;
- sz = btr_next_buffer(btrn, &buf2);
- ret = sc_send_bin_buffer(&ct->scc, buf2, sz);
- if (ret < 0)
- goto out;
- btr_consume(btrn, sz);
- return 0;
- }
- case CL_RECEIVING:
- {
- char *buf2;
- ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
- if (ret < 0)
- goto out;
- if (ret == 0)
- return 0;
- /*
- * The FD_ISSET() is not strictly necessary, but is allows us
- * to skip the malloc below if there is nothing to read anyway.
- */
- if (!FD_ISSET(ct->scc.fd, &s->rfds))
- return 0;
- if (ct->use_sideband) {
- struct sb_buffer sbb;
- ret = recv_sb(ct, &s->rfds, &sbb);
- if (ret > 0)
- ret = dispatch_sbb(ct, &sbb);
- goto out;
+ /* fall though */
+ case CL_EXECUTING:
+ if (ct->btrn[0]) {
+ ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
+ if (ret < 0)
+ goto close0;
+ if (ret > 0 && FD_ISSET(ct->scc.fd, &s->rfds)) {
+ struct sb_buffer sbb;
+ ret = recv_sb(ct, &s->rfds, &sbb);
+ if (ret < 0)
+ goto close0;
+ if (ret > 0) {
+ ret = dispatch_sbb(ct, &sbb);
+ if (ret < 0)
+ goto close0;
+ }
+ }
}
- buf2 = para_malloc(CLIENT_BUFSIZE);
- ret = client_recv_buffer(ct, &s->rfds, buf2, CLIENT_BUFSIZE, &n);
- if (n > 0) {
- buf2 = para_realloc(buf2, n);
- btr_add_output(buf2, n, btrn);
- } else
- free(buf2);
+ ret = 0;
goto out;
- }
}
- return;
+ close1:
+ PARA_INFO_LOG("channel 1: %s\n", para_strerror(-ret));
+ btr_remove_node(&ct->btrn[1]);
+ if (ct->btrn[0])
- return;
++ return 0;
+ goto out;
+ close0:
+ PARA_INFO_LOG("channel 0: %s\n", para_strerror(-ret));
+ btr_remove_node(&ct->btrn[0]);
+ if (ct->btrn[1] && ct->status == CL_SENDING)
++ return 0;
out:
- if (ret < 0) {
- if (!ct->use_sideband && ret != -E_SERVER_EOF &&
- ret != -E_BTR_EOF && ret != -E_EOF)
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
- btr_remove_node(&ct->btrn);
- }
+ if (ret >= 0)
- return;
++ return 0;
+ btr_remove_node(&ct->btrn[0]);
+ btr_remove_node(&ct->btrn[1]);
+ if (ret != -E_SERVER_CMD_SUCCESS && ret != -E_SERVER_CMD_FAILURE)
+ PARA_ERROR_LOG("%s\n", para_strerror(-ret));
- t->error = ret;
+ return ret;
}
/**
if (ret < 0)
goto err_out;
ct->status = CL_CONNECTED;
- ct->btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = "client", .parent = parent, .child = child));
+ ct->btrn[0] = btr_new_node(&(struct btr_node_description)
+ EMBRACE(.name = "client recv", .parent = NULL, .child = child));
+ ct->btrn[1] = btr_new_node(&(struct btr_node_description)
+ EMBRACE(.name = "client send", .parent = parent, .child = NULL));
ct->task.pre_select = client_pre_select;
ct->task.post_select = client_post_select;
ct->task.error = 0;
return ret;
}
+__noreturn static void print_help_and_die(struct client_task *ct)
+{
+ struct ggo_help h = DEFINE_GGO_HELP(client);
+ bool d = ct->conf.detailed_help_given;
+
+ ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
+ exit(0);
+}
+
/**
* Parse a client configuration.
*
ret = -E_CLIENT_SYNTAX;
if (client_cmdline_parser(argc, argv, &ct->conf))
goto out;
- HANDLE_VERSION_FLAG("client", ct->conf);
+ version_handle_flag("client", ct->conf.version_given);
+ if (ct->conf.help_given || ct->conf.detailed_help_given)
+ print_help_and_die(ct);
ct->config_file = ct->conf.config_file_given?
para_strdup(ct->conf.config_file_arg) :
#include <regex.h>
#include <signal.h>
-#include <sys/time.h>
#include <sys/types.h>
#include <osl.h>
localtime_r(&nmmd->mtime, &mtime_tm);
strftime(mtime, 29, "%b %d %Y", &mtime_tm);
}
- gettimeofday(¤t_time, NULL);
+ clock_get_realtime(¤t_time);
/*
* The calls to WRITE_STATUS_ITEM() below never fail because
* b->max_size is zero (unlimited), see para_printf(). However, clang
*/
int send_strerror(struct command_context *cc, int err)
{
- return cc->use_sideband?
- send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s\n", para_strerror(err))
- :
- sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(err));
+ return send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s\n", para_strerror(err));
}
/**
free(msg);
msg = tmp;
}
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
- ret = sc_send_buffer(&cc->scc, msg);
- free(msg);
- return ret;
+ return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
}
ret = check_sender_args(cc->argc, cc->argv, &scd);
if (ret < 0) {
if (scd.sender_num < 0)
return ret;
msg = senders[scd.sender_num].help();
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT,
- false);
- ret = sc_send_buffer(&cc->scc, msg);
- free(msg);
- return ret;
+ return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
}
switch (scd.cmd_num) {
free(info);
}
ut = get_server_uptime_str(now);
- ret = xasprintf(&msg, "version: " GIT_VERSION "\n"
+ ret = xasprintf(&msg,
+ "version: %s\n"
"up: %s\nplayed: %u\n"
"server_pid: %d\n"
"afs_pid: %d\n"
"current loglevel: %s\n"
"supported audio formats: %s\n"
"%s",
+ version_git(),
ut, mmd->num_played,
(int)getppid(),
(int)mmd->afs_pid,
mmd->num_commands,
mmd->num_connects,
conf.loglevel_arg,
- SERVER_AUDIO_FORMATS,
+ AUDIO_FORMAT_HANDLERS,
sender_info
);
mutex_unlock(mmd_mutex);
free(ut);
free(sender_info);
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
- ret = sc_send_bin_buffer(&cc->scc, msg, ret);
- free(msg);
- return ret;
+ return send_sb(&cc->scc, msg, ret, SBD_OUTPUT, false);
}
/* version */
if (cc->argc != 1)
return -E_COMMAND_SYNTAX;
- msg = VERSION_TEXT("server") "built: " BUILD_DATE "\n" UNAME_RS
- ", " CC_VERSION "\n";
- len = strlen(msg);
- return send_sb(&cc->scc, msg, len, SBD_OUTPUT, true);
+ len = xasprintf(&msg, "%s", version_text("server"));
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, len, SBD_OUTPUT, false);
- return sc_send_bin_buffer(&cc->scc, msg, len);
++ return send_sb(&cc->scc, msg, len, SBD_OUTPUT, false);
}
#define EMPTY_STATUS_ITEMS \
*/
static unsigned empty_status_items(int parser_friendly, char **result)
{
- static char *esi;
- static unsigned len;
-
- if (esi)
- goto out;
+ char *esi;
+ unsigned len;
if (parser_friendly)
len = xasprintf(&esi,
EMPTY_STATUS_ITEMS
#undef ITEM
);
-out:
*result = esi;
return len;
}
{
int i, ret;
struct misc_meta_data tmp, *nmmd = &tmp;
- char *s, *esi = NULL;
+ char *s;
int32_t num = 0;
int parser_friendly = 0;
for (;;) {
mmd_dup(nmmd);
ret = get_status(nmmd, parser_friendly, &s);
- if (cc->use_sideband)
- ret = send_sb(&cc->scc, s, ret, SBD_OUTPUT, false);
- else {
- ret = sc_send_bin_buffer(&cc->scc, s, ret);
- free(s);
- }
+ ret = send_sb(&cc->scc, s, ret, SBD_OUTPUT, false);
if (ret < 0)
goto out;
if (nmmd->vss_status_flags & VSS_NEXT) {
+ char *esi;
ret = empty_status_items(parser_friendly, &esi);
- if (cc->use_sideband)
- ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT,
- false);
- else {
- ret = sc_send_bin_buffer(&cc->scc, esi, ret);
- free(esi);
- }
- ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT, true);
++ ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT, false);
if (ret < 0)
goto out;
} else
goto out;
}
out:
- free(esi);
return ret;
}
static int send_list_of_commands(struct command_context *cc, struct server_command *cmd,
const char *handler)
{
- int ret;
char *msg = NULL;
for (; cmd->name; cmd++) {
msg = para_strcat(msg, tmp);
free(tmp);
}
- if (cc->use_sideband)
- return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
- ret = sc_send_buffer(&cc->scc, msg);
- free(msg);
- return ret;
+ return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
}
/* returns string that must be freed by the caller */
);
free(perms);
free(handler);
- if (cc->use_sideband)
- return send_sb(&cc->scc, buf, ret, SBD_OUTPUT, false);
- ret = sc_send_buffer(&cc->scc, buf);
- free(buf);
- return ret;
+ return send_sb(&cc->scc, buf, ret, SBD_OUTPUT, false);
}
/* hup */
return (cmd_ptr->perms & perms) < cmd_ptr->perms ? -E_PERM : 0;
}
- /*
- * Parse first string from *cmd and lookup in table of valid commands.
- * On error, NULL is returned.
- */
- static struct server_command *parse_cmd(const char *cmdstr)
- {
- char buf[255];
- int n = 0;
-
- sscanf(cmdstr, "%200s%n", buf, &n);
- if (!n)
- return NULL;
- buf[n] = '\0';
- return get_cmd_ptr(buf, NULL);
- }
-
- static int read_command(struct stream_cipher_context *scc, char **result)
- {
- int ret;
- char buf[4096];
- char *command = NULL;
-
- for (;;) {
- size_t numbytes;
- char *p;
-
- ret = sc_recv_buffer(scc, buf, sizeof(buf));
- if (ret < 0)
- goto out;
- if (!ret)
- break;
- numbytes = ret;
- ret = -E_COMMAND_SYNTAX;
- if (command && numbytes + strlen(command) > MAX_COMMAND_LEN) /* DOS */
- goto out;
- command = para_strcat(command, buf);
- p = strstr(command, EOC_MSG);
- if (p) {
- *p = '\0';
- break;
- }
- }
- ret = command? 1 : -E_COMMAND_SYNTAX;
- out:
- if (ret < 0)
- free(command);
- else
- *result = command;
- return ret;
-
- }
-
static void reset_signals(void)
{
para_sigaction(SIGCHLD, SIG_IGN);
para_sigaction(SIGHUP, SIG_DFL);
}
- static int parse_auth_request(char *buf, int len, struct user **u,
- bool *use_sideband)
+ static int parse_auth_request(char *buf, int len, struct user **u)
{
int ret;
char *p, *username, **features = NULL;
size_t auth_rq_len = strlen(AUTH_REQUEST_MSG);
+ bool sideband_requested = false;
*u = NULL;
- *use_sideband = false;
if (len < auth_rq_len + 2)
return -E_AUTH_REQUEST;
if (strncmp(buf, AUTH_REQUEST_MSG, auth_rq_len) != 0)
create_argv(p, ",", &features);
for (i = 0; features[i]; i++) {
if (strcmp(features[i], "sideband") == 0)
- *use_sideband = true;
+ sideband_requested = true;
else {
ret = -E_BAD_FEATURE;
goto out;
}
}
}
- PARA_DEBUG_LOG("received auth request for user %s (sideband = %s)\n",
- username, *use_sideband? "true" : "false");
+ if (sideband_requested == false) { /* sideband is mandatory */
+ PARA_ERROR_LOG("client did not request sideband\n");
+ ret = -E_BAD_FEATURE;
+ goto out;
+ }
+ PARA_DEBUG_LOG("received auth request for user %s\n", username);
*u = lookup_user(username);
ret = 1;
out:
char *p, *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
size_t numbytes;
struct command_context cc_struct = {.peer = peername}, *cc = &cc_struct;
+ struct iovec iov;
cc->scc.fd = fd;
reset_signals();
ret = recv_buffer(fd, buf, HANDSHAKE_BUFSIZE);
if (ret < 0)
goto net_err;
- ret = parse_auth_request(buf, ret, &cc->u, &cc->use_sideband);
+ ret = parse_auth_request(buf, ret, &cc->u);
if (ret < 0)
goto net_err;
p = buf + strlen(AUTH_REQUEST_MSG);
}
PARA_DEBUG_LOG("sending %u byte challenge + rc4 keys (%zu bytes)\n",
CHALLENGE_SIZE, numbytes);
- if (cc->use_sideband) {
- struct iovec iov;
- ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
- buf = NULL;
- if (ret < 0)
- goto net_err;
- ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE,
- HANDSHAKE_BUFSIZE, &iov);
- if (ret < 0)
- goto net_err;
- buf = iov.iov_base;
- numbytes = iov.iov_len;
- } else {
- ret = write_all(fd, buf, numbytes);
- if (ret < 0)
- goto net_err;
- /* recv challenge response */
- ret = recv_bin_buffer(fd, buf, HASH_SIZE);
- if (ret < 0)
- goto net_err;
- numbytes = ret;
- }
+ ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
+ buf = NULL;
+ if (ret < 0)
+ goto net_err;
+ ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE,
+ HANDSHAKE_BUFSIZE, &iov);
+ if (ret < 0)
+ goto net_err;
+ buf = iov.iov_base;
+ numbytes = iov.iov_len;
PARA_DEBUG_LOG("received %zu bytes challenge response\n", numbytes);
ret = -E_BAD_USER;
if (!cc->u)
/* init stream cipher keys with the second part of the random buffer */
cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
cc->scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN);
- if (cc->use_sideband)
- ret = send_sb(&cc->scc, NULL, 0, SBD_PROCEED, false);
- else
- ret = sc_send_buffer(&cc->scc, PROCEED_MSG);
+ ret = send_sb(&cc->scc, NULL, 0, SBD_PROCEED, false);
if (ret < 0)
goto net_err;
- if (cc->use_sideband) {
- struct iovec iov;
- ret = recv_sb(&cc->scc, SBD_COMMAND, MAX_COMMAND_LEN, &iov);
- if (ret < 0)
- goto net_err;
- ret = parse_sb_command(cc, &iov);
- if (ret < 0)
- goto err_out;
- cc->argc = ret;
- } else {
- ret = read_command(&cc->scc, &command);
- if (ret == -E_COMMAND_SYNTAX)
- goto err_out;
- if (ret < 0)
- goto net_err;
- ret = -E_BAD_CMD;
- cc->cmd = parse_cmd(command);
- if (!cc->cmd)
- goto err_out;
- /* valid command, check permissions */
- ret = check_perms(cc->u->perms, cc->cmd);
- if (ret < 0)
- goto err_out;
- /* valid command and sufficient perms */
- ret = create_argv(command, "\n", &cc->argv);
- if (ret < 0)
- goto err_out;
- cc->argc = ret;
- }
+ ret = recv_sb(&cc->scc, SBD_COMMAND, MAX_COMMAND_LEN, &iov);
+ if (ret < 0)
+ goto net_err;
+ ret = parse_sb_command(cc, &iov);
+ if (ret < 0)
+ goto err_out;
+ cc->argc = ret;
PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cc->cmd->name,
cc->u->name, peername);
ret = cc->cmd->handler(cc);
if (ret >= 0)
goto out;
err_out:
- if (send_strerror(cc, -ret) >= 0 && cc->use_sideband)
+ if (send_strerror(cc, -ret) >= 0)
send_sb(&cc->scc, NULL, 0, SBD_EXIT__FAILURE, true);
net_err:
PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
mmd->events++;
mmd->active_connections--;
mutex_unlock(mmd_mutex);
- if (ret >= 0 && cc->use_sideband) {
+ if (ret >= 0) {
ret = send_sb(&cc->scc, NULL, 0, SBD_EXIT__SUCCESS, true);
if (ret < 0)
PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
#define STDIN_ERRORS
#define WRITE_ERRORS
#define CHECK_WAV_ERRORS
+#define VERSION_ERRORS
+#define SCHED_ERRORS
extern const char **para_errlist[];
#define OSS_MIX_ERRORS \
PARA_ERROR(OSS_MIXER_CHANNEL, "invalid mixer channel"), \
+
#define ALSA_MIX_ERRORS \
PARA_ERROR(ALSA_MIX_OPEN, "could not open mixer"), \
PARA_ERROR(ALSA_MIX_BAD_ELEM, "invalid/unsupported control element"), \
PARA_ERROR(LIBSAMPLERATE, "secret rabbit code error"), \
+#define OPUS_COMMON_ERRORS \
+ PARA_ERROR(OPUS_HEADER, "invalid opus header"), \
+
+
+#define OPUS_AFH_ERRORS \
+ PARA_ERROR(OPUS_COMMENT, "invalid or corrupted opus comment"), \
+
+
+#define OPUSDEC_FILTER_ERRORS \
+ PARA_ERROR(CREATE_OPUS_DECODER, "could not create opus decoder"), \
+ PARA_ERROR(OPUS_SET_GAIN, "opus: could not set gain"), \
+ PARA_ERROR(OPUS_DECODE, "opus decode error"), \
+
#define SIDEBAND_ERRORS \
PARA_ERROR(BAD_BAND, "invalid or unexpected band designator"), \
PARA_ERROR(SB_PACKET_SIZE, "invalid sideband packet size or protocol error"), \
#define PLAY_ERRORS \
PARA_ERROR(PLAY_SYNTAX, "para_play: syntax error"), \
PARA_ERROR(NO_VALID_FILES, "no valid file found in playlist"), \
- PARA_ERROR(TERM_RQ, "user termination request"), \
PARA_ERROR(BAD_PLAY_CMD, "invalid command"), \
#define COMPRESS_FILTER_ERRORS \
- PARA_ERROR(COMPRESS_SYNTAX, "syntax error in compress filter config"), \
PARA_ERROR(COMPRESS_EOF, "compress: end of file"), \
#define AFH_ERRORS \
PARA_ERROR(AFH_SYNTAX, "afh syntax error"), \
- PARA_ERROR(AFH_SHORT_WRITE, "afh short write"), \
#define AFH_COMMON_ERRORS \
#define AUDIOC_ERRORS \
- PARA_ERROR(AUDIOC_SYNTAX, "audioc syntax error"), \
PARA_ERROR(AUDIOC_EOF, "audioc: end of file"), \
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 SCHED_ERRORS \
- PARA_ERROR(NOT_INITIALIZED, "scheduler not yet initialized"), \
- PARA_ERROR(SCHED_SHUTDOWN, "scheduler was shut down"), \
-
-
#define NET_ERRORS \
PARA_ERROR(NAME_TOO_LONG, "name too long for struct sockaddr_un"), \
PARA_ERROR(ADDRESS_LOOKUP, "can not resolve requested address"),\
#define UDP_RECV_ERRORS \
- PARA_ERROR(UDP_SYNTAX, "udp_recv syntax error"), \
PARA_ERROR(UDP_OVERRUN, "output buffer overrun"), \
PARA_ERROR(UNSUPPORTED_AUDIO_FORMAT, "given audio format not supported"), \
PARA_ERROR(NOT_PLAYING, "not playing"), \
PARA_ERROR(AUDIOD_OFF, "audiod switched off"), \
- PARA_ERROR(STATUS_TIMEOUT, "timeout reading server status"), \
#define AUDIOD_COMMAND_ERRORS \
#define MP3DEC_FILTER_ERRORS \
PARA_ERROR(MAD_FRAME_DECODE, "mad frame decode error"), \
- PARA_ERROR(MP3DEC_SYNTAX, "syntax error in mp3dec config"), \
PARA_ERROR(MP3DEC_EOF, "mp3dec: end of file"), \
PARA_ERROR(MP3DEC_CORRUPT, "too many corrupt frames"), \
#define FILTER_ERRORS \
PARA_ERROR(NO_FILTERS, "at least one filter must be given"), \
- PARA_ERROR(FILTER_SYNTAX, "syntax error"), \
#define STRING_ERRORS \
PARA_ERROR(SEXP_BUILD, "could not build S-expression"), \
PARA_ERROR(SEXP_ENCRYPT, "could not encrypt S-expression"), \
PARA_ERROR(SEXP_DECRYPT, "could not decrypt S-expression"), \
- PARA_ERROR(MD_OPEN, "could not open message digest object"), \
- PARA_ERROR(CIPHER_OPEN, "could not create stream cipher handle"), \
PARA_ERROR(BAD_PRIVATE_KEY, "invalid private key"), \
PARA_ERROR(KEY_MARKER, "invalid/missing key header or footer"), \
PARA_ERROR(ASN1_PARSE, "could not parse ASN.1 key"), \
PARA_ERROR(SENDER_CMD, "command not supported by this sender"), \
PARA_ERROR(SERVER_CRASH, "para_server crashed -- can not live without it"), \
PARA_ERROR(BAD_USER, "auth request for invalid user"), \
- PARA_ERROR(BAD_FEATURE, "request for unknown or invalid feature"), \
+ PARA_ERROR(BAD_FEATURE, "invalid feature request"), \
PARA_ERROR(BAD_AUTH, "authentication failure"), \
PARA_DEBUG_LOG("decrypted buffer before unpad (%d bytes):\n",
key_size);
- dump_buffer("non-unpadded decrypted buffer", oaep_buf, key_size);;
+ dump_buffer("non-unpadded decrypted buffer", oaep_buf, key_size);
ret = unpad_oaep(oaep_buf, key_size, outbuf, nbytes);
if (ret < 0)
goto out_mpi_release;
PARA_DEBUG_LOG("decrypted buffer after unpad (%zu bytes):\n",
*nbytes);
- dump_buffer("unpadded decrypted buffer", outbuf, *nbytes);;
+ dump_buffer("unpadded decrypted buffer", outbuf, *nbytes);
ret = 1;
out_mpi_release:
gcry_mpi_release(out_mpi);
free(sc);
}
- int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t size)
- {
- gcry_error_t gret;
- int ret;
- unsigned char *tmp = para_malloc(size);
-
- assert(size);
- gret = gcry_cipher_encrypt(scc->send->handle, tmp, size,
- (unsigned char *)buf, size);
- assert(gret == 0);
- ret = xwrite(scc->fd, (char *)tmp, size);
- free(tmp);
- return ret;
- }
-
- int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t size)
- {
- gcry_error_t gret;
- ssize_t ret = recv(scc->fd, buf, size, 0);
-
- if (ret < 0)
- ret = -ERRNO_TO_PARA_ERROR(errno);
- if (ret <= 0)
- return ret;
- /* perform in-place encryption */
- gret = gcry_cipher_encrypt(scc->recv->handle, (unsigned char *)buf, ret,
- NULL, 0);
- assert(gret == 0);
- return ret;
- }
-
void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
{
gcry_cipher_hd_t handle = sc->handle;
/** Sent by para_client to initiate the authentication procedure. */
#define AUTH_REQUEST_MSG "auth rsa "
- /** Sent by para_server for commands that expect a data file. */
- #define AWAITING_DATA_MSG "\nAwaiting Data."
- /** Sent by para_server if authentication was successful. */
- #define PROCEED_MSG "Proceed."
- /** Length of the \p PROCEED_MSG string. */
- #define PROCEED_MSG_LEN strlen(PROCEED_MSG)
- /** Sent by para_client to indicate the end of the command line. */
- #define EOC_MSG "\nEnd of Command."
/* exec */
int para_exec_cmdline_pid(pid_t *pid, const char *cmdline, int *fds);
/* time */
-int tv_diff(const struct timeval *b, const struct timeval *a, struct timeval *diff);
-long unsigned tv2ms(const struct timeval*);
-void d2tv(double, struct timeval*);
-void tv_add(const struct timeval*, const struct timeval *, struct timeval *);
-void tv_scale(const unsigned long, const struct timeval *, struct timeval *);
+int tv_diff(const struct timeval *b, const struct timeval *a,
+ struct timeval *diff);
+long unsigned tv2ms(const struct timeval *tv);
+void d2tv(double x, struct timeval *tv);
+void tv_add(const struct timeval *a, const struct timeval *b,
+ struct timeval *sum);
+void tv_scale(const unsigned long mult, const struct timeval *tv,
+ struct timeval *result);
void tv_divide(const unsigned long divisor, const struct timeval *tv,
- struct timeval *result);
+ struct timeval *result);
int tv_convex_combination(const long a, const struct timeval *tv1,
const long b, const struct timeval *tv2,
struct timeval *result);
-void ms2tv(const long unsigned n, struct timeval *tv);
+void ms2tv(long unsigned n, struct timeval *tv);
void compute_chunk_time(long unsigned chunk_num,
struct timeval *chunk_tv, struct timeval *stream_start,
struct timeval *result);
+struct timeval *clock_get_realtime(struct timeval *tv);
/** The enum of all status items. */
enum status_items {STATUS_ITEM_ENUM NUM_STAT_ITEMS};