From: Andre Noll Date: Tue, 1 May 2018 16:17:32 +0000 (+0200) Subject: Merge branch 'refs/heads/t/gui-sigwinch' X-Git-Tag: v0.6.2~9 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=c517cb88ae745c9be06ac5cd99236c4bae8575c9;hp=98dc2e1f173732411953da7300460cc419efd2bb Merge branch 'refs/heads/t/gui-sigwinch' A single patch which removes a long standing issue of para_gui. Cooking for half a year. * refs/heads/t/gui-sigwinch: gui: Catch SIGWINCH. --- diff --git a/Doxyfile b/Doxyfile index d8960dde..b11683e4 100644 --- a/Doxyfile +++ b/Doxyfile @@ -812,7 +812,7 @@ RECURSIVE = NO # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = config.h # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/Makefile.real b/Makefile.real index b60c5698..76487677 100644 --- a/Makefile.real +++ b/Makefile.real @@ -18,7 +18,7 @@ uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS") uname_rs := $(shell uname -rs) cc_version := $(shell $(CC) --version | head -n 1) GIT_VERSION := $(shell ./GIT-VERSION-GEN git-version.h) -COPYRIGHT_YEAR := 2017 +COPYRIGHT_YEAR := 2018 ifeq ("$(origin O)", "command line") build_dir := $(O) diff --git a/NEWS.md b/NEWS.md index d0bd6585..4fd9dcb4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,13 @@ NEWS ==== +------------------------------------------- +0.6.2 (to be accounced) "elastic diversity" +------------------------------------------- + +- para_gui no longer waits up to one second to update the screen when +the geometry of the terminal changes. + ---------------------------------------- 0.6.1 (2017-09-23) "segmented iteration" ---------------------------------------- diff --git a/afh_recv.c b/afh_recv.c index c3e6ddbd..6525209b 100644 --- a/afh_recv.c +++ b/afh_recv.c @@ -68,7 +68,7 @@ static int afh_recv_open(struct receiver_node *rn) struct lls_parse_result *lpr = rn->lpr; struct private_afh_recv_data *pard; struct afh_info *afhi; - const char *fn = RECV_CMD_OPT_STRING_VAL(AFH, FILENAME, lpr); + const char *fn = RECV_CMD_OPT_STRING_VAL(AFH, FILENAME, lpr), *msg; int32_t bc = RECV_CMD_OPT_INT32_VAL(AFH, BEGIN_CHUNK, lpr); const struct lls_opt_result *r_e = RECV_CMD_OPT_RESULT(AFH, END_CHUNK, lpr); int ret; @@ -87,8 +87,10 @@ static int afh_recv_open(struct receiver_node *rn) goto out_unmap; pard->audio_format_num = ret; ret = -ERRNO_TO_PARA_ERROR(EINVAL); + msg = "no data chunks"; if (afhi->chunks_total == 0) goto out_clear_afhi; + msg = "invalid begin chunk"; if (PARA_ABS(bc) >= afhi->chunks_total) goto out_clear_afhi; if (bc >= 0) @@ -100,6 +102,7 @@ static int afh_recv_open(struct receiver_node *rn) if (lls_opt_given(r_e)) { int32_t ec = lls_int32_val(0, r_e); ret = -ERRNO_TO_PARA_ERROR(EINVAL); + msg = "invalid end chunk"; if (PARA_ABS(ec) > afhi->chunks_total) goto out_clear_afhi; if (ec >= 0) @@ -109,12 +112,14 @@ static int afh_recv_open(struct receiver_node *rn) } else pard->last_chunk = afhi->chunks_total - 1; ret = -ERRNO_TO_PARA_ERROR(EINVAL); + msg = "begin chunk >= end chunk!?"; if (pard->first_chunk >= pard->last_chunk) goto out_clear_afhi; pard->current_chunk = pard->first_chunk; return pard->audio_format_num; out_clear_afhi: clear_afhi(afhi); + PARA_ERROR_LOG("%s: %s\n", fn, msg); out_unmap: para_munmap(pard->map, pard->map_size); close(pard->fd); diff --git a/afs.c b/afs.c index a8c504f4..538606ad 100644 --- a/afs.c +++ b/afs.c @@ -22,8 +22,8 @@ #include "string.h" #include "afh.h" #include "afs.h" -#include "server.h" #include "net.h" +#include "server.h" #include "ipc.h" #include "list.h" #include "sched.h" @@ -74,11 +74,6 @@ static struct afs_table afs_tables[NUM_AFS_TABLES] = { struct command_task { /** The file descriptor for the local socket. */ int fd; - /** - * Value sent by the command handlers to identify themselves as - * children of the running para_server. - */ - uint32_t cookie; /** The associated task structure. */ struct task *task; }; @@ -93,15 +88,6 @@ static struct signal_task *signal_task; static enum play_mode current_play_mode; static char *current_mop; /* mode or playlist specifier. NULL means dummy mood */ -/** - * A random number used to "authenticate" the connection. - * - * para_server picks this number by random before it forks the afs process. The - * command handlers know this number as well and write it to the afs socket, - * together with the id of the shared memory area which contains the payload of - * the afs command. A local process has to know this number to abuse the afs - * service provided by the local socket. - */ extern uint32_t afs_socket_cookie; /** @@ -699,8 +685,7 @@ static int open_afs_tables(void) ret = afs_tables[i].open(database_dir); if (ret >= 0) continue; - PARA_ERROR_LOG("%s init: %s\n", afs_tables[i].name, - para_strerror(-ret)); + PARA_ERROR_LOG("could not open %s\n", afs_tables[i].name); break; } if (ret >= 0) @@ -880,7 +865,7 @@ static int execute_server_command(fd_set *rfds) } /* returns 0 if no data available, 1 else */ -static int execute_afs_command(int fd, fd_set *rfds, uint32_t expected_cookie) +static int execute_afs_command(int fd, fd_set *rfds) { uint32_t cookie; int query_shmid; @@ -898,9 +883,9 @@ static int execute_afs_command(int fd, fd_set *rfds, uint32_t expected_cookie) return 1; } cookie = *(uint32_t *)buf; - if (cookie != expected_cookie) { + if (cookie != afs_socket_cookie) { PARA_NOTICE_LOG("received invalid cookie (got %u, expected %u)\n", - (unsigned)cookie, (unsigned)expected_cookie); + (unsigned)cookie, (unsigned)afs_socket_cookie); return 1; } query_shmid = *(int *)(buf + sizeof(cookie)); @@ -938,7 +923,7 @@ static int command_post_select(struct sched *s, void *context) } /* Check the list of connected clients. */ list_for_each_entry_safe(client, tmp, &afs_client_list, node) { - ret = execute_afs_command(client->fd, &s->rfds, ct->cookie); + ret = execute_afs_command(client->fd, &s->rfds); if (ret == 0) { /* prevent bogus connection flooding */ struct timeval diff; tv_diff(now, &client->connect_time, &diff); @@ -969,11 +954,10 @@ static int command_post_select(struct sched *s, void *context) return 0; } -static void register_command_task(uint32_t cookie, struct sched *s) +static void register_command_task(struct sched *s) { struct command_task *ct = &command_task_struct; ct->fd = setup_command_socket_or_die(); - ct->cookie = cookie; ct->task = task_register(&(struct task_info) { .name = "afs command", @@ -986,10 +970,9 @@ static void register_command_task(uint32_t cookie, struct sched *s) /** * Initialize the audio file selector process. * - * \param cookie The value used for "authentication". * \param socket_fd File descriptor used for communication with the server. */ -__noreturn void afs_init(uint32_t cookie, int socket_fd) +__noreturn void afs_init(int socket_fd) { static struct sched s; int i, ret; @@ -1005,10 +988,9 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd) ret = mark_fd_nonblocking(server_socket); if (ret < 0) goto out_close; - PARA_INFO_LOG("server_socket: %d, afs_socket_cookie: %u\n", - server_socket, (unsigned) cookie); + PARA_INFO_LOG("server_socket: %d\n", server_socket); init_admissible_files(OPT_STRING_VAL(AFS_INITIAL_MODE)); - register_command_task(cookie, &s); + register_command_task(&s); s.default_timeout.tv_sec = 0; s.default_timeout.tv_usec = 999 * 1000; ret = write(socket_fd, "\0", 1); diff --git a/afs.h b/afs.h index 544a498d..8beca5ae 100644 --- a/afs.h +++ b/afs.h @@ -161,6 +161,14 @@ struct afs_callback_arg { struct osl_object query; /** Will be written on band SBD_OUTPUT, fully buffered. */ struct para_buffer pbout; + /** + * Convenience pointer for the deserialized parse result. + * + * Most afs command handlers call \ref send_lls_callback_request() to + * serialize the parse result of the subcommand and pass it to the + * callback. In afs context a pointer to the deserialized parse result + * is stored here. + */ struct lls_parse_result *lpr; }; @@ -212,7 +220,7 @@ _static_inline_ int afs_max_size_handler(char *buf, size_t size, void *private) return pass_buffer_as_shm(amshd->fd, amshd->band, buf, size); } -__noreturn void afs_init(uint32_t cookie, int socket_fd); +__noreturn void afs_init(int socket_fd); __must_check int afs_event(enum afs_events event, struct para_buffer *pb, void *data); int send_callback_request(afs_callback *f, struct osl_object *query, diff --git a/aft.c b/aft.c index 44337306..8969e7ac 100644 --- a/aft.c +++ b/aft.c @@ -22,9 +22,30 @@ #include "sideband.h" #include "command.h" -static struct osl_table *audio_file_table; +/* Data about one audio file. Needed for ls and stat output. */ +struct ls_data { + /* Usual audio format handler information. */ + struct afh_info afhi; + /* Audio file selector information. */ + struct afs_info afsi; + /* The full path of the audio file. */ + char *path; + /* The score value (if -a was given). */ + long score; + /* The hash value of the audio file data. */ + unsigned char *hash; +}; + +/* + * The internal state of the audio file table is described by the following + * variables which are private to aft.c. + */ +static struct osl_table *audio_file_table; /* NULL if table not open */ +static struct osl_row *current_aft_row; /* NULL if no audio file open */ + static char *status_items; static char *parser_friendly_status_items; +static struct ls_data status_item_ls_data; /** The different sorting methods of the ls command. */ enum ls_sorting_method { @@ -70,20 +91,6 @@ enum ls_listing_mode { LS_MODE_PARSER, }; -/* Data about one audio file. Needed for ls and stat output. */ -struct ls_data { - /* Usual audio format handler information. */ - struct afh_info afhi; - /* Audio file selector information. */ - struct afs_info afsi; - /* The full path of the audio file. */ - char *path; - /* The score value (if -a was given). */ - long score; - /* The hash value of the audio file data. */ - unsigned char *hash; -}; - /** * The size of the individual output fields of the ls command. * @@ -954,9 +961,6 @@ out: return ret; } -static struct ls_data status_item_ls_data; -static struct osl_row *current_aft_row; - static void make_inode_status_items(struct para_buffer *pb) { struct stat statbuf = {.st_size = 0}; @@ -1590,7 +1594,7 @@ ACTION: Table modifications to be done by the callback. +----+----+---+------+---------------------------------------------------+ | N | N | Y | Y | (new file) create new entry (force has no effect) +----+----+---+------+---------------------------------------------------+ -| N | N | N | Y | (new file) create new entry +| N | N | N | Y | (new file) create new entry +----+----+---+------+---------------------------------------------------+ Notes: @@ -2577,6 +2581,7 @@ static int aft_event_handler(enum afs_events event, struct para_buffer *pb, * every time. */ make_status_items(); + return 0; } default: return 0; } diff --git a/base64.h b/base64.h index 4bfaa99d..ea62d98f 100644 --- a/base64.h +++ b/base64.h @@ -1,3 +1,7 @@ +/* Copyright (C) 2016 Andre Noll , see file COPYING. */ + +/** \file base64.h uudecode/base64 API. */ + int uudecode(char const *src, size_t encoded_size, char **result, size_t *decoded_size); int base64_decode(char const *src, size_t encoded_size, char **result, diff --git a/bash_completion b/bash_completion index 4b1a4be5..88b37dc2 100644 --- a/bash_completion +++ b/bash_completion @@ -6,10 +6,6 @@ _para_complete() local line="$COMP_LINE" OLD_IFS="$IFS" local opts n - if [[ "$COMP_WORDBREAKS" != ' ' ]]; then - COMP_WORDBREAKS=' ' - return 124 # try again with proper value - fi # This extracts short and long options from the help output local script='{ if ($1 ~ "-[a-zA-Z]," && $2 ~ "--[a-zA-Z]") { diff --git a/client.h b/client.h index f8cc5d64..7ba56b91 100644 --- a/client.h +++ b/client.h @@ -36,8 +36,6 @@ struct client_task { unsigned char *challenge_hash; /** The parsed command line (including the command). */ struct lls_parse_result *lpr; - /** The config file for client options. */ - char *config_file; /** The RSA private key. */ char *key_file; /** Paraslash user name. */ diff --git a/client_common.c b/client_common.c index 97d29f8f..a8d48055 100644 --- a/client_common.c +++ b/client_common.c @@ -40,7 +40,6 @@ void client_close(struct client_task *ct) if (!ct) return; free(ct->user); - free(ct->config_file); free(ct->key_file); lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR); free(ct->challenge_hash); @@ -536,7 +535,6 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr, ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx)); if (ret < 0) goto out; - ll = CLIENT_OPT_UINT32_VAL(LOGLEVEL, lpr); version_handle_flag("client", CLIENT_OPT_GIVEN(VERSION, lpr)); handle_help_flag(lpr); @@ -573,6 +571,9 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr, lpr = merged_lpr; } /* success */ + ll = CLIENT_OPT_UINT32_VAL(LOGLEVEL, lpr); + if (loglevel) + *loglevel = ll; user = CLIENT_OPT_GIVEN(USER, lpr)? para_strdup(CLIENT_OPT_STRING_VAL(USER, lpr)) : para_logname(); @@ -593,21 +594,17 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr, ct->scc.fd = -1; ct->lpr = lpr; ct->key_file = kf; - ct->config_file = cf; ct->user = user; *ct_ptr = ct; - if (loglevel) - *loglevel = ll; ret = lls_num_inputs(lpr); out: free(home); + free(cf); if (ret < 0) { if (errctx) PARA_ERROR_LOG("%s\n", errctx); free(errctx); - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); lls_free_parse_result(lpr, cmd); - free(cf); free(kf); *ct_ptr = NULL; } diff --git a/command.c b/command.c index 837c49cf..6568b789 100644 --- a/command.c +++ b/command.c @@ -22,12 +22,12 @@ #include "string.h" #include "afh.h" #include "afs.h" +#include "net.h" #include "server.h" #include "list.h" #include "send.h" #include "sched.h" #include "vss.h" -#include "net.h" #include "daemon.h" #include "fd.h" #include "ipc.h" @@ -872,7 +872,7 @@ static int run_command(struct command_context *cc, struct iovec *iov) * permissions to execute that command, the function calls the corresponding * command handler which does argument checking and further processing. * - * In order to cope with a DOS attacks, a timeout is set up which terminates + * In order to cope with DOS attacks, a timeout is set up which terminates * the function if the connection was not authenticated when the timeout * expires. * diff --git a/configure.ac b/configure.ac index 1a375e9f..499571a7 100644 --- a/configure.ac +++ b/configure.ac @@ -46,20 +46,21 @@ AC_DEFUN([LIB_SUBST_FLAGS], [ AC_SUBST($1_cppflags) AC_SUBST($1_ldflags) ]) +AC_DEFUN([REQUIRE_EXECUTABLE], [ + AC_PATH_PROG(m4_toupper([$1]), [$1]) + test -z "$m4_toupper([$1])" && AC_MSG_ERROR( + [$1 is required to build this package]) +]) AC_USE_SYSTEM_EXTENSIONS AC_C_BIGENDIAN() - -AC_PATH_PROG([BISON], [bison]) -AC_PATH_PROG([FLEX], [flex]) - -AC_PATH_PROG([M4], [m4]) -test -z "$M4" && AC_MSG_ERROR( - [The m4 macro processor is required to build this package]) - AC_PROG_CC AC_PROG_CPP +REQUIRE_EXECUTABLE([bison]) +REQUIRE_EXECUTABLE([flex]) +REQUIRE_EXECUTABLE([m4]) + executables="recv filter audioc write afh play" ########################################################################### osl STASH_FLAGS diff --git a/crypt.c b/crypt.c index 39fcd7ed..b8a587cd 100644 --- a/crypt.c +++ b/crypt.c @@ -38,9 +38,9 @@ void get_random_bytes_or_die(unsigned char *buf, int num) } /* - * Read 64 bytes from /dev/urandom and adds them to the SSL PRNG. Seed the PRNG - * used by random() with a random seed obtained from SSL. If /dev/random is not - * readable the function calls exit(). + * Read 64 bytes from /dev/urandom and add them to the SSL PRNG. Seed the PRNG + * used by random(3) with a random seed obtained from SSL. If /dev/urandom is + * not readable, the function calls exit(). * * \sa RAND_load_file(3), \ref get_random_bytes_or_die(), srandom(3), * random(3), \ref para_random(). @@ -154,8 +154,8 @@ int get_public_key(const char *key_file, struct asymmetric_key **result) goto out; ret = is_ssh_rsa_key(map, map_size); if (!ret) { - para_munmap(map, map_size); - return -E_SSH_PARSE; + ret = -E_SSH_PARSE; + goto out_unmap; } cp = map + ret; encoded_size = map_size - ret; diff --git a/daemon.c b/daemon.c index e47639bc..ddfe680c 100644 --- a/daemon.c +++ b/daemon.c @@ -30,6 +30,7 @@ struct daemon { char *hostname; /** Used for colored log messages. */ char log_colors[NUM_LOGLEVELS][COLOR_MAXLEN]; + char *old_cwd; }; static struct daemon the_daemon, *me = &the_daemon; @@ -117,7 +118,12 @@ void daemon_set_logfile(const char *logfile_name) { free(me->logfile_name); me->logfile_name = NULL; - if (logfile_name) + if (!logfile_name) + return; + if (me->old_cwd && logfile_name[0] != '/') + me->logfile_name = make_message("%s/%s", me->old_cwd, + logfile_name); + else me->logfile_name = para_strdup(logfile_name); } @@ -197,6 +203,7 @@ int daemonize(bool parent_waits) /* become session leader */ if (setsid() < 0) goto err; + me->old_cwd = getcwd(NULL, 0); if (chdir("/") < 0) goto err; null = open("/dev/null", O_RDWR); @@ -234,15 +241,18 @@ void daemon_close_log(void) */ void daemon_open_log_or_die(void) { - daemon_close_log(); + FILE *new_log; + if (!me->logfile_name) return; - me->logfile = fopen(me->logfile_name, "a"); - if (!me->logfile) { + new_log = fopen(me->logfile_name, "a"); + if (!new_log) { PARA_EMERG_LOG("can not open %s: %s\n", me->logfile_name, strerror(errno)); exit(EXIT_FAILURE); } + daemon_close_log(); + me->logfile = new_log; /* equivalent to setlinebuf(), but portable */ setvbuf(me->logfile, NULL, _IOLBF, 0); } diff --git a/dccp_send.c b/dccp_send.c index 6f989541..69ba65f5 100644 --- a/dccp_send.c +++ b/dccp_send.c @@ -21,8 +21,8 @@ #include "error.h" #include "string.h" #include "afh.h" -#include "server.h" #include "net.h" +#include "server.h" #include "list.h" #include "send.h" #include "sched.h" @@ -161,7 +161,8 @@ static void dccp_post_select(fd_set *rfds, __a_unused fd_set *wfds) static int dccp_com_on(__a_unused struct sender_command_data *scd) { - return generic_com_on(dss, IPPROTO_DCCP); + generic_com_on(dss, IPPROTO_DCCP); + return 1; } static int dccp_com_off(__a_unused struct sender_command_data *scd) @@ -224,8 +225,6 @@ static char *dccp_status(void) */ void dccp_send_init(struct sender *s) { - int ret; - s->status = dccp_status; s->send = NULL; s->pre_select = dccp_pre_select; @@ -243,7 +242,5 @@ void dccp_send_init(struct sender *s) init_sender_status(dss, OPT_RESULT(DCCP_ACCESS), OPT_UINT32_VAL(DCCP_PORT), OPT_UINT32_VAL(DCCP_MAX_CLIENTS), OPT_GIVEN(DCCP_DEFAULT_DENY)); - ret = generic_com_on(dss, IPPROTO_DCCP); - if (ret < 0) - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + generic_com_on(dss, IPPROTO_DCCP); } diff --git a/fd.c b/fd.c index 7079b51c..0347fd83 100644 --- a/fd.c +++ b/fd.c @@ -179,15 +179,15 @@ __printf_2_3 int write_va_buffer(int fd, const char *fmt, ...) * \param rfds An optional fd set pointer. * \param num_bytes Result pointer. Contains the number of bytes read from \a fd. * - * If \a rfds is not \p NULL and the (non-blocking) file descriptor \a fd is - * not set in \a rfds, this function returns early without doing anything. - * Otherwise The function tries to read up to \a sz bytes from \a fd, where \a - * sz is the sum of the lengths of all vectors in \a iov. As for xwrite(), - * \p EAGAIN is not considered an error condition. However, \p EOF is. + * If rfds is not NULL and the (non-blocking) file descriptor fd is not set in + * rfds, this function returns early without doing anything. Otherwise it tries + * to read up to sz bytes from fd, where sz is the sum of the lengths of all + * vectors in iov. Like \ref xwrite(), EAGAIN and EINTR are not considered + * error conditions. However, EOF is. * * \return Zero or a negative error code. If the underlying call to readv(2) * returned zero (indicating an end of file condition) or failed for some - * reason other than \p EAGAIN, a negative error code is returned. + * reason other than EAGAIN or EINTR, a negative error code is returned. * * In any case, \a num_bytes contains the number of bytes that have been * successfully read from \a fd (zero if the first readv() call failed with @@ -226,7 +226,7 @@ int readv_nonblock(int fd, struct iovec *iov, int iovcnt, fd_set *rfds, if (ret == 0) return -E_EOF; if (ret < 0) { - if (errno == EAGAIN) + if (errno == EAGAIN || errno == EINTR) return 0; return -ERRNO_TO_PARA_ERROR(errno); } @@ -455,22 +455,20 @@ again: * PROT_EXEC PROT_READ PROT_WRITE. * \param flags Exactly one of MAP_SHARED and MAP_PRIVATE. * \param fd The file to mmap from. - * \param offset Mmap start. * \param map Result pointer. * * \return Standard. * * \sa mmap(2). */ -int para_mmap(size_t length, int prot, int flags, int fd, off_t offset, - void *map) +int para_mmap(size_t length, int prot, int flags, int fd, void *map) { void **m = map; errno = EINVAL; if (!length) goto err; - *m = mmap(NULL, length, prot, flags, fd, offset); + *m = mmap(NULL, length, prot, flags, fd, (off_t)0); if (*m != MAP_FAILED) return 1; err: @@ -639,7 +637,7 @@ int mmap_full_file(const char *path, int open_mode, void **map, if (S_ISDIR(file_status.st_mode)) goto out; - ret = para_mmap(*size, mmap_prot, mmap_flags, fd, 0, map); + ret = para_mmap(*size, mmap_prot, mmap_flags, fd, map); out: if (ret < 0 || !fd_ptr) close(fd); diff --git a/fd.h b/fd.h index 106f5a4c..25eea8a2 100644 --- a/fd.h +++ b/fd.h @@ -12,8 +12,7 @@ __must_check int mark_fd_nonblocking(int fd); __must_check int mark_fd_blocking(int fd); void para_fd_set(int fd, fd_set *fds, int *max_fileno); __must_check int para_fgets(char *line, int size, FILE *f); -int para_mmap(size_t length, int prot, int flags, int fd, off_t offset, - void *map); +int para_mmap(size_t length, int prot, int flags, int fd, void *map); int para_open(const char *path, int flags, mode_t mode); int para_mkdir(const char *path, mode_t mode); int para_chdir(const char *path); diff --git a/gcrypt.c b/gcrypt.c index d5cb49a4..052546dd 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -52,21 +52,22 @@ void get_random_bytes_or_die(unsigned char *buf, int num) } /* - * This is called at the beginning of every program that uses libgcrypt. We - * don't have to initialize any random seed here, but we must initialize the - * gcrypt library. This task is performed by gcry_check_version() which can - * also check that the gcrypt library version is at least the minimal required - * version. + * This is called at the beginning of every program that uses libgcrypt. The + * call to gcry_check_version() initializes the gcrypt library and checks that + * we have at least the minimal required version. */ void init_random_seed_or_die(void) { const char *req_ver = "1.5.0"; + int seed; - if (gcry_check_version(req_ver)) - return; - PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n", - req_ver, gcry_check_version(NULL)); - exit(EXIT_FAILURE); + if (!gcry_check_version(req_ver)) { + PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n", + req_ver, gcry_check_version(NULL)); + exit(EXIT_FAILURE); + } + get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed)); + srandom(seed); } /** S-expression for the public part of an RSA key. */ diff --git a/http_recv.c b/http_recv.c index c581ebdd..3a723299 100644 --- a/http_recv.c +++ b/http_recv.c @@ -106,8 +106,10 @@ static int http_recv_post_select(struct sched *s, void *context) } if (phd->status == HTTP_SENT_GET_REQUEST) { ret = read_pattern(rn->fd, HTTP_OK_MSG, strlen(HTTP_OK_MSG), &s->rfds); - if (ret < 0) + if (ret < 0) { + PARA_ERROR_LOG("did not receive HTTP OK message\n"); goto out; + } if (ret == 0) return 0; PARA_INFO_LOG("received ok msg, streaming\n"); @@ -128,8 +130,10 @@ static int http_recv_post_select(struct sched *s, void *context) btr_add_output_pool(rn->btrp, num_bytes - iov[0].iov_len, btrn); } out: - if (ret < 0) + if (ret < 0) { + PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); btr_remove_node(&rn->btrn); + } return ret; } diff --git a/http_send.c b/http_send.c index dace5c23..210f85ac 100644 --- a/http_send.c +++ b/http_send.c @@ -16,6 +16,7 @@ #include "error.h" #include "string.h" #include "afh.h" +#include "net.h" #include "server.h" #include "http.h" #include "list.h" @@ -23,7 +24,6 @@ #include "sched.h" #include "vss.h" #include "close_on_fork.h" -#include "net.h" #include "fd.h" #include "chunk_queue.h" #include "acl.h" @@ -209,7 +209,8 @@ static void http_pre_select(int *max_fileno, fd_set *rfds, fd_set *wfds) static int http_com_on(__a_unused struct sender_command_data *scd) { - return generic_com_on(hss, IPPROTO_TCP); + generic_com_on(hss, IPPROTO_TCP); + return 1; } static int http_com_off(__a_unused struct sender_command_data *scd) @@ -245,7 +246,6 @@ static char *http_status(void) */ void http_send_init(struct sender *s) { - int ret; s->status = http_status; s->send = http_send; s->pre_select = http_pre_select; @@ -265,7 +265,5 @@ void http_send_init(struct sender *s) OPT_GIVEN(HTTP_DEFAULT_DENY)); if (OPT_GIVEN(HTTP_NO_AUTOSTART)) return; - ret = generic_com_on(hss, IPPROTO_TCP); - if (ret < 0) - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + generic_com_on(hss, IPPROTO_TCP); } diff --git a/m4/lls/mixer.suite.m4 b/m4/lls/mixer.suite.m4 index 37ecbd81..3019f769 100644 --- a/m4/lls/mixer.suite.m4 +++ b/m4/lls/mixer.suite.m4 @@ -170,7 +170,6 @@ caption = List of subcommands arg_info = required_arg arg_type = string typestr = mood_spec - default_val = m/fade [help] This mood (or playlist) is selected right after setting the initial volume. @@ -195,7 +194,6 @@ caption = List of subcommands arg_info = required_arg arg_type = string typestr = mood_spec - default_val = m/sleep [help] Select the given mood or playlist after the fade-out. If unset, playback is stopped until fade-in starts. @@ -217,7 +215,6 @@ caption = List of subcommands arg_info = required_arg arg_type = string typestr = mood_spec - default_val = m/wake [help] This mood or playlist is selected right before fade-in begins. [/help] diff --git a/m4/lls/recv.suite.m4 b/m4/lls/recv.suite.m4 index 793a2f5f..993a4494 100644 --- a/m4/lls/recv.suite.m4 +++ b/m4/lls/recv.suite.m4 @@ -2,7 +2,16 @@ m4_define(PROGRAM, para_recv) [suite recv] version-string = GIT_VERSION() [supercommand para_recv] - purpose = a command line HTTP/DCCP/UDP stream grabber + purpose = receive an audio stream + [description] + para_recv starts one paraslash receiver (http, dccp, udp or afh) + to produce an audio stream in the same way para_audiod would download + the stream from para_server (http, dccp or udp) or para_server makes a + stream out of an audio file (afh). This is mostly useful for debugging. + + Regardless of which receiver was started, the audio stream is written + to stdout. + [/description] m4_include(common-option-section.m4) m4_include(help.m4) m4_include(detailed-help.m4) @@ -19,4 +28,6 @@ version-string = GIT_VERSION() Any options for the selected receiver must be quoted. Example: -r 'http -i www.paraslash.org -p 8009' + + If no receiver is given, http is assumed. [/help] diff --git a/m4/lls/recv_cmd.suite.m4 b/m4/lls/recv_cmd.suite.m4 index 674a4487..de6c5a68 100644 --- a/m4/lls/recv_cmd.suite.m4 +++ b/m4/lls/recv_cmd.suite.m4 @@ -79,7 +79,7 @@ caption = receivers The request is reconciled with the CCIDs on the server through the 'server-priority' mechanism of RFC 4340 6.3.1/10. The server CCIDs - can be listed by calling 'para_client si'. + can be listed by calling 'para_client sender dccp status'. [/help] [subcommand udp] purpose = receive an audio stream over UDP diff --git a/mixer.c b/mixer.c index 00af08a4..52af25f9 100644 --- a/mixer.c +++ b/mixer.c @@ -192,9 +192,6 @@ static void change_afs_mode(const char *afs_mode) { char *cmd; - client_cmd("stop"); - if (!afs_mode) - return; cmd = make_message("select %s", afs_mode); client_cmd(cmd); free(cmd); @@ -290,7 +287,7 @@ static int com_sleep(const struct mixer *m, struct mixer_handle *h) PARA_INFO_LOG("waketime: %d:%02d\n", tm->tm_hour, tm->tm_min); client_cmd("stop"); sleep(1); - if (fot) { + if (fot && fo_mood) { ret = set_initial_volume(m, h); if (ret < 0) return ret; @@ -307,12 +304,13 @@ static int com_sleep(const struct mixer *m, struct mixer_handle *h) if (ret < 0) return ret; } - if (OPT_GIVEN(SLEEP, SLEEP_MOOD)) { + if (sleep_mood) { change_afs_mode(sleep_mood); - client_cmd("play"); - } else + if (!fot || !fo_mood) /* currently stopped */ + client_cmd("play"); + } else if (fot && fo_mood) /* currently playing */ client_cmd("stop"); - if (!fit) + if (!fit || !fi_mood) /* nothing to do */ return 1; change_afs_mode(fi_mood); for (;;) { diff --git a/mood.c b/mood.c index ae8364a2..a63d4d2a 100644 --- a/mood.c +++ b/mood.c @@ -418,10 +418,13 @@ static int load_mood(const struct osl_row *mood_row, struct mood **m, *m = NULL; ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def); - if (ret < 0) + if (ret < 0) { + if (errmsg) + *errmsg = make_message( + "could not read mood definition"); return ret; - if (!*mood_name) - return -E_DUMMY_ROW; + } + assert(*mood_name); mlpd.m = alloc_new_mood(mood_name); ret = for_each_line(FELF_READ_ONLY, mood_def.data, mood_def.size, parse_mood_line, &mlpd); @@ -876,7 +879,9 @@ int change_current_mood(const char *mood_name, char **errmsg) }; ret = osl(osl_get_row(moods_table, BLOBCOL_NAME, &obj, &row)); if (ret < 0) { - PARA_NOTICE_LOG("no such mood: %s\n", mood_name); + if (errmsg) + *errmsg = make_message("no such mood: %s", + mood_name); return ret; } ret = load_mood(row, &m, errmsg); @@ -891,13 +896,20 @@ int change_current_mood(const char *mood_name, char **errmsg) aa.m = current_mood; PARA_NOTICE_LOG("computing statistics of admissible files\n"); ret = audio_file_loop(&aa, add_if_admissible); - if (ret < 0) + if (ret < 0) { + if (errmsg) + *errmsg = make_message("audio file loop failed"); return ret; + } for (i = 0; i < statistics.num; i++) { struct admissible_file_info *a = aa.array + i; ret = add_to_score_table(a->aft_row, a->score); - if (ret < 0) + if (ret < 0) { + if (errmsg) + *errmsg = make_message( + "could not add row to score table"); goto out; + } } log_statistics(); ret = statistics.num; diff --git a/mp.c b/mp.c index 3c84a054..c5702c62 100644 --- a/mp.c +++ b/mp.c @@ -9,7 +9,7 @@ * The public API (at the bottom of the file) allows to parse the same mood * definition many times in an efficient manner. * - * The first function to all is \ref mp_init(), which analyzes the given mood + * The first function to call is \ref mp_init(), which analyzes the given mood * definition syntactically. It returns the abstract syntax tree of the mood * definition and pre-compiles all regular expression patterns to make later * pattern matching efficient. diff --git a/net.c b/net.c index 3f76d21c..1fece043 100644 --- a/net.c +++ b/net.c @@ -425,15 +425,20 @@ int makesock_addrinfo(unsigned l4type, bool passive, struct addrinfo *ai, for (; ai; ai = ai->ai_next) { int fd; ret = socket(ai->ai_family, sock_type(l4type), l4type); - if (ret < 0) + if (ret < 0) { + PARA_NOTICE_LOG("socket(): %s\n", strerror(errno)); continue; + } fd = ret; flowopt_setopts(fd, fo); if (!passive) { - if (connect(fd, ai->ai_addr, ai->ai_addrlen) == 0) - return fd; - close(fd); - continue; + if (connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) { + PARA_NOTICE_LOG("connect(): %s\n", + strerror(errno)); + close(fd); + continue; + } + return fd; } /* * Reuse the address on passive sockets to avoid failure on @@ -442,10 +447,12 @@ int makesock_addrinfo(unsigned l4type, bool passive, struct addrinfo *ai, */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { + PARA_NOTICE_LOG("setsockopt(): %s\n", strerror(errno)); close(fd); continue; } if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) { + PARA_NOTICE_LOG("bind(): %s\n", strerror(errno)); close(fd); continue; } @@ -496,16 +503,15 @@ int makesock(unsigned l4type, bool passive, const char *host, uint16_t port_numb * * \param l4type The transport-layer type (\p IPPROTO_xxx). * \param port The decimal port number to listen on. - * \param fo Flowopts (if any) to set before starting to listen. * * \return Positive integer (socket descriptor) on success, negative value * otherwise. * * \sa \ref makesock(), ip(7), ipv6(7), bind(2), listen(2). */ -int para_listen(unsigned l4type, uint16_t port, struct flowopts *fo) +int para_listen_simple(unsigned l4type, uint16_t port) { - int ret, fd = makesock(l4type, 1, NULL, port, fo); + int ret, fd = makesock(l4type, 1, NULL, port, NULL); if (fd > 0) { ret = listen(fd, BACKLOG); diff --git a/net.h b/net.h index f172131e..143fb812 100644 --- a/net.h +++ b/net.h @@ -48,6 +48,9 @@ #define DCCP_SOCKOPT_TX_CCID 14 /**< Set/get the TX CCID. */ #endif +/** The maximum length of the host component in an URL. */ +#define MAX_HOSTLEN 256 + /** * Flowopts: Transport-layer independent encapsulation of socket options * that need to be registered prior to setting up a connection. @@ -124,12 +127,8 @@ bool sockaddr_equal(const struct sockaddr *sa1, const struct sockaddr *sa2); */ /** How many pending connections queue of a listening server will hold. */ #define BACKLOG 10 -extern int para_listen(unsigned l4type, uint16_t port, struct flowopts *fo); -static inline int para_listen_simple(unsigned l4type, uint16_t port) -{ - return para_listen(l4type, port, NULL); -} +int para_listen_simple(unsigned l4type, uint16_t port); /** Pretty-printing of IPv4/6 socket addresses */ extern char *remote_name(int sockfd); diff --git a/ogg_afh_common.c b/ogg_afh_common.c index 46465de1..62cde3d4 100644 --- a/ogg_afh_common.c +++ b/ogg_afh_common.c @@ -154,7 +154,7 @@ int oac_get_file_info(char *map, size_t numbytes, struct afh_info *afhi, afhi->seconds_total = num_frames / afhi->frequency; /* use roughly one page per chunk */ frames_per_chunk = num_frames / i; - PARA_INFO_LOG("%" PRIu32 "seconds, %d frames/chunk\n", + PARA_INFO_LOG("%" PRIu32 " seconds, %d frames/chunk\n", afhi->seconds_total, frames_per_chunk); ct_size = 250; afhi->chunk_table = para_malloc(ct_size * sizeof(uint32_t)); diff --git a/play.c b/play.c index b304e427..78d53fa8 100644 --- a/play.c +++ b/play.c @@ -139,7 +139,7 @@ static void handle_help_flags(void) if (OPT_GIVEN(DETAILED_HELP)) help = lls_long_help(CMD_PTR); - else if (OPT_GIVEN(HELP)) + else if (OPT_GIVEN(HELP) || lls_num_inputs(play_lpr) == 0) help = lls_short_help(CMD_PTR); else return; @@ -163,7 +163,7 @@ static void parse_config_or_die(int argc, char *argv[]) goto fail; loglevel = OPT_UINT32_VAL(LOGLEVEL); version_handle_flag("play", OPT_GIVEN(VERSION)); - handle_help_flags(); + handle_help_flags(); /* also handles the zero-arg case */ if (OPT_GIVEN(CONFIG_FILE)) cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE)); else { @@ -178,7 +178,7 @@ static void parse_config_or_die(int argc, char *argv[]) if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && OPT_GIVEN(CONFIG_FILE)) goto free_cf; ret = 0; - goto free_cf; + goto setup_keymap; } ret = lls(lls_convert_config(map, sz, NULL, &cf_argv, &errctx)); para_munmap(map, sz); @@ -196,10 +196,7 @@ static void parse_config_or_die(int argc, char *argv[]) lls_free_parse_result(play_lpr, cmd); play_lpr = merged_lpr; loglevel = OPT_UINT32_VAL(LOGLEVEL); - - ret = lls(lls_check_arg_count(play_lpr, 1, INT_MAX, &errctx)); - if (ret < 0) - goto free_cf; +setup_keymap: num_kmas = OPT_GIVEN(KEY_MAP); for (i = 0; i < num_kmas; i++) { const char *kma = lls_string_val(i, OPT_RESULT(KEY_MAP)); diff --git a/resample_filter.c b/resample_filter.c index 8a87b1f3..bbdda51c 100644 --- a/resample_filter.c +++ b/resample_filter.c @@ -155,6 +155,7 @@ static int resample_frames(int16_t *in, size_t num_frames, bool have_more, size_t *result_frames) { int ret, num_samples, out_samples; + float *in_float; int16_t *out; SRC_DATA data; @@ -166,11 +167,12 @@ static int resample_frames(int16_t *in, size_t num_frames, bool have_more, data.output_frames = num_frames * ctx->ratio + 1; out_samples = data.output_frames * ctx->channels; - data.data_in = para_malloc(num_samples * sizeof(float)); - src_short_to_float_array(in, data.data_in, num_samples); + in_float = para_malloc(num_samples * sizeof(float)); + src_short_to_float_array(in, in_float, num_samples); + data.data_in = in_float; data.data_out = para_malloc(out_samples * sizeof(float)); ret = src_process(ctx->src_state, &data); - free(data.data_in); + free(in_float); if (ret != 0) { PARA_ERROR_LOG("%s\n", src_strerror(ret)); free(data.data_out); diff --git a/send.h b/send.h index 9a6e5f74..84f35f92 100644 --- a/send.h +++ b/send.h @@ -186,7 +186,7 @@ void generic_com_allow(struct sender_command_data *scd, struct sender_status *ss); void generic_com_deny(struct sender_command_data *scd, struct sender_status *ss); -int generic_com_on(struct sender_status *ss, unsigned protocol); +void generic_com_on(struct sender_status *ss, unsigned protocol); void generic_com_off(struct sender_status *ss); char *generic_sender_help(void); struct sender_client *accept_sender_client(struct sender_status *ss, fd_set *rfds); diff --git a/send_common.c b/send_common.c index acb7aa6d..16820a53 100644 --- a/send_common.c +++ b/send_common.c @@ -30,34 +30,6 @@ /** Clients will be kicked if there are more than that many bytes pending. */ #define MAX_CQ_BYTES 40000 -/** - * Open a passive socket of given layer4 type. - * - * Set the resulting file descriptor to nonblocking mode and add it to the list - * of fds that are being closed in the child process when the server calls - * fork(). - * - * \param l4type The transport-layer protocol. - * \param port The port number. - * - * \return The listening fd on success, negative on errors. - */ -static int open_sender(unsigned l4type, int port) -{ - int fd, ret = para_listen_simple(l4type, port); - - if (ret < 0) - return ret; - fd = ret; - ret = mark_fd_nonblocking(fd); - if (ret < 0) { - close(fd); - return ret; - } - add_close_on_fork_list(fd); - return fd; -} - /** * Shut down a client connected to a paraslash sender. * @@ -234,21 +206,38 @@ void generic_com_deny(struct sender_command_data *scd, * Activate a paraslash sender. * * \param ss The sender to activate. - * \param protocol The symbolic name of the transport-layer protocol. + * \param protocol layer4 type (IPPROTO_TCP or IPPROTO_DCCP). * - * \return Standard. + * This opens a passive socket of given layer4 type, sets the resulting file + * descriptor to nonblocking mode and adds it to the close on fork list. + * + * Errors are logged but otherwise ignored. */ -int generic_com_on(struct sender_status *ss, unsigned protocol) +void generic_com_on(struct sender_status *ss, unsigned protocol) { - int ret; + int fd, ret; if (ss->listen_fd >= 0) - return 1; - ret = open_sender(protocol, ss->port); - if (ret < 0) - return ret; - ss->listen_fd = ret; - return 1; + return; + ret = para_listen_simple(protocol, ss->port); + if (ret < 0) { + PARA_ERROR_LOG("could not listen on port %d: %s\n", ss->port, + para_strerror(-ret)); + return; + } + fd = ret; + ret = mark_fd_nonblocking(fd); + if (ret < 0) { + PARA_ERROR_LOG("could not set %s socket fd for port %d to " + "nonblocking mode: %s\n", + protocol == IPPROTO_TCP? "TCP" : "DCCP", ss->port, + para_strerror(-ret)); + close(fd); + return; + } + add_close_on_fork_list(fd); + ss->listen_fd = fd; + return; } /** @@ -277,9 +266,8 @@ void generic_com_off(struct sender_status *ss) * \param ss The sender whose listening fd is ready for reading. * \param rfds Passed to para_accept(), * - * This must be called only if the socket fd of \a ss is ready for reading. It - * calls para_accept() to accept the connection and performs the following - * actions on the resulting file descriptor \a fd: + * This calls para_accept() and performs the following actions on the resulting + * file descriptor fd: * * - Checks whether the maximal number of connections are exceeded. * - Sets \a fd to nonblocking mode. diff --git a/server.c b/server.c index 2018b8ee..66c93ab2 100644 --- a/server.c +++ b/server.c @@ -45,6 +45,7 @@ #include "afh.h" #include "string.h" #include "afs.h" +#include "net.h" #include "server.h" #include "list.h" #include "send.h" @@ -52,7 +53,6 @@ #include "vss.h" #include "config.h" #include "close_on_fork.h" -#include "net.h" #include "daemon.h" #include "ipc.h" #include "fd.h" @@ -86,7 +86,15 @@ struct lls_parse_result *server_lpr = NULL; /* Command line options (no config file options). Used in handle_sighup(). */ static struct lls_parse_result *cmdline_lpr; -/** A random value used in child context for authentication. */ +/** + * A random number used to "authenticate" the afs connection. + * + * para_server picks this number by random before it forks the afs process. The + * command handlers know this number as well and write it to the afs socket, + * together with the id of the shared memory area which contains the payload of + * the afs command. A local process has to know this number to abuse the afs + * service provided by the local socket. + */ uint32_t afs_socket_cookie; /** The mutex protecting the shared memory area containing the mmd struct. */ @@ -177,7 +185,6 @@ void parse_config_or_die(bool reload) struct lls_parse_result *cf_lpr, *merged_lpr; char *home = para_homedir(); - daemon_close_log(); if (OPT_GIVEN(CONFIG_FILE)) cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE)); else @@ -454,7 +461,7 @@ static int init_afs(int argc, char **argv) i = argc - lls_num_inputs(cmdline_lpr) - 1; sprintf(argv[i], "para_server (afs)"); close(afs_server_socket[0]); - afs_init(afs_socket_cookie, afs_server_socket[1]); + afs_init(afs_server_socket[1]); } close(afs_server_socket[1]); if (read(afs_server_socket[0], &c, 1) <= 0) { diff --git a/server.h b/server.h index 1852dd50..988a98d8 100644 --- a/server.h +++ b/server.h @@ -5,10 +5,6 @@ /** Size of the selector_info and audio_file info strings of struct misc_meta_data. */ #define MMD_INFO_SIZE 16384 -/** The maximum length of the host component in an URL */ -#define MAX_HOSTLEN 256 - - /** Arguments for the sender command. */ struct sender_command_data { /** Greater than zero indicates that a sender cmd is already queued. */ diff --git a/udp_send.c b/udp_send.c index 49c17631..38d49e3e 100644 --- a/udp_send.c +++ b/udp_send.c @@ -18,13 +18,13 @@ #include "error.h" #include "string.h" #include "afh.h" +#include "net.h" #include "server.h" #include "list.h" #include "send.h" #include "sched.h" #include "vss.h" #include "portable_io.h" -#include "net.h" #include "fd.h" #include "close_on_fork.h" diff --git a/vss.c b/vss.c index 00c632c7..13a8e25f 100644 --- a/vss.c +++ b/vss.c @@ -25,8 +25,8 @@ #include "string.h" #include "afh.h" #include "afs.h" -#include "server.h" #include "net.h" +#include "server.h" #include "list.h" #include "send.h" #include "sched.h" @@ -997,7 +997,7 @@ static void recv_afs_result(struct vss_task *vsst, fd_set *rfds) goto err; } ret = para_mmap(statbuf.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, - passed_fd, 0, &vsst->map); + passed_fd, &vsst->map); if (ret < 0) goto err; vsst->mapsize = statbuf.st_size;