From: Andre Noll Date: Sat, 17 Aug 2013 11:57:32 +0000 (+0200) Subject: Merge branch 't/remove_sb_compat' X-Git-Tag: v0.5.0~10 X-Git-Url: http://git.tuebingen.mpg.de/?a=commitdiff_plain;h=650e5374914c1eb725ce7d2a720611bec22112bc;hp=-c;p=paraslash.git Merge branch 't/remove_sb_compat' This topic branch was cooking for over 4 months and should now be ready for prime time. The patches break compatibility with earlier versions, so we need to bump the version number real soon now. 72ffa7 client: Only start stdin task for addblob commands. 85a6ae Remove old stream cipher API. d1407f Allow addblob commands to create output. 243e31 client: Remove client_recv_buffer(). 277ed4 client: Remove sb-compatibility code. 36ba18 Reject non-sideband connections. 6ca50b blob: Avoid zero sized memcpy(). cf308c Fix typo in documentation of stdin_command(). fdb9d2 blob: Simplify fd2buf(). --- 650e5374914c1eb725ce7d2a720611bec22112bc diff --combined NEWS index 4127e38b,f323df1d..a1cdf58e --- a/NEWS +++ b/NEWS @@@ -1,30 -1,6 +1,36 @@@ ------------------------------------------- -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" diff --combined afs.c index c87fdf78,da92d6c5..49ce13eb --- a/afs.c +++ b/afs.c @@@ -546,31 -546,6 +546,28 @@@ static int activate_mood_or_playlist(ch return 1; } +/** + * 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; - 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); ++ 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 = { @@@ -613,6 -588,28 +610,6 @@@ out 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; @@@ -723,9 -720,9 +720,9 @@@ static void signal_pre_select(struct sc 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"); @@@ -733,20 -730,20 +730,20 @@@ } 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) @@@ -915,7 -912,7 +912,7 @@@ err /** 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; @@@ -923,13 -920,16 +920,13 @@@ 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) { @@@ -950,18 -950,17 +947,18 @@@ 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) @@@ -1068,9 -1067,6 +1065,6 @@@ int com_init(struct command_context *cc } 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; } diff --combined aft.c index a2883d4a,0cc2bd07..adc9a6f2 --- a/aft.c +++ b/aft.c @@@ -280,7 -280,7 +280,7 @@@ static struct osl_table_description aud .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) { /* @@@ -1694,7 -1694,7 +1694,7 @@@ static void com_add_callback(int fd, co 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; @@@ -1876,12 -1876,8 +1876,8 @@@ static int add_one_audio_file(const cha 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. */ @@@ -1901,12 -1897,8 +1897,8 @@@ 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; } /* @@@ -1923,12 -1915,8 +1915,8 @@@ 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; } @@@ -1943,14 -1931,8 +1931,8 @@@ out_unmap 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. */ @@@ -1994,11 -1976,7 +1976,7 @@@ int com_add(struct command_context *cc 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; @@@ -2006,14 -1984,9 +1984,9 @@@ } 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; @@@ -2025,12 -1998,8 +1998,8 @@@ 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; } diff --combined audiod.c index 8f2a72ac,b2d5c8db..611e72d7 --- a/audiod.c +++ b/audiod.c @@@ -343,11 -343,10 +343,11 @@@ static void parse_config_or_die(void 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); @@@ -428,7 -427,7 +428,7 @@@ static void close_filters(struct slot_i 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; @@@ -497,6 -496,7 +497,6 @@@ static void open_filters(struct slot_in 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)); @@@ -992,7 -992,7 +992,7 @@@ static void signal_pre_select(struct sc 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; @@@ -1004,7 -1004,6 +1004,7 @@@ 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) @@@ -1020,7 -1019,7 +1020,7 @@@ static void command_pre_select(struct s 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); @@@ -1037,7 -1036,6 +1037,7 @@@ 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) @@@ -1091,44 -1089,32 +1091,44 @@@ static void set_stat_task_restart_barri 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); } /* @@@ -1137,11 -1123,12 +1137,11 @@@ */ 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); @@@ -1164,13 -1151,10 +1164,13 @@@ 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; @@@ -1193,7 -1177,7 +1193,7 @@@ 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); @@@ -1216,7 -1200,7 +1216,7 @@@ 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) { @@@ -1266,7 -1250,6 +1266,7 @@@ st->last_status_read = *now; out: start_stop_decoders(); + return 0; } static void init_status_task(struct status_task *st) @@@ -1301,17 -1284,18 +1301,17 @@@ static void set_initial_status(void __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); } @@@ -1350,9 -1334,9 +1350,9 @@@ int main(int argc, char *argv[] }; 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(); diff --combined client.c index 2d6ef31f,44862ab9..873edc16 --- a/client.c +++ b/client.c @@@ -54,7 -54,7 +54,7 @@@ static void exec_pre_select(struct sche 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; @@@ -63,8 -63,10 +63,8 @@@ 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; @@@ -74,7 -76,6 +74,7 @@@ et->result_buf[et->result_size - 1] = '\0'; out: btr_consume(btrn, sz); + return 0; } static int make_client_argv(const char *line) @@@ -445,14 -446,16 +445,14 @@@ static int client_i9e_line_handler(cha 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; } @@@ -475,7 -478,7 +475,7 @@@ __noreturn static void interactive_sess .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 { @@@ -528,26 -531,39 +528,37 @@@ __noreturn static void print_completion #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) { + struct supervisor_task *svt = container_of(t, struct supervisor_task, + task); + - if (ct->task.error < 0) { - t->error = ct->task.error; - 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; ++ 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" + } }; /** @@@ -595,8 -611,8 +606,8 @@@ int main(int argc, char *argv[] 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) { diff --combined client_common.c index 1ecba730,3ff43d1b..c19b7121 --- a/client_common.c +++ b/client_common.c @@@ -13,6 -13,7 +13,6 @@@ #include "error.h" #include "list.h" #include "sched.h" -#include "client.cmdline.h" #include "crypt.h" #include "net.h" #include "fd.h" @@@ -22,17 -23,16 +22,17 @@@ #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(). @@@ -49,7 -49,8 +49,8 @@@ void client_disconnect(struct client_ta 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]); } /** @@@ -69,7 -70,8 +70,8 @@@ void client_close(struct client_task *c 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); } @@@ -91,7 -93,6 +93,6 @@@ static void client_pre_select(struct sc { 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; @@@ -99,7 -100,6 +100,6 @@@ 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; @@@ -109,76 -109,49 +109,49 @@@ 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; @@@ -201,21 -174,21 +174,21 @@@ static int recv_sb(struct client_task * 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; } @@@ -251,10 -224,14 +224,14 @@@ static int dispatch_sbb(struct client_t 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: @@@ -299,8 -276,8 +276,8 @@@ static int send_sb_command(struct clien 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; @@@ -310,7 -287,7 +287,7 @@@ 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); } /** @@@ -326,10 -303,9 +303,9 @@@ * * \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]; @@@ -338,29 -314,30 +314,30 @@@ 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 @@@ -369,35 -346,23 +346,23 @@@ { /* 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); @@@ -406,166 -371,104 +371,104 @@@ 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; - } } + 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; ++ 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; } /** @@@ -598,8 -501,10 +501,10 @@@ int client_connect(struct client_task * 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; @@@ -612,15 -517,6 +517,15 @@@ err_out 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. * @@@ -651,9 -547,7 +556,9 @@@ int client_parse_config(int argc, char 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) : diff --combined command.c index 41a58eac,d4955fb6..4bbf494c --- a/command.c +++ b/command.c @@@ -8,6 -8,7 +8,6 @@@ #include #include -#include #include #include @@@ -123,7 -124,7 +123,7 @@@ static unsigned get_status(struct misc_ 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 @@@ -268,10 -269,7 +268,7 @@@ __printf_3_4 int send_sb_va(struct stre */ 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)); } /** @@@ -338,23 -336,14 +335,14 @@@ static int com_sender(struct command_co 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) { @@@ -395,8 -384,7 +383,8 @@@ static int com_si(struct command_contex 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" @@@ -404,7 -392,6 +392,7 @@@ "current loglevel: %s\n" "supported audio formats: %s\n" "%s", + version_git(), ut, mmd->num_played, (int)getppid(), (int)mmd->afs_pid, @@@ -412,17 -399,13 +400,13 @@@ 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 */ @@@ -433,10 -416,10 +417,8 @@@ static int com_version(struct command_c 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 \ @@@ -474,8 -457,11 +456,8 @@@ */ 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, @@@ -495,6 -481,7 +477,6 @@@ EMPTY_STATUS_ITEMS #undef ITEM ); -out: *result = esi; return len; } @@@ -505,7 -492,7 +487,7 @@@ static int com_stat(struct command_cont { int i, ret; struct misc_meta_data tmp, *nmmd = &tmp; - char *s, *esi = NULL; + char *s; int32_t num = 0; int parser_friendly = 0; @@@ -536,24 -523,12 +518,13 @@@ 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 @@@ -567,13 -542,13 +538,12 @@@ 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++) { @@@ -584,11 -559,7 +554,7 @@@ 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 */ @@@ -644,11 -615,7 +610,7 @@@ static int com_help(struct command_cont ); 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 */ @@@ -810,58 -777,6 +772,6 @@@ static int check_perms(unsigned int per 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); @@@ -870,15 -785,14 +780,14 @@@ 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) @@@ -894,15 -808,19 +803,19 @@@ 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: @@@ -979,6 -897,7 +892,7 @@@ __noreturn void handle_connect(int fd, 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(); @@@ -997,7 -916,7 +911,7 @@@ 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); @@@ -1021,28 -940,16 +935,16 @@@ } 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) @@@ -1063,41 -970,16 +965,16 @@@ /* 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); @@@ -1108,7 -990,7 +985,7 @@@ 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)); @@@ -1120,7 -1002,7 +997,7 @@@ out 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)); diff --combined error.h index ef54ef27,844c0045..51ace983 --- a/error.h +++ b/error.h @@@ -34,15 -34,12 +34,15 @@@ DEFINE_ERRLIST_OBJECT_ENUM #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"), \ @@@ -55,19 -52,6 +55,19 @@@ 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"), \ @@@ -76,6 -60,7 +76,6 @@@ #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"), \ @@@ -181,6 -166,7 +181,6 @@@ #define COMPRESS_FILTER_ERRORS \ - PARA_ERROR(COMPRESS_SYNTAX, "syntax error in compress filter config"), \ PARA_ERROR(COMPRESS_EOF, "compress: end of file"), \ @@@ -221,6 -207,7 +221,6 @@@ #define AFH_ERRORS \ PARA_ERROR(AFH_SYNTAX, "afh syntax error"), \ - PARA_ERROR(AFH_SHORT_WRITE, "afh short write"), \ #define AFH_COMMON_ERRORS \ @@@ -290,6 -277,7 +290,6 @@@ #define AUDIOC_ERRORS \ - PARA_ERROR(AUDIOC_SYNTAX, "audioc syntax error"), \ PARA_ERROR(AUDIOC_EOF, "audioc: end of file"), \ @@@ -301,8 -289,14 +301,9 @@@ 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"),\ @@@ -314,6 -308,7 +315,6 @@@ #define UDP_RECV_ERRORS \ - PARA_ERROR(UDP_SYNTAX, "udp_recv syntax error"), \ PARA_ERROR(UDP_OVERRUN, "output buffer overrun"), \ @@@ -337,6 -332,7 +338,6 @@@ 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 \ @@@ -372,12 -368,14 +373,12 @@@ #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 \ @@@ -447,6 -445,8 +448,6 @@@ 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"), \ @@@ -464,7 -464,7 +465,7 @@@ 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"), \ diff --combined gcrypt.c index b4718ec0,a96db362..2736a6c7 --- a/gcrypt.c +++ b/gcrypt.c @@@ -758,13 -758,13 +758,13 @@@ static int decode_rsa(gcry_sexp_t sexp 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); @@@ -937,39 -937,6 +937,6 @@@ void sc_free(struct stream_cipher *sc 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; diff --combined para.h index 4de4af4a,46efebde..6655d356 --- a/para.h +++ b/para.h @@@ -82,37 -82,25 +82,29 @@@ extern __printf_2_3 void (*para_log)(in /** 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};