From: Andre Noll Date: Thu, 1 Dec 2022 17:08:44 +0000 (+0100) Subject: Merge topic branch t/openssl-3 into master X-Git-Tag: v0.7.2~11 X-Git-Url: http://git.tuebingen.mpg.de/?a=commitdiff_plain;h=fca08641935a5bdf6570a14e0b7aeed536745060;hp=a07746d8f55d0655510cad2448ef552288338c69;p=paraslash.git Merge topic branch t/openssl-3 into master Two patches. The first suppresses warnings when compiling against openssl-3, the second switches the two hash functions over to the EVP API. More work is needed but it does not hurt to merge this first step now. * refs/heads/t/openssl-3: openssl: Switch to evp API for sha1 and sha256. openssl: Deactivate openssl-3 warnings for now. --- diff --git a/Doxyfile b/Doxyfile index b11683e4..e147548f 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2019,8 +2019,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = __GNUC__=4 \ - __GNUC_MINOR__=4 +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/NEWS.md b/NEWS.md index 5a00175c..fff7a242 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,23 @@ NEWS ==== +------------------------------------------ +0.7.2 (to be announced) "optical friction" +------------------------------------------ + +- A major cleanup of the audio file selector. +- The client no longer prints error messages from afs commands to + stdout but to stderr. +- The sleep subcommand of para_mixer gained two options to control + the startup mood and the time period before fade-out starts. A bunch + of further improvements for this subcommand went in as well. +- Minor cleanup of the net subsystem. +- The openssl specific code now employs the EVP API to compute hashes. + It should compile without warnings against openssl-3. + +Downloads: +[tarball](./releases/paraslash-git.tar.xz) + -------------------------------------- 0.7.1 (2022-10-03) "digital spindrift" -------------------------------------- @@ -27,6 +44,7 @@ usual mix of bug fixes and minor improvements not mentioned here. requires support from the compiler, the oldest supported gcc version has been bumped to gcc-5.4 (released in 2015). +Downloads: [tarball](./releases/paraslash-0.7.1.tar.xz), [signature](./releases/paraslash-0.7.1.tar.xz.asc) @@ -219,6 +237,23 @@ Downloads: [tarball](./releases/paraslash-0.6.1.tar.xz), [signature](./releases/paraslash-0.6.1.tar.xz.asc) +--------------------------------------- +0.5.9 (2021-11-04) "reversed dimension" +--------------------------------------- +This release contains a few important fixes which have accumulated in +the maint branch. The paraslash-0.5.x series has now reached its end +of life and will no longer be supported. All users should upgrade to +a more recent version at this point. + +- Fix an issue with the bash completion script. +- Initialize the random seed also when using libgrypt. +- Fix some compiler warnings in the resample filter +- Don't return spurious errors from the ff server command. + +Downloads: +[tarball](./releases/paraslash-0.5.9.tar.bz2), +[signature](./releases/paraslash-0.5.9.tar.bz2.asc) + --------------------------------------- 0.5.8 (2017-09-23) "branching parabola" --------------------------------------- diff --git a/afs.c b/afs.c index 3da39f32..b15f8385 100644 --- a/afs.c +++ b/afs.c @@ -30,46 +30,30 @@ #include "sched.h" #include "fd.h" #include "signal.h" -#include "mood.h" #include "sideband.h" #include "command.h" -/** The osl tables used by afs. \sa \ref blob.c. */ -enum afs_table_num { - /** Contains audio file information. See \ref aft.c. */ - TBLNUM_AUDIO_FILES, - /** The table for the paraslash attributes. See \ref attribute.c. */ - TBLNUM_ATTRIBUTES, - /* - * Moods and playlists organize the current set of admissible files in - * an osl table which contains only volatile columns. Each row consists - * of a pointer to an audio file and the score value of this file. - */ - TBLNUM_SCORES, - /** - * A standard blob table containing the mood definitions. For details - * see \ref mood.c. - */ - TBLNUM_MOODS, - /** A blob table containing lyrics on a per-song basis. */ - TBLNUM_LYRICS, - /** Another blob table for images (for example album cover art). */ - TBLNUM_IMAGES, - /** Yet another blob table for storing standard playlists. */ - TBLNUM_PLAYLIST, - /** How many tables are in use? */ - NUM_AFS_TABLES -}; - -static struct afs_table afs_tables[NUM_AFS_TABLES] = { - [TBLNUM_AUDIO_FILES] = {.init = aft_init, .name = "audio_files"}, - [TBLNUM_ATTRIBUTES] = {.init = attribute_init, .name = "attributes"}, - [TBLNUM_SCORES] = {.init = score_init, .name = "scores"}, - [TBLNUM_MOODS] = {.init = moods_init, .name = "moods"}, - [TBLNUM_LYRICS] = {.init = lyrics_init, .name = "lyrics"}, - [TBLNUM_IMAGES] = {.init = images_init, .name = "images"}, - [TBLNUM_PLAYLIST] = {.init = playlists_init, .name = "playlists"}, +/** + * The array of tables of the audio file selector. + * + * We organize them in an array to be able to loop over all tables. + */ +static const struct afs_table { + /** The name is no table operation, so define it here. */ + const char * const name; + /** The only way to invoke the ops is via this pointer. */ + const struct afs_table_operations *ops; +} afs_tables[] = { + {.name = "audio_files", .ops = &aft_ops}, + {.name = "attributes", .ops = &attr_ops}, + {.name = "scores", .ops = &score_ops}, + {.name = "moods", .ops = &moods_ops}, + {.name = "lyrics", .ops = &lyrics_ops}, + {.name = "images", .ops = &images_ops}, + {.name = "playlists", .ops = &playlists_ops}, }; +/** Used to loop over the afs tables. */ +#define NUM_AFS_TABLES ARRAY_SIZE(afs_tables) struct command_task { /** The file descriptor for the local socket. */ @@ -116,7 +100,7 @@ extern uint32_t afs_socket_cookie; */ struct callback_query { /** The function to be called. */ - afs_callback *handler; + afs_callback *cb; /** The number of bytes of the query */ size_t query_size; }; @@ -207,7 +191,7 @@ int send_callback_request(afs_callback *f, struct osl_object *query, if (ret < 0) goto out; cq = query_shm; - cq->handler = f; + cq->cb = f; cq->query_size = query_shm_size - sizeof(*cq); if (query) @@ -447,40 +431,30 @@ no_admissible_files: return write_all(server_socket, buf, 8); } -static int activate_mood_or_playlist(const char *arg, int *num_admissible, - char **errmsg) +static int activate_mood_or_playlist(const char *arg, struct para_buffer *pb) { enum play_mode mode; int ret; + char *msg; if (!arg) { + ret = mood_load(NULL, &msg); + mode = PLAY_MODE_MOOD; + } else if (!strncmp(arg, "p/", 2)) { + ret = playlist_load(arg + 2, &msg); + mode = PLAY_MODE_PLAYLIST; + } else if (!strncmp(arg, "m/", 2)) { + ret = mood_load(arg + 2, &msg); mode = PLAY_MODE_MOOD; - ret = change_current_mood(NULL, errmsg); - if (ret < 0) { - if (num_admissible) - *num_admissible = 0; - return ret; - } } else { - if (!strncmp(arg, "p/", 2)) { - ret = playlist_open(arg + 2); - if (ret < 0 && errmsg) - *errmsg = make_message( "could not open %s", - arg); - mode = PLAY_MODE_PLAYLIST; - } else if (!strncmp(arg, "m/", 2)) { - ret = change_current_mood(arg + 2, errmsg); - mode = PLAY_MODE_MOOD; - } else { - if (errmsg) - *errmsg = make_message("%s: parse error", arg); - return -ERRNO_TO_PARA_ERROR(EINVAL); - } - if (ret < 0) - return ret; + ret = -ERRNO_TO_PARA_ERROR(EINVAL); + msg = make_message("%s: parse error", arg); } - if (num_admissible) - *num_admissible = ret; + if (pb) + para_printf(pb, "%s", msg); + free(msg); + if (ret < 0) + return ret; current_play_mode = mode; /* * We get called with arg == current_mop from the signal dispatcher @@ -490,22 +464,15 @@ static int activate_mood_or_playlist(const char *arg, int *num_admissible, */ if (arg != current_mop) { free(current_mop); - if (arg) { - current_mop = para_strdup(arg); - mutex_lock(mmd_mutex); - strncpy(mmd->afs_mode_string, arg, - sizeof(mmd->afs_mode_string)); - mmd->afs_mode_string[sizeof(mmd->afs_mode_string) - 1] = '\0'; - mmd->events++; - mutex_unlock(mmd_mutex); - } else { - mutex_lock(mmd_mutex); - strcpy(mmd->afs_mode_string, "dummy"); - mmd->events++; - mutex_unlock(mmd_mutex); - current_mop = NULL; - } + current_mop = arg? para_strdup(arg) : NULL; } + /* Notify the server about the mood/playlist change. */ + mutex_lock(mmd_mutex); + strncpy(mmd->afs_mode_string, arg? arg: "dummy", + sizeof(mmd->afs_mode_string)); + mmd->afs_mode_string[sizeof(mmd->afs_mode_string) - 1] = '\0'; + mmd->events++; + mutex_unlock(mmd_mutex); return 1; } @@ -558,77 +525,14 @@ static void flush_and_free_pb(struct para_buffer *pb) free(pb->buf); } -static int com_select_callback(struct afs_callback_arg *aca) -{ - const struct lls_command *cmd = SERVER_CMD_CMD_PTR(SELECT); - const char *arg; - int num_admissible, ret; - char *errmsg; - - ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr); - assert(ret >= 0); - arg = lls_input(0, aca->lpr); - ret = clear_score_table(); - if (ret < 0) { - para_printf(&aca->pbout, "could not clear score table\n"); - goto free_lpr; - } - if (current_play_mode == PLAY_MODE_MOOD) - close_current_mood(); - else - playlist_close(); - ret = activate_mood_or_playlist(arg, &num_admissible, &errmsg); - if (ret >= 0) - goto out; - /* ignore subsequent errors (but log them) */ - para_printf(&aca->pbout, "%s\n", errmsg); - free(errmsg); - para_printf(&aca->pbout, "could not activate %s\n", arg); - if (current_mop && strcmp(current_mop, arg) != 0) { - int ret2; - para_printf(&aca->pbout, "switching back to %s\n", current_mop); - ret2 = activate_mood_or_playlist(current_mop, &num_admissible, - &errmsg); - if (ret2 >= 0) - goto out; - para_printf(&aca->pbout, "%s\n", errmsg); - free(errmsg); - para_printf(&aca->pbout, "could not reactivate %s: %s\n", - current_mop, para_strerror(-ret2)); - } - para_printf(&aca->pbout, "activating dummy mood\n"); - activate_mood_or_playlist(NULL, &num_admissible, NULL); -out: - para_printf(&aca->pbout, "activated %s (%d admissible file%s)\n", - current_mop? current_mop : "dummy mood", num_admissible, - num_admissible == 1? "" : "s"); -free_lpr: - lls_free_parse_result(aca->lpr, cmd); - return ret; -} - -static int com_select(struct command_context *cc, struct lls_parse_result *lpr) -{ - const struct lls_command *cmd = SERVER_CMD_CMD_PTR(SELECT); - char *errctx; - int ret = lls(lls_check_arg_count(lpr, 1, 1, &errctx)); - - if (ret < 0) { - send_errctx(cc, errctx); - return ret; - } - return send_lls_callback_request(com_select_callback, cmd, lpr, cc); -} -EXPORT_SERVER_CMD_HANDLER(select); - static void init_admissible_files(const char *arg) { - int ret = activate_mood_or_playlist(arg, NULL, NULL); + int ret = activate_mood_or_playlist(arg, NULL); if (ret < 0) { PARA_WARNING_LOG("could not activate %s: %s\n", arg, para_strerror(-ret)); if (arg) - activate_mood_or_playlist(NULL, NULL, NULL); + activate_mood_or_playlist(NULL, NULL); } } @@ -656,7 +560,7 @@ static void close_afs_tables(void) int i; PARA_NOTICE_LOG("closing afs tables\n"); for (i = 0; i < NUM_AFS_TABLES; i++) - afs_tables[i].close(); + afs_tables[i].ops->close(); free(database_dir); database_dir = NULL; } @@ -692,10 +596,10 @@ static int open_afs_tables(void) int i, ret; get_database_dir(); - PARA_NOTICE_LOG("opening %d osl tables in %s\n", NUM_AFS_TABLES, + PARA_NOTICE_LOG("opening %zu osl tables in %s\n", NUM_AFS_TABLES, database_dir); for (i = 0; i < NUM_AFS_TABLES; i++) { - ret = afs_tables[i].open(database_dir); + ret = afs_tables[i].ops->open(database_dir); if (ret >= 0) continue; PARA_ERROR_LOG("could not open %s\n", afs_tables[i].name); @@ -704,7 +608,7 @@ static int open_afs_tables(void) if (ret >= 0) return ret; while (i) - afs_tables[--i].close(); + afs_tables[--i].ops->close(); return ret; } @@ -824,6 +728,43 @@ err: return ret; } +/** + * Format and send an error message to the command handler. + * + * To pass an error message from the callback of an afs command to the client, + * this function should be called. It formats the message into a buffer which + * is passed as a shared memory area to the command handler from where it + * propagates to the client. + * + * The message will be tagged with the ERROR_LOG sideband designator so that + * the client writes it to its stderr stream rather than to stdout as with + * aca->pbout. In analogy to the default Unix semantics of stderr, the message + * is sent without buffering. + * + * If sending the error message fails, an error is logged on the server side, + * but no other action is taken. + * + * \param aca Used to obtain the fd to send the shmid to. + * \param fmt Usual format string. + */ +__printf_2_3 void afs_error(const struct afs_callback_arg *aca, + const char *fmt,...) +{ + va_list argp; + char *msg; + unsigned n; + int ret; + + va_start(argp, fmt); + n = xvasprintf(&msg, fmt, argp); + va_end(argp); + ret = pass_buffer_as_shm(aca->fd, SBD_ERROR_LOG, msg, n + 1); + if (ret < 0) + PARA_ERROR_LOG("Could not send %s: %s\n", msg, + para_strerror(-ret)); + free(msg); +} + static int call_callback(int fd, int query_shmid) { void *query_shm; @@ -843,7 +784,7 @@ static int call_callback(int fd, int query_shmid) .fd = fd, .band = SBD_OUTPUT }; - ret = cq->handler(&aca); + ret = cq->cb(&aca); ret2 = shm_detach(query_shm); if (ret2 < 0) { if (ret < 0) /* ignore (but log) detach error */ @@ -996,12 +937,10 @@ static int afs_poll(struct pollfd *fds, nfds_t nfds, int timeout) __noreturn void afs_init(int socket_fd) { static struct sched s; - int i, ret; + int ret; register_signal_task(&s); init_list_head(&afs_client_list); - for (i = 0; i < NUM_AFS_TABLES; i++) - afs_tables[i].init(&afs_tables[i]); ret = open_afs_tables(); if (ret < 0) goto out; @@ -1023,7 +962,7 @@ __noreturn void afs_init(int socket_fd) } ret = schedule(&s); sched_shutdown(&s); - close_current_mood(); + mood_unload(); out_close: close_afs_tables(); out: @@ -1036,6 +975,53 @@ out: exit(EXIT_FAILURE); } +static int com_select_callback(struct afs_callback_arg *aca) +{ + const struct lls_command *cmd = SERVER_CMD_CMD_PTR(SELECT); + const char *arg; + int ret; + + ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr); + assert(ret >= 0); + arg = lls_input(0, aca->lpr); + score_clear(); + if (current_play_mode == PLAY_MODE_MOOD) + mood_unload(); + else + playlist_unload(); + ret = activate_mood_or_playlist(arg, &aca->pbout); + if (ret >= 0) + goto free_lpr; + /* ignore subsequent errors (but log them) */ + if (current_mop && strcmp(current_mop, arg) != 0) { + int ret2; + afs_error(aca, "switching back to %s\n", current_mop); + ret2 = activate_mood_or_playlist(current_mop, &aca->pbout); + if (ret2 >= 0) + goto free_lpr; + afs_error(aca, "could not reactivate %s: %s\n", current_mop, + para_strerror(-ret2)); + } + activate_mood_or_playlist(NULL, &aca->pbout); +free_lpr: + lls_free_parse_result(aca->lpr, cmd); + return ret; +} + +static int com_select(struct command_context *cc, struct lls_parse_result *lpr) +{ + const struct lls_command *cmd = SERVER_CMD_CMD_PTR(SELECT); + char *errctx; + int ret = lls(lls_check_arg_count(lpr, 1, 1, &errctx)); + + if (ret < 0) { + send_errctx(cc, errctx); + return ret; + } + return send_lls_callback_request(com_select_callback, cmd, lpr, cc); +} +EXPORT_SERVER_CMD_HANDLER(select); + static int com_init_callback(struct afs_callback_arg *aca) { uint32_t table_mask = *(uint32_t *)aca->query.data; @@ -1044,16 +1030,15 @@ static int com_init_callback(struct afs_callback_arg *aca) close_afs_tables(); get_database_dir(); for (i = 0; i < NUM_AFS_TABLES; i++) { - struct afs_table *t = &afs_tables[i]; + const struct afs_table *t = afs_tables + i; if (!(table_mask & (1 << i))) continue; - if (!t->create) + if (!t->ops->create) continue; - ret = t->create(database_dir); + ret = t->ops->create(database_dir); if (ret < 0) { - para_printf(&aca->pbout, "cannot create table %s\n", - t->name); + afs_error(aca, "cannot create table %s\n", t->name); goto out; } para_printf(&aca->pbout, "successfully created %s table\n", @@ -1061,7 +1046,7 @@ static int com_init_callback(struct afs_callback_arg *aca) } ret = open_afs_tables(); if (ret < 0) - para_printf(&aca->pbout, "cannot open afs tables: %s\n", + afs_error(aca, "cannot open afs tables: %s\n", para_strerror(-ret)); out: return ret; @@ -1082,7 +1067,7 @@ static int com_init(struct command_context *cc, struct lls_parse_result *lpr) table_mask = 0; for (i = 0; i < num_inputs; i++) { for (j = 0; j < NUM_AFS_TABLES; j++) { - struct afs_table *t = &afs_tables[j]; + const struct afs_table *t = afs_tables + j; if (strcmp(lls_input(i, lpr), t->name)) continue; @@ -1156,10 +1141,10 @@ __must_check int afs_event(enum afs_events event, struct para_buffer *pb, int i, ret; for (i = 0; i < NUM_AFS_TABLES; i++) { - struct afs_table *t = &afs_tables[i]; - if (!t->event_handler) + const struct afs_table *t = afs_tables + i; + if (!t->ops->event_handler) continue; - ret = t->event_handler(event, pb, data); + ret = t->ops->event_handler(event, pb, data); if (ret < 0) { PARA_CRIT_LOG("table %s, event %u: %s\n", t->name, event, para_strerror(-ret)); diff --git a/afs.h b/afs.h index b1606493..9a1d7d9c 100644 --- a/afs.h +++ b/afs.h @@ -73,19 +73,15 @@ struct afsi_change_event_data { struct afs_info *old_afsi; }; -/** Function pointers for table handling. */ -struct afs_table { - /** Initializes the other pointers in this struct. */ - void (*init)(struct afs_table *t); - /** The name of this table. */ - const char *name; - /** Gets called on startup and on \p SIGHUP. */ +/** Methods for table startup/shutdown and event handling. */ +struct afs_table_operations { + /** Gets called on startup and on SIGHUP. */ int (*open)(const char *base_dir); - /** Gets called on shutdown and on \p SIGHUP. */ + /** Gets called on shutdown and on SIGHUP. */ void (*close)(void); - /** Called by the \a init afs command. */ + /** Called from the init command. */ int (*create)(const char *); - /** Handles afs events. */ + /** Handle events generated by other tables. See enum \ref afs_events. */ int (*event_handler)(enum afs_events event, struct para_buffer *pb, void *data); }; @@ -173,6 +169,8 @@ struct afs_callback_arg { }; /** + * The "top half" of an afs command. + * * Afs command handlers run as a process which is not related to the afs * process, i.e. they can not change the address space of afs directly. * Therefore afs commands typically consist of two functions: The command @@ -183,9 +181,13 @@ struct afs_callback_arg { typedef int afs_callback(struct afs_callback_arg *aca); /** + * Dispatch the output of an afs callback. + * * Some AFS callbacks need to send data back to the command handler. Pointers * to this type of function are passed to \ref send_callback_request() and - * related functions to dispatch the data in the command handler process. + * related functions to dispatch the data in the command handler process. Most + * (but not all) afs commands pass \ref afs_cb_result_handler(), which sends + * the output of the callback to the connected client. */ typedef int callback_result_handler(struct osl_object *result, uint8_t band, void *private); int afs_cb_result_handler(struct osl_object *result, uint8_t band, void *private); @@ -229,30 +231,31 @@ int send_callback_request(afs_callback *f, struct osl_object *query, int send_lls_callback_request(afs_callback *f, const struct lls_command * const cmd, struct lls_parse_result *lpr, void *private_result_data); +__printf_2_3 void afs_error(const struct afs_callback_arg *aca, + const char *fmt,...); int string_compare(const struct osl_object *obj1, const struct osl_object *obj2); int for_each_matching_row(struct pattern_match_data *pmd); /* score */ -void score_init(struct afs_table *t); -int admissible_file_loop(void *data, osl_rbtree_loop_func *func); +extern const struct afs_table_operations score_ops; +int score_loop(osl_rbtree_loop_func *func, void *data); int score_get_best(struct osl_row **aft_row, long *score); int get_score_and_aft_row(struct osl_row *score_row, long *score, struct osl_row **aft_row); int score_add(const struct osl_row *row, long score); int score_update(const struct osl_row *aft_row, long new_score); -int get_num_admissible_files(unsigned *num); int score_delete(const struct osl_row *aft_row); -int clear_score_table(void); -int row_belongs_to_score_table(const struct osl_row *aft_row, unsigned *rank); +void score_clear(void); +bool row_belongs_to_score_table(const struct osl_row *aft_row); /* attribute */ -void attribute_init(struct afs_table *t); +extern const struct afs_table_operations attr_ops; void get_attribute_bitmap(const uint64_t *atts, char *buf); /* needed by com_ls() */ int get_attribute_bitnum_by_name(const char *att_name, unsigned char *bitnum); int get_attribute_text(uint64_t *atts, const char *delim, char **text); int attribute_check_callback(struct afs_callback_arg *aca); /* aft */ -void aft_init(struct afs_table *t); +extern const struct afs_table_operations aft_ops; int aft_get_row_of_path(const char *path, struct osl_row **row); int aft_check_attributes(uint64_t att_mask, struct para_buffer *pb); int open_and_update_audio_file(int *fd); @@ -264,9 +267,14 @@ int audio_file_loop(void *private_data, osl_rbtree_loop_func *func); int aft_check_callback(struct afs_callback_arg *aca); void free_status_items(void); +/* mood */ +int mood_load(const char *mood_name, char **msg); +void mood_unload(void); +int mood_check_callback(struct afs_callback_arg *aca); + /* playlist */ -int playlist_open(const char *name); -void playlist_close(void); +int playlist_load(const char *name, char **msg); +void playlist_unload(void); int playlist_check_callback(struct afs_callback_arg *aca); /** evaluates to 1 if x < y, to -1 if x > y and to 0 if x == y */ @@ -275,15 +283,15 @@ int playlist_check_callback(struct afs_callback_arg *aca); /** Define exported functions and a table pointer for an osl blob table. */ #define DECLARE_BLOB_SYMBOLS(table_name, cmd_prefix) \ - void table_name ## _init(struct afs_table *t); \ int cmd_prefix ## _get_name_by_id(uint32_t id, char **name); \ int cmd_prefix ## _get_def_by_id(uint32_t id, struct osl_object *def); \ - int cmd_prefix ## _get_def_by_name(char *name, struct osl_object *def); \ + int cmd_prefix ## _get_def_by_name(const char *name, struct osl_object *def); \ int cmd_prefix ## _get_name_and_def_by_row(const struct osl_row *row, \ char **name, struct osl_object *def); \ int table_name ##_event_handler(enum afs_events event, \ struct para_buffer *pb, void *data); \ - extern struct osl_table *table_name ## _table; + extern struct osl_table *table_name ## _table; \ + extern const struct afs_table_operations table_name ## _ops; /** \cond blob_symbols */ DECLARE_BLOB_SYMBOLS(lyrics, lyr); diff --git a/aft.c b/aft.c index f690e819..0009a54f 100644 --- a/aft.c +++ b/aft.c @@ -1375,7 +1375,7 @@ static int com_ls_callback(struct afs_callback_arg *aca) aca->pbout.flags = (opts->mode == LS_MODE_PARSER)? PBF_SIZE_PREFIX : 0; if (admissible_only(opts)) - ret = admissible_file_loop(opts, prepare_ls_row); + ret = score_loop(prepare_ls_row, opts); else ret = osl(osl_rbtree_loop(audio_file_table, AFTCOL_PATH, opts, prepare_ls_row)); @@ -1761,7 +1761,7 @@ static int com_add_callback(struct afs_callback_arg *aca) ret = afs_event(AUDIO_FILE_ADD, &aca->pbout, aft_row); out: if (ret < 0) - para_printf(&aca->pbout, "could not add %s\n", path); + afs_error(aca, "could not add %s\n", path); lls_free_parse_result(aca->lpr, cmd); return ret; } @@ -1979,12 +1979,12 @@ static int touch_audio_file(__a_unused struct osl_table *table, ret = get_afsi_object_of_row(row, &obj); if (ret < 0) { - para_printf(&aca->pbout, "cannot touch %s\n", name); + afs_error(aca, "cannot touch %s\n", name); return ret; } ret = load_afsi(&old_afsi, &obj); if (ret < 0) { - para_printf(&aca->pbout, "cannot touch %s\n", name); + afs_error(aca, "cannot touch %s\n", name); return ret; } new_afsi = old_afsi; @@ -2038,7 +2038,7 @@ static int com_touch_callback(struct afs_callback_arg *aca) uint32_t id = lls_uint32_val(0, r_i); ret = img_get_name_by_id(id, NULL); if (ret < 0) { - para_printf(&aca->pbout, "invalid image ID: %u\n", id); + afs_error(aca, "invalid image ID: %u\n", id); return ret; } } @@ -2047,7 +2047,7 @@ static int com_touch_callback(struct afs_callback_arg *aca) uint32_t id = lls_uint32_val(0, r_y); ret = lyr_get_name_by_id(id, NULL); if (ret < 0) { - para_printf(&aca->pbout, "invalid lyrics ID: %u\n", id); + afs_error(aca, "invalid lyrics ID: %u\n", id); return ret; } } @@ -2090,7 +2090,7 @@ static int remove_audio_file(__a_unused struct osl_table *table, return ret; ret = osl(osl_del_row(audio_file_table, row)); if (ret < 0) - para_printf(&aca->pbout, "cannot remove %s\n", name); + afs_error(aca, "cannot remove %s\n", name); return ret; } @@ -2326,7 +2326,7 @@ static int com_setatt_callback(struct afs_callback_arg *aca) ret = get_attribute_bitnum_by_name(p, &bitnum); free(p); if (ret < 0) { - para_printf(&aca->pbout, "invalid argument: %s\n", arg); + afs_error(aca, "invalid argument: %s\n", arg); goto out; } if (c == '+') @@ -2648,15 +2648,10 @@ static int aft_event_handler(enum afs_events event, struct para_buffer *pb, } } -/** - * Initialize the audio file table. - * - * \param t Pointer to the structure to be initialized. - */ -void aft_init(struct afs_table *t) -{ - t->open = aft_open; - t->close = aft_close; - t->create = aft_create; - t->event_handler = aft_event_handler; -} +/** The audio file table contains information about known audio files. */ +const struct afs_table_operations aft_ops = { + .open = aft_open, + .close = aft_close, + .create = aft_create, + .event_handler = aft_event_handler, +}; diff --git a/attribute.c b/attribute.c index fb1b3eac..51630b25 100644 --- a/attribute.c +++ b/attribute.c @@ -119,7 +119,7 @@ static int print_attribute(struct osl_table *table, struct osl_row *row, } ret = osl(osl_get_object(table, row, ATTCOL_BITNUM, &bitnum_obj)); if (ret < 0) { - para_printf(&aca->pbout, "%s: %s\n", name, para_strerror(-ret)); + afs_error(aca, "%s: %s\n", name, para_strerror(-ret)); return ret; } para_printf(&aca->pbout, "%u\t%s\n", *(unsigned char*)bitnum_obj.data, @@ -168,11 +168,6 @@ static int com_lsatt(struct command_context *cc, struct lls_parse_result *lpr) } EXPORT_SERVER_CMD_HANDLER(lsatt); -struct addatt_event_data { - const char *name; - unsigned char bitnum; -}; - static int com_addatt_callback(struct afs_callback_arg *aca) { const struct lls_command *cmd = SERVER_CMD_CMD_PTR(ADDATT); @@ -188,12 +183,10 @@ static int com_addatt_callback(struct afs_callback_arg *aca) struct osl_object objs[NUM_ATT_COLUMNS]; struct osl_row *row; unsigned char bitnum; - struct addatt_event_data aed; len = strlen(name); if (len == 0 || name[len - 1] == '-' || name[len - 1] == '+') { - para_printf(&aca->pbout, - "invalid attribute name: %s\n", name); + afs_error(aca, "invalid attribute name: %s\n", name); continue; } ret = get_attribute_bitnum_by_name(name, &bitnum); @@ -225,16 +218,14 @@ static int com_addatt_callback(struct afs_callback_arg *aca) ret = osl(osl_add_row(attribute_table, objs)); if (ret < 0) goto out; - aed.name = name; - aed.bitnum = bitnum; - ret = afs_event(ATTRIBUTE_ADD, &aca->pbout, &aed); + ret = afs_event(ATTRIBUTE_ADD, &aca->pbout, NULL); if (ret < 0) goto out; greatest_att_bitnum = PARA_MAX(greatest_att_bitnum, (int)bitnum); } out: if (ret < 0) - para_printf(&aca->pbout, "error while adding %s\n", + afs_error(aca, "error while adding %s\n", lls_input(i, aca->lpr)); lls_free_parse_result(aca->lpr, cmd); return ret; @@ -277,7 +268,7 @@ static int com_mvatt_callback(struct afs_callback_arg *aca) ret = osl(osl_update_object(attribute_table, row, ATTCOL_NAME, &obj)); out: if (ret < 0) - para_printf(&aca->pbout, "cannot rename %s to %s\n", old, new); + afs_error(aca, "cannot rename %s to %s\n", old, new); else ret = afs_event(ATTRIBUTE_RENAME, &aca->pbout, NULL); lls_free_parse_result(aca->lpr, cmd); @@ -306,13 +297,13 @@ static int remove_attribute(struct osl_table *table, struct osl_row *row, ret = get_attribute_bitnum_by_name(name, &red.bitnum); if (ret < 0) { - para_printf(&aca->pbout, "cannot remove %s\n", name); + afs_error(aca, "cannot remove %s\n", name); return ret; } para_printf(&aca->pbout, "removing attribute %s\n", name); ret = osl(osl_del_row(table, row)); if (ret < 0) { - para_printf(&aca->pbout, "cannot remove %s\n", name); + afs_error(aca, "cannot remove %s\n", name); return ret; } return afs_event(ATTRIBUTE_REMOVE, &aca->pbout, &red); @@ -499,14 +490,9 @@ static int attribute_create(const char *dir) return osl(osl_create_table(&attribute_table_desc)); } -/** - * Initialize the attribute table structure. - * - * \param t The table structure to initialize. - */ -void attribute_init(struct afs_table *t) -{ - t->open = attribute_open; - t->close = attribute_close; - t->create = attribute_create; -} +/** The attribute table stores name/bitnum pairs. */ +const struct afs_table_operations attr_ops = { /* no event handler */ + .open = attribute_open, + .close = attribute_close, + .create = attribute_create, +}; diff --git a/blob.c b/blob.c index b6372401..1802de5d 100644 --- a/blob.c +++ b/blob.c @@ -100,7 +100,7 @@ static int print_blob(struct osl_table *table, struct osl_row *row, } ret = osl(osl_get_object(table, row, BLOBCOL_ID, &obj)); if (ret < 0) { - para_printf(&aca->pbout, "cannot list %s\n", name); + afs_error(aca, "cannot list %s\n", name); return ret; } id = read_u32(obj.data); @@ -210,7 +210,7 @@ static int remove_blob(struct osl_table *table, struct osl_row *row, int ret = osl(osl_del_row(table, row)); if (ret < 0) { - para_printf(&aca->pbout, "cannot remove %s\n", name); + afs_error(aca, "cannot remove %s\n", name); return ret; } return 1; @@ -338,7 +338,7 @@ static int com_addblob_callback(__a_unused const struct lls_command * const cmd, ret = afs_event(BLOB_ADD, NULL, table); out: if (ret < 0) - para_printf(&aca->pbout, "cannot add %s\n", name); + afs_error(aca, "cannot add %s\n", name); else para_printf(&aca->pbout, "added %s as id %u\n", name, id); return ret; @@ -446,15 +446,14 @@ static int com_mvblob_callback(const struct lls_command * const cmd, ret = osl(osl_get_row(table, BLOBCOL_NAME, &obj, &row)); if (ret < 0) { - para_printf(&aca->pbout, "cannot find source blob %s\n", src); + afs_error(aca, "cannot find source blob %s\n", src); goto out; } obj.data = (char *)dest; obj.size = strlen(dest) + 1; ret = osl(osl_update_object(table, row, BLOBCOL_NAME, &obj)); if (ret < 0) { - para_printf(&aca->pbout, "cannot rename blob %s to %s\n", - src, dest); + afs_error(aca, "cannot rename blob %s to %s\n", src, dest); goto out; } ret = afs_event(BLOB_RENAME, NULL, table); @@ -520,11 +519,11 @@ static int blob_get_name_by_id(struct osl_table *table, uint32_t id, return blob_get_name_by_id(table_name ## _table, id, name); \ } -static int blob_get_def_by_name(struct osl_table *table, char *name, +static int blob_get_def_by_name(struct osl_table *table, const char *name, struct osl_object *def) { struct osl_row *row; - struct osl_object obj = {.data = name, .size = strlen(name) + 1}; + struct osl_object obj = {.data = (void *)name, .size = strlen(name) + 1}; int ret; def->data = NULL; @@ -538,7 +537,7 @@ static int blob_get_def_by_name(struct osl_table *table, char *name, /** Define the \p get_def_by_id function for this blob type. */ #define DEFINE_GET_DEF_BY_NAME(table_name, cmd_prefix) \ - int cmd_prefix ## _get_def_by_name(char *name, struct osl_object *def) \ + int cmd_prefix ## _get_def_by_name(const char *name, struct osl_object *def) \ { \ return blob_get_def_by_name(table_name ## _table, name, def); \ } @@ -625,25 +624,21 @@ static int blob_open(struct osl_table **table, &table_name ## _table_desc, dir); \ } - -/** Define the \p init function for this blob type. */ -#define DEFINE_BLOB_INIT(table_name) \ - void table_name ## _init(struct afs_table *t) \ - { \ - t->open = table_name ## _open; \ - t->close = table_name ## _close; \ - t->create = table_name ## _create;\ - t->event_handler = table_name ##_event_handler; \ - table_name ## _table = NULL; \ - } - +/** Blob tables map integers to blobs. */ +#define DEFINE_BLOB_AFS_TABLE_OPS(table_name) \ + const struct afs_table_operations table_name ## _ops = { \ + .open = table_name ## _open, \ + .close = table_name ## _close, \ + .create = table_name ## _create, \ + .event_handler = table_name ##_event_handler, \ + }; /** Define all functions for this blob type. */ #define DEFINE_BLOB_FUNCTIONS(table_name, short_name, c_short_name) \ DEFINE_BLOB_OPEN(table_name) \ DEFINE_BLOB_CLOSE(table_name) \ DEFINE_BLOB_CREATE(table_name) \ - DEFINE_BLOB_INIT(table_name) \ + DEFINE_BLOB_AFS_TABLE_OPS(table_name) \ DEFINE_BLOB_COMMAND(ls, LS, table_name, short_name, c_short_name) \ DEFINE_BLOB_COMMAND(cat, CAT, table_name, short_name, c_short_name) \ DEFINE_BLOB_COMMAND(add, ADD, table_name, short_name, c_short_name) \ diff --git a/client_common.c b/client_common.c index 64f6c676..95e59fd2 100644 --- a/client_common.c +++ b/client_common.c @@ -490,7 +490,7 @@ int client_connect(struct client_task *ct, struct sched *s, PARA_NOTICE_LOG("connecting %s:%u\n", host, port); ct->scc.fd = -1; - ret = para_connect_simple(IPPROTO_TCP, host, port); + ret = para_connect(IPPROTO_TCP, host, port); if (ret < 0) return ret; ct->scc.fd = ret; diff --git a/command.c b/command.c index 00d2c5a6..c56a1582 100644 --- a/command.c +++ b/command.c @@ -47,12 +47,14 @@ extern struct misc_meta_data *mmd; int send_afs_status(struct command_context *cc, int parser_friendly); static bool subcmd_should_die; +/* + * Don't call PARA_XXX_LOG() here as we might already hold the log mutex. See + * generic_signal_handler() for details. + */ static void command_handler_sighandler(int s) { - if (s != SIGTERM) - return; - PARA_EMERG_LOG("terminating on signal %d\n", SIGTERM); - subcmd_should_die = true; + if (s == SIGTERM) + subcmd_should_die = true; } /* @@ -505,6 +507,7 @@ static int com_stat(struct command_context *cc, struct lls_parse_result *lpr) * while we sleep. */ para_block_signal(SIGTERM); + para_block_signal(SIGUSR1); for (;;) { sigset_t set; /* @@ -536,8 +539,10 @@ static int com_stat(struct command_context *cc, struct lls_parse_result *lpr) * open a race window similar to the one described above. */ pselect(1, NULL, NULL, NULL, &ts, &set); - if (subcmd_should_die) + if (subcmd_should_die) { + PARA_EMERG_LOG("terminating on SIGTERM\n"); goto out; + } ret = -E_SERVER_CRASH; if (getppid() == 1) goto out; diff --git a/dccp_recv.c b/dccp_recv.c index fe2f7abf..0b20bcc8 100644 --- a/dccp_recv.c +++ b/dccp_recv.c @@ -27,6 +27,10 @@ #include "net.h" #include "fd.h" +#ifndef DCCP_SOCKOPT_CCID +#define DCCP_SOCKOPT_CCID 13 /**< Sets both TX/RX CCID. */ +#endif + static void dccp_recv_close(struct receiver_node *rn) { if (rn->fd > 0) @@ -59,6 +63,9 @@ static int dccp_recv_ccid_support_check(const struct lls_parse_result *lpr) return 1; } +/** Flowopt shortcut */ +#define OPT_ADD(fo, lev, opt, val, len) flowopt_add(fo, lev, opt, #opt, val, len) + static int dccp_recv_open(struct receiver_node *rn) { struct lls_parse_result *lpr = rn->lpr; @@ -83,7 +90,7 @@ static int dccp_recv_open(struct receiver_node *rn) OPT_ADD(fo, SOL_DCCP, DCCP_SOCKOPT_CCID, ccids, i); } - fd = makesock(IPPROTO_DCCP, 0, host, port, fo); + fd = makesock(IPPROTO_DCCP, false, host, port, fo); flowopt_cleanup(fo); free(ccids); if (fd < 0) diff --git a/dccp_send.c b/dccp_send.c index 15a361ba..6182c964 100644 --- a/dccp_send.c +++ b/dccp_send.c @@ -45,6 +45,10 @@ static void dccp_pre_monitor(struct sched *s) sched_monitor_readfd(dss->listen_fds[n], s); } +#ifndef DCCP_SOCKOPT_TX_CCID +#define DCCP_SOCKOPT_TX_CCID 14 /**< Set/get the TX CCID. */ +#endif + /** * Query the TX CCID used on the sender-client half connection. * \param sockfd Server socket descriptor to query (after accept(2)). @@ -89,6 +93,13 @@ static void dccp_shutdown(void) free_sender_status(dss); } +#ifndef DCCP_SOCKOPT_GET_CUR_MPS +#define DCCP_SOCKOPT_GET_CUR_MPS 5 /**< Max packet size, RFC 4340, 14. */ +#endif + +/** Estimated worst-case length of a DCCP header including options. */ +#define DCCP_MAX_HEADER 128 + /** * Obtain current MPS according to RFC 4340, sec. 14. */ static int dccp_init_fec(struct sender_client *sc) { diff --git a/error.h b/error.h index 82920ea8..7c146da2 100644 --- a/error.h +++ b/error.h @@ -2,6 +2,7 @@ /** \file error.h List of error codes and messages. */ +/** \cond para_error */ /** Codes and messages. */ #define PARA_ERRORS \ PARA_ERROR(SUCCESS, "success"), \ @@ -148,7 +149,6 @@ PARA_ERROR(NO_AUDIO_FILE, "no audio file"), \ PARA_ERROR(NOFD, "did not receive open fd from afs"), \ PARA_ERROR(NO_MATCH, "no matches"), \ - PARA_ERROR(NO_MOOD, "no mood available"), \ PARA_ERROR(NO_MORE_SLOTS, "no more empty slots"), \ PARA_ERROR(NOT_PLAYING, "not playing"), \ PARA_ERROR(NO_VALID_FILES, "no valid file found in playlist"), \ @@ -169,7 +169,6 @@ PARA_ERROR(OPUS_SET_GAIN, "opus: could not set gain"), \ PARA_ERROR(PATH_FOUND, ""), /* not really an error */ \ PARA_ERROR(PLAYLIST_EMPTY, "attempted to load empty playlist"), \ - PARA_ERROR(PLAYLIST_LOADED, ""), /* not really an error */ \ PARA_ERROR(PREBUFFER_SUCCESS, "prebuffering complete"), \ PARA_ERROR(PRIVATE_KEY, "can not read private key"), \ PARA_ERROR(QUEUE, "packet queue overrun"), \ @@ -261,6 +260,7 @@ enum para_error_codes {PARA_ERRORS}; extern const char * const para_errlist[]; /** Exactly one .c file per executable must define the array. */ #define DEFINE_PARA_ERRLIST const char * const para_errlist[] = {PARA_ERRORS} +/** \endcond para_error */ /** * This bit indicates whether a number is considered a system error number diff --git a/http_recv.c b/http_recv.c index 5aafacb8..32c9e7b9 100644 --- a/http_recv.c +++ b/http_recv.c @@ -150,7 +150,7 @@ static int http_recv_open(struct receiver_node *rn) struct lls_parse_result *lpr = rn->lpr; const char *r_i = RECV_CMD_OPT_STRING_VAL(HTTP, HOST, lpr); uint32_t r_p = RECV_CMD_OPT_UINT32_VAL(HTTP, PORT, lpr); - int fd, ret = para_connect_simple(IPPROTO_TCP, r_i, r_p); + int fd, ret = para_connect(IPPROTO_TCP, r_i, r_p); if (ret < 0) return ret; diff --git a/m4/lls/mixer.suite.m4 b/m4/lls/mixer.suite.m4 index 3019f769..e366a201 100644 --- a/m4/lls/mixer.suite.m4 +++ b/m4/lls/mixer.suite.m4 @@ -147,11 +147,10 @@ caption = List of subcommands [subcommand sleep] purpose = stream, fade out, sleep, fade in [description] - Change to the initial volume and select the initial mood/playlist. - Fade out to the given fade-out volume in the specified time. Switch - to the sleep mood/playlist and wait until wake time minus fade-in - time. Finally, switch to the wake mood/playlist and fade in to the - fade-in volume. + Set the initial volume and mood, start playing and sleep. Then switch + to the fade-out mood and fade to the fade-out volume. Next, switch to + the sleep mood and wait until wake time minus fade-in time. Finally, + switch to the wake mood and fade in to the fade-in volume. [/description] [option ivol] summary = set initial volume @@ -165,6 +164,26 @@ caption = List of subcommands channel part may be omitted, in which case the default channel is used. This option may be given multiple times. [/help] + [option initial-mood] + summary = mood or playlist to start with + arg_info = required_arg + arg_type = string + typestr = mood_spec + [help] + This mood or playlist is selected right after setting the initial + volume and before fade-out starts. If unset, fade-out starts + immediately. + [/help] + [option initial-delay] + summary = time before fade-out starts. + arg_info = required_arg + arg_type = uint32 + typestr = seconds + default_val = 0 + [help] + If left at the default, no initial delay occurs even if an initial + mood is given. + [/help] [option fo-mood] summary = mood or playlist for fade-out arg_info = required_arg diff --git a/mixer.c b/mixer.c index eae89291..dda7fc1d 100644 --- a/mixer.c +++ b/mixer.c @@ -187,11 +187,11 @@ static int com_fade(const struct mixer *m) } EXPORT_CMD(fade); -static void client_cmd(const char *cmd) +static void run(const char *exe, const char *cmd) { int ret, status, fds[3] = {0, 0, 0}; pid_t pid; - char *cmdline = make_message(BINDIR "/para_client %s", cmd); + char *cmdline = make_message("%s %s", exe, cmd); PARA_NOTICE_LOG("%s\n", cmdline); ret = para_exec_cmdline_pid(&pid, cmdline, fds); @@ -215,6 +215,16 @@ fail: exit(EXIT_FAILURE); } +static void client_cmd(const char *cmd) +{ + run(BINDIR "/para_client", cmd); +} + +static void audioc_cmd(const char *cmd) +{ + run(BINDIR "/para_audioc", cmd); +} + static void change_afs_mode(const char *afs_mode) { char *cmd; @@ -263,6 +273,20 @@ static int set_initial_volume(const struct mixer *m, struct mixer_handle *h) return 1; } +static void stop(const struct mixer *m, struct mixer_handle *h) +{ + int ret, old_vol = 0; + + ret = m->get(h); + if (ret > 0) + old_vol = ret; + fade(m, h, 0, 3); + audioc_cmd("off"); + client_cmd("stop"); + audioc_cmd("on"); + m->set(h, old_vol); +} + static int com_sleep(const struct mixer *m) { time_t t1, wake_time_epoch; @@ -270,6 +294,7 @@ static int com_sleep(const struct mixer *m) struct tm *tm; int ret; const char *wake_time = OPT_STRING_VAL(SLEEP, WAKE_TIME); + const char *initial_mood = OPT_STRING_VAL(SLEEP, INITIAL_MOOD); const char *fo_mood = OPT_STRING_VAL(SLEEP, FO_MOOD); const char *fi_mood = OPT_STRING_VAL(SLEEP, FI_MOOD); const char *sleep_mood = OPT_STRING_VAL(SLEEP, SLEEP_MOOD); @@ -316,17 +341,27 @@ static int com_sleep(const struct mixer *m) } wake_time_epoch = mktime(tm); PARA_INFO_LOG("waketime: %d:%02d\n", tm->tm_hour, tm->tm_min); - client_cmd("stop"); - sleep(1); + stop(m, h); + ret = set_initial_volume(m, h); + if (ret < 0) + goto close_mixer; + /* + * Setting the volume invalidates the current channel setting, so we + * have to set it again. + */ + ret = set_channel(m, h, OPT_STRING_VAL(PARA_MIXER, MIXER_CHANNEL)); + if (ret < 0) + goto close_mixer; + delay = OPT_UINT32_VAL(SLEEP, INITIAL_DELAY); + if (delay > 0 && initial_mood && *initial_mood) { + change_afs_mode(initial_mood); + client_cmd("play"); + sleep(delay); + stop(m, h); + } if (fot && fo_mood && *fo_mood) { - ret = set_initial_volume(m, h); - if (ret < 0) - goto close_mixer; change_afs_mode(fo_mood); client_cmd("play"); - ret = set_channel(m, h, OPT_STRING_VAL(PARA_MIXER, MIXER_CHANNEL)); - if (ret < 0) - goto close_mixer; ret = fade(m, h, fov, fot); if (ret < 0) goto close_mixer; @@ -340,7 +375,7 @@ static int com_sleep(const struct mixer *m) if (!fot || !fo_mood) /* currently stopped */ client_cmd("play"); } else if (fot && fo_mood && *fo_mood) /* currently playing */ - client_cmd("stop"); + stop(m, h); m->close(&h); if (!fit || !fi_mood || !*fi_mood) /* nothing to do */ return 1; @@ -355,13 +390,12 @@ static int com_sleep(const struct mixer *m) sleep(delay); } change_afs_mode(fi_mood); - if (sleep_mood && *sleep_mood) /* currently playing */ - client_cmd("next"); - else /* currently stopped */ - client_cmd("play"); ret = open_mixer_and_set_channel(m, &h); if (ret < 0) return ret; + if (sleep_mood && *sleep_mood) /* currently playing */ + stop(m, h); + client_cmd("play"); ret = fade(m, h, fiv, fit); close_mixer: m->close(&h); diff --git a/mood.c b/mood.c index d47c54ef..9cdfd011 100644 --- a/mood.c +++ b/mood.c @@ -12,7 +12,6 @@ #include "afh.h" #include "afs.h" #include "list.h" -#include "mood.h" /* * Mood parser API. It's overkill to have an own header file for @@ -47,20 +46,29 @@ struct afs_statistics { /** Number of admissible files */ unsigned num; }; -static struct afs_statistics statistics = {.normalization_divisor = 1}; -struct mood { - /** The name of this mood. */ +/** + * Stores an instance of a loaded mood (parser and statistics). + * + * A structure of this type is allocated and initialized when a mood is loaded. + */ +struct mood_instance { + /** NULL means that this is the "dummy" mood. */ char *name; - /** Info for the bison parser. */ + /** Bison's abstract syntax tree, used to determine admissibility. */ struct mp_context *parser_context; + /** To compute the score. */ + struct afs_statistics stats; }; /* - * If current_mood is NULL then no mood is currently open. If - * current_mood->name is NULL, the dummy mood is currently open. + * If current_mood is NULL then no mood is currently loaded. If + * current_mood->name is NULL, the current mood is the dummy mood. + * + * The statistics are adjusted dynamically through this pointer as files are + * added, removed or played. */ -static struct mood *current_mood; +static struct mood_instance *current_mood; /* * Find the position of the most-significant set bit. @@ -119,15 +127,7 @@ __a_const static uint64_t int_sqrt(uint64_t x) return res; } -/* returns 1 if row admissible, 0 if not, negative on errors */ -static int row_is_admissible(const struct osl_row *aft_row, struct mood *m) -{ - if (!m) - return -E_NO_MOOD; - return mp_eval_row(aft_row, m->parser_context); -} - -static void destroy_mood(struct mood *m) +static void destroy_mood(struct mood_instance *m) { if (!m) return; @@ -136,32 +136,36 @@ static void destroy_mood(struct mood *m) free(m); } -static struct mood *alloc_new_mood(const char *name) +static struct mood_instance *alloc_new_mood(const char *name) { - struct mood *m = zalloc(sizeof(struct mood)); + struct mood_instance *m = zalloc(sizeof(*m)); + if (name) m->name = para_strdup(name); + m->stats.normalization_divisor = 1; return m; } -static int load_mood(const struct osl_row *mood_row, struct mood **m, - char **errmsg) +static int init_mood_parser(const char *mood_name, struct mood_instance **m, + char **err) { - char *mood_name; struct osl_object mood_def; int ret; - ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def); + if (!*mood_name) { + if (err) + *err = make_message("empty mood name\n"); + return -ERRNO_TO_PARA_ERROR(EINVAL); + } + ret = mood_get_def_by_name(mood_name, &mood_def); if (ret < 0) { - if (errmsg) - *errmsg = make_message( - "could not read mood definition"); + if (err) + *err = make_message("could not read mood definition\n"); return ret; } - assert(*mood_name); *m = alloc_new_mood(mood_name); - PARA_INFO_LOG("opening mood %s\n", mood_name); - ret = mp_init(mood_def.data, mood_def.size, &(*m)->parser_context, errmsg); + PARA_INFO_LOG("loading mood %s\n", mood_name); + ret = mp_init(mood_def.data, mood_def.size, &(*m)->parser_context, err); osl_close_disk_object(&mood_def); if (ret < 0) destroy_mood(*m); @@ -170,14 +174,14 @@ static int load_mood(const struct osl_row *mood_row, struct mood **m, static int check_mood(struct osl_row *mood_row, void *data) { - struct para_buffer *pb = data; + struct afs_callback_arg *aca = data; char *mood_name, *errmsg; struct osl_object mood_def; - struct mood *m; + struct mood_instance *m; int ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def); if (ret < 0) { - para_printf(pb, "cannot read mood\n"); + afs_error(aca, "cannot read mood\n"); return ret; } if (!*mood_name) /* ignore dummy row */ @@ -186,9 +190,9 @@ static int check_mood(struct osl_row *mood_row, void *data) ret = mp_init(mood_def.data, mood_def.size, &m->parser_context, &errmsg); if (ret < 0) { - para_printf(pb, "%s: %s\n", mood_name, errmsg); + afs_error(aca, "%s: %s\n%s\n", mood_name, errmsg, + para_strerror(-ret)); free(errmsg); - para_printf(pb, "%s\n", para_strerror(-ret)); } else destroy_mood(m); ret = 1; /* don't fail the loop on invalid mood definitions */ @@ -200,7 +204,7 @@ out: /** * Check all moods for syntax errors. * - * \param aca Only ->pbout is used for diagnostics. + * \param aca Output goes to ->pbout, errors to ->fd on the error band. * * \return Negative on fatal errors. Inconsistent mood definitions are not * considered an error. @@ -208,8 +212,7 @@ out: int mood_check_callback(struct afs_callback_arg *aca) { para_printf(&aca->pbout, "checking moods...\n"); - return osl(osl_rbtree_loop(moods_table, BLOBCOL_ID, &aca->pbout, - check_mood)); + return osl(osl_rbtree_loop(moods_table, BLOBCOL_ID, aca, check_mood)); } /* @@ -249,25 +252,27 @@ int mood_check_callback(struct afs_callback_arg *aca) * overflows and rounding errors we store the common divisor of the * correction factors separately. */ -static long compute_score(struct afs_info *afsi) +static long compute_score(struct afs_info *afsi, + const struct afs_statistics *stats) { int64_t mean_n, mean_l,score_n, score_l; - assert(statistics.normalization_divisor > 0); - assert(statistics.num > 0); - mean_n = statistics.num_played_sum / statistics.num; - mean_l = statistics.last_played_sum / statistics.num; + assert(stats->normalization_divisor > 0); + assert(stats->num > 0); + mean_n = stats->num_played_sum / stats->num; + mean_l = stats->last_played_sum / stats->num; score_n = -((int64_t)afsi->num_played - mean_n) - * statistics.num_played_correction - / statistics.normalization_divisor; + * stats->num_played_correction + / stats->normalization_divisor; score_l = -((int64_t)afsi->last_played - mean_l) - * statistics.last_played_correction - / statistics.normalization_divisor; + * stats->last_played_correction + / stats->normalization_divisor; return (score_n + score_l) / 2; } -static int add_afs_statistics(const struct osl_row *row) +static int add_afs_statistics(const struct osl_row *row, + struct afs_statistics *stats) { uint64_t n, x, s, q; struct afs_info afsi; @@ -276,64 +281,65 @@ static int add_afs_statistics(const struct osl_row *row) ret = get_afsi_of_row(row, &afsi); if (ret < 0) return ret; - n = statistics.num; + n = stats->num; x = afsi.last_played; - s = statistics.last_played_sum; + s = stats->last_played_sum; if (n > 0) { q = (x > s / n)? x - s / n : s / n - x; - statistics.last_played_qd += q * q * n / (n + 1); + stats->last_played_qd += q * q * n / (n + 1); } - statistics.last_played_sum += x; + stats->last_played_sum += x; x = afsi.num_played; - s = statistics.num_played_sum; + s = stats->num_played_sum; if (n > 0) { q = (x > s / n)? x - s / n : s / n - x; - statistics.num_played_qd += q * q * n / (n + 1); + stats->num_played_qd += q * q * n / (n + 1); } - statistics.num_played_sum += x; - statistics.num++; + stats->num_played_sum += x; + stats->num++; return 1; } static int del_afs_statistics(const struct osl_row *row) { + struct afs_statistics *stats = ¤t_mood->stats; uint64_t n, s, q, a, new_s; struct afs_info afsi; int ret; ret = get_afsi_of_row(row, &afsi); if (ret < 0) return ret; - n = statistics.num; + n = stats->num; assert(n); if (n == 1) { - memset(&statistics, 0, sizeof(statistics)); - statistics.normalization_divisor = 1; + memset(stats, 0, sizeof(*stats)); + stats->normalization_divisor = 1; return 1; } - s = statistics.last_played_sum; - q = statistics.last_played_qd; + s = stats->last_played_sum; + q = stats->last_played_qd; a = afsi.last_played; new_s = s - a; - statistics.last_played_sum = new_s; - statistics.last_played_qd = q + s * s / n - a * a + stats->last_played_sum = new_s; + stats->last_played_qd = q + s * s / n - a * a - new_s * new_s / (n - 1); - s = statistics.num_played_sum; - q = statistics.num_played_qd; + s = stats->num_played_sum; + q = stats->num_played_qd; a = afsi.num_played; new_s = s - a; - statistics.num_played_sum = new_s; - statistics.num_played_qd = q + s * s / n - a * a + stats->num_played_sum = new_s; + stats->num_played_qd = q + s * s / n - a * a - new_s * new_s / (n - 1); - statistics.num--; + stats->num--; return 1; } /* - * At mood open time we determine the set of admissible files for the given + * At mood load time we determine the set of admissible files for the given * mood where each file is identified by a pointer to a row of the audio file * table. In the first pass the pointers are added to a temporary array and * statistics are computed. When all admissible files have been processed in @@ -343,7 +349,7 @@ static int del_afs_statistics(const struct osl_row *row) */ struct admissible_array { /** Files are admissible wrt. this mood. */ - struct mood *m; + struct mood_instance *m; /** The size of the array */ unsigned size; /** Pointer to the array of admissible files. */ @@ -357,19 +363,18 @@ struct admissible_array { static int add_if_admissible(struct osl_row *aft_row, void *data) { struct admissible_array *aa = data; - int ret; + struct afs_statistics *stats = &aa->m->stats; - ret = row_is_admissible(aft_row, aa->m); - if (ret <= 0) - return ret; - if (statistics.num >= aa->size) { + if (!mp_eval_row(aft_row, aa->m->parser_context)) + return 0; + if (stats->num >= aa->size) { aa->size *= 2; aa->size += 100; aa->array = arr_realloc(aa->array, aa->size, sizeof(struct osl_row *)); } - aa->array[statistics.num] = aft_row; - return add_afs_statistics(aft_row); + aa->array[stats->num] = aft_row; + return add_afs_statistics(aft_row, stats); } /** @@ -414,29 +419,25 @@ _static_inline_ int64_t update_quadratic_deviation(int64_t n, int64_t old_qd, return old_qd + delta * (sigma - 2 * old_sum / n - delta / n); } -static int update_afs_statistics(struct afs_info *old_afsi, +static void update_afs_statistics(struct afs_info *old_afsi, struct afs_info *new_afsi) { - unsigned n; - int ret = get_num_admissible_files(&n); - - if (ret < 0) - return ret; - assert(n); - - statistics.last_played_qd = update_quadratic_deviation(n, - statistics.last_played_qd, old_afsi->last_played, - new_afsi->last_played, statistics.last_played_sum); - statistics.last_played_sum += new_afsi->last_played - old_afsi->last_played; - - statistics.num_played_qd = update_quadratic_deviation(n, - statistics.num_played_qd, old_afsi->num_played, - new_afsi->num_played, statistics.num_played_sum); - statistics.num_played_sum += new_afsi->num_played - old_afsi->num_played; - return 1; + struct afs_statistics *stats = ¤t_mood->stats; + + assert(stats->num > 0); + stats->last_played_qd = update_quadratic_deviation(stats->num, + stats->last_played_qd, old_afsi->last_played, + new_afsi->last_played, stats->last_played_sum); + stats->last_played_sum += new_afsi->last_played - old_afsi->last_played; + + stats->num_played_qd = update_quadratic_deviation(stats->num, + stats->num_played_qd, old_afsi->num_played, + new_afsi->num_played, stats->num_played_sum); + stats->num_played_sum += new_afsi->num_played - old_afsi->num_played; } -static int add_to_score_table(const struct osl_row *aft_row) +static int add_to_score_table(const struct osl_row *aft_row, + const struct afs_statistics *stats) { long score; struct afs_info afsi; @@ -444,7 +445,7 @@ static int add_to_score_table(const struct osl_row *aft_row) if (ret < 0) return ret; - score = compute_score(&afsi); + score = compute_score(&afsi, stats); return score_add(aft_row, score); } @@ -457,23 +458,18 @@ static int delete_from_statistics_and_score_table(const struct osl_row *aft_row) } /** - * Delete one entry from the statistics and from the score table. + * Delete an audio file from the score table and update mood statistics. * - * \param aft_row The audio file which is no longer admissible. + * \param aft_row Identifies the row to delete. * - * \return Positive on success, negative on errors. + * \return Standard. * * \sa \ref score_delete(). */ static int mood_delete_audio_file(const struct osl_row *aft_row) { - int ret; - - ret = row_belongs_to_score_table(aft_row, NULL); - if (ret < 0) - return ret; - if (!ret) /* not admissible, nothing to do */ - return 1; + if (!row_belongs_to_score_table(aft_row)) + return 0; return delete_from_statistics_and_score_table(aft_row); } @@ -492,95 +488,71 @@ static int mood_update_audio_file(const struct osl_row *aft_row, struct afs_info *old_afsi) { long score, percent; - int ret, is_admissible, was_admissible = 0; + int ret; + bool is_admissible, was_admissible; struct afs_info afsi; - unsigned rank; if (!current_mood) return 1; /* nothing to do */ - ret = row_belongs_to_score_table(aft_row, &rank); - if (ret < 0) - return ret; - was_admissible = ret; - ret = row_is_admissible(aft_row, current_mood); - if (ret < 0) - return ret; - is_admissible = (ret > 0); + was_admissible = row_belongs_to_score_table(aft_row); + is_admissible = mp_eval_row(aft_row, current_mood->parser_context); if (!was_admissible && !is_admissible) return 1; if (was_admissible && !is_admissible) return delete_from_statistics_and_score_table(aft_row); if (!was_admissible && is_admissible) { - ret = add_afs_statistics(aft_row); + ret = add_afs_statistics(aft_row, ¤t_mood->stats); if (ret < 0) return ret; - return add_to_score_table(aft_row); + return add_to_score_table(aft_row, ¤t_mood->stats); } /* update score */ ret = get_afsi_of_row(aft_row, &afsi); if (ret < 0) return ret; - if (old_afsi) { - ret = update_afs_statistics(old_afsi, &afsi); - if (ret < 0) - return ret; - } - score = compute_score(&afsi); + if (old_afsi) + update_afs_statistics(old_afsi, &afsi); + score = compute_score(&afsi, ¤t_mood->stats); PARA_DEBUG_LOG("score: %li\n", score); percent = (score + 100) / 3; if (percent > 100) percent = 100; else if (percent < 0) percent = 0; - PARA_DEBUG_LOG("moving from rank %u to %li%%\n", rank, percent); + PARA_DEBUG_LOG("moving to %li%%\n", percent); return score_update(aft_row, percent); } /* sse: seconds since epoch. */ -static void log_statistics(int64_t sse) +static char *get_statistics(struct mood_instance *m, int64_t sse) { - unsigned n = statistics.num; + unsigned n = m->stats.num; int mean_days, sigma_days; - assert(current_mood); - PARA_NOTICE_LOG("loaded mood %s\n", current_mood->name? - current_mood->name : "(dummy)"); - if (!n) { - PARA_WARNING_LOG("no admissible files\n"); - return; - } - PARA_NOTICE_LOG("%u admissible files\n", statistics.num); - mean_days = (sse - statistics.last_played_sum / n) / 3600 / 24; - sigma_days = int_sqrt(statistics.last_played_qd / n) / 3600 / 24; - PARA_NOTICE_LOG("last_played mean/sigma: %d/%d days\n", mean_days, sigma_days); - PARA_NOTICE_LOG("num_played mean/sigma: %" PRId64 "/%" PRIu64 "\n", - statistics.num_played_sum / n, - int_sqrt(statistics.num_played_qd / n)); - PARA_NOTICE_LOG("num_played correction factor: %" PRId64 "\n", - statistics.num_played_correction); - PARA_NOTICE_LOG("last_played correction factor: %" PRId64 "\n", - statistics.last_played_correction); - PARA_NOTICE_LOG("normalization divisor: %" PRId64 "\n", - statistics.normalization_divisor); + mean_days = (sse - m->stats.last_played_sum / n) / 3600 / 24; + sigma_days = int_sqrt(m->stats.last_played_qd / n) / 3600 / 24; + return make_message( + "loaded mood %s (%u files)\n" + "last_played mean/sigma: %d/%d days\n" + "num_played mean/sigma: %" PRId64 "/%" PRIu64 "\n" + , + m->name? m->name : "(dummy)", + n, + mean_days, sigma_days, + m->stats.num_played_sum / n, + int_sqrt(m->stats.num_played_qd / n) + ); } -/** - * Close the current mood. - * - * Frees all resources of the current mood. - */ -void close_current_mood(void) +/** Free all resources of the current mood, if any. */ +void mood_unload(void) { destroy_mood(current_mood); current_mood = NULL; - memset(&statistics, 0, sizeof(statistics)); - statistics.normalization_divisor = 1; } -static void compute_correction_factors(int64_t sse) +static void compute_correction_factors(int64_t sse, struct afs_statistics *s) { - struct afs_statistics *s = &statistics; - if (s->num > 0) { s->normalization_divisor = int_sqrt(s->last_played_qd) * int_sqrt(s->num_played_qd) / s->num / 100; @@ -598,28 +570,24 @@ static void compute_correction_factors(int64_t sse) /** * Change the current mood. * - * \param mood_name The name of the mood to open. - * \param errmsg Error description is returned here. + * \param mood_name The name of the mood to load. + * \param msg Error message or mood info is returned here. * * If \a mood_name is \a NULL, load the dummy mood that accepts every audio file * and uses a scoring method based only on the \a last_played information. * - * The errmsg pointer may be NULL, in which case no error message will be - * returned. If a non-NULL pointer is given, the caller must free *errmsg. - * - * If there is already an open mood, it will be closed first. + * If the message pointer is not NULL, a suitable message is returned there in + * all cases. The caller must free this string. * - * \return Positive on success, negative on errors. + * \return The number of admissible files on success, negative on errors. It is + * not considered an error if no files are admissible. * * \sa struct \ref afs_info::last_played, \ref mp_eval_row(). */ -int change_current_mood(const char *mood_name, char **errmsg) +int mood_load(const char *mood_name, char **msg) { int i, ret; - struct admissible_array aa = { - .size = 0, - .array = NULL - }; + struct admissible_array aa = {.size = 0}; /* * We can not use the "now" pointer from sched.c here because we are * called before schedule(), which initializes "now". @@ -627,85 +595,68 @@ int change_current_mood(const char *mood_name, char **errmsg) struct timeval rnow; if (mood_name) { - struct mood *m; - struct osl_row *row; - struct osl_object obj; - - if (!*mood_name) { - *errmsg = make_message("empty mood name"); - return -ERRNO_TO_PARA_ERROR(EINVAL); - } - obj.data = (char *)mood_name; - obj.size = strlen(mood_name) + 1; - ret = osl(osl_get_row(moods_table, BLOBCOL_NAME, &obj, &row)); - if (ret < 0) { - if (errmsg) - *errmsg = make_message("no such mood: %s", - mood_name); - return ret; - } - ret = load_mood(row, &m, errmsg); + ret = init_mood_parser(mood_name, &aa.m, msg); if (ret < 0) return ret; - close_current_mood(); - current_mood = m; - } else { /* load dummy mood */ - close_current_mood(); - current_mood = alloc_new_mood(NULL); - } - aa.m = current_mood; + } else /* load dummy mood */ + aa.m = alloc_new_mood(NULL); PARA_NOTICE_LOG("computing statistics of admissible files\n"); ret = audio_file_loop(&aa, add_if_admissible); if (ret < 0) { - if (errmsg) - *errmsg = make_message("audio file loop failed"); + if (msg) /* false if we are called via the event handler */ + *msg = make_message("audio file loop failed\n"); goto out; } clock_get_realtime(&rnow); - compute_correction_factors(rnow.tv_sec); - log_statistics(rnow.tv_sec); - for (i = 0; i < statistics.num; i++) { - ret = add_to_score_table(aa.array[i]); + compute_correction_factors(rnow.tv_sec, &aa.m->stats); + if (aa.m->stats.num == 0) { + if (msg) + *msg = make_message("no admissible files\n"); + ret = 0; + goto out; + } + for (i = 0; i < aa.m->stats.num; i++) { + ret = add_to_score_table(aa.array[i], &aa.m->stats); if (ret < 0) { - if (errmsg) - *errmsg = make_message( - "could not add row to score table"); + if (msg) + *msg = make_message( + "could not add row to score table\n"); goto out; } } - ret = statistics.num; + /* success */ + if (msg) + *msg = get_statistics(aa.m, rnow.tv_sec); + ret = aa.m->stats.num; + mood_unload(); + current_mood = aa.m; out: free(aa.array); if (ret < 0) - close_current_mood(); + destroy_mood(aa.m); return ret; } /* - * Close and re-open the current mood. + * Empty the score table and start over. * * This function is called on events which render the current list of * admissible files useless, for example if an attribute is removed from the * attribute table. - * - * If no mood is currently open, the function returns success. */ static int reload_current_mood(void) { int ret; char *mood_name = NULL; - ret = clear_score_table(); - if (ret < 0) - return ret; - if (!current_mood) - return 1; + assert(current_mood); + score_clear(); PARA_NOTICE_LOG("reloading %s\n", current_mood->name? current_mood->name : "(dummy)"); if (current_mood->name) mood_name = para_strdup(current_mood->name); - close_current_mood(); - ret = change_current_mood(mood_name, NULL); + mood_unload(); + ret = mood_load(mood_name, NULL); free(mood_name); return ret; } diff --git a/mood.h b/mood.h deleted file mode 100644 index fcfe1efc..00000000 --- a/mood.h +++ /dev/null @@ -1,7 +0,0 @@ -/* Copyright (C) 2007 Andre Noll , see file COPYING. */ - -/** \file mood.h Public functions of mood.c. */ - -int change_current_mood(const char *mood_name, char **errmsg); -void close_current_mood(void); -int mood_check_callback(struct afs_callback_arg *aca); diff --git a/mp.c b/mp.c index fb5a0c07..a068b043 100644 --- a/mp.c +++ b/mp.c @@ -557,7 +557,7 @@ int mp_init(const char *definition, int nbytes, struct mp_context **result, * function returns true (without looking at the audio file metadata) to * indicate that the given audio file should be considered admissible. * - * \sa \ref change_current_mood(), \ref mp_eval_ast(). + * \sa \ref mood_load(), \ref mp_eval_ast(). */ bool mp_eval_row(const struct osl_row *aft_row, struct mp_context *ctx) { diff --git a/net.c b/net.c index e01af24b..a24081f5 100644 --- a/net.c +++ b/net.c @@ -18,6 +18,13 @@ #include "list.h" #include "fd.h" +/* Whether the given address conforms to the IPv4 address format. */ +static inline bool is_valid_ipv4_address(const char *address) +{ + struct in_addr test_it; + return inet_pton(AF_INET, address, &test_it) != 0; +} + /** * Parse and validate IPv4 address/netmask string. * @@ -58,13 +65,6 @@ failed: return NULL; } - -/** - * Match string as a candidate IPv4 address. - * - * \param address The string to match. - * \return True if \a address has "dot-quad" format. - */ static bool is_v4_dot_quad(const char *address) { bool result; @@ -77,6 +77,13 @@ static bool is_v4_dot_quad(const char *address) return result; } +/* Whether a string conforms to IPv6 address format (RFC 4291). */ +static inline bool is_valid_ipv6_address(const char *address) +{ + struct in6_addr test_it; + return inet_pton(AF_INET6, address, &test_it) != 0; +} + /** * Perform basic syntax checking on the host-part of an URL: * @@ -205,7 +212,7 @@ char *format_url(const char *url, int default_port) * \param transport Transport protocol name (e.g. "udp", "tcp"), or NULL. * \return Pointer to static result buffer. * - * \sa getservent(3), services(5), nsswitch.conf(5). + * \sa getservbyport(3), services(5), nsswitch.conf(5). */ const char *stringify_port(int port, const char *transport) { @@ -224,12 +231,13 @@ const char *stringify_port(int port, const char *transport) return service; } -/** - * Determine the socket type for a given layer-4 protocol. - * - * \param l4type The symbolic name of the transport-layer protocol. - * - * \sa ip(7), socket(2). +#ifndef SOCK_DCCP +#define SOCK_DCCP 6 /**< Linux socket type. */ +#endif + +/* + * Determine the socket type, given the symbolic name of the transport-layer + * protocol. See ip(7), socket(2). */ static inline int sock_type(const unsigned l4type) { @@ -241,9 +249,7 @@ static inline int sock_type(const unsigned l4type) return -1; /* not supported here */ } -/** - * Pretty-print transport-layer name. - */ +/* Pretty-print transport-layer name. */ static const char *layer4_name(const unsigned l4type) { switch (l4type) { @@ -273,7 +279,12 @@ struct pre_conn_opt { struct list_head node; /**< FIFO, as sockopt order matters. */ }; -/** FIFO list of pre-connection socket options to be set */ +/** + * List of pre-connection socket options to be set. + * + * This list contains transport-layer independent encapsulation of socket + * options that need to be registered prior to setting up a connection. + */ struct flowopts { struct list_head sockopts; }; @@ -325,7 +336,7 @@ void flowopt_add(struct flowopts *fo, int lev, int opt, list_add_tail(&new->node, &fo->sockopts); } -/** Set the entire bunch of pre-connection options at once. */ +/* Set the entire bunch of pre-connection options at once. */ static void flowopt_setopts(int sockfd, struct flowopts *fo) { struct pre_conn_opt *pc; @@ -509,7 +520,7 @@ int makesock(unsigned l4type, bool passive, const char *host, uint16_t port_numb if (ai) freeaddrinfo(ai); if (ret < 0) { - PARA_ERROR_LOG("can not create %s socket %s#%d.\n", + PARA_NOTICE_LOG("can not create %s socket %s#%d.\n", layer4_name(l4type), host? host : (passive? "[loopback]" : "[localhost]"), port_number); } @@ -571,11 +582,7 @@ int para_listen_simple(unsigned l4type, uint16_t port) return para_listen(l4type, NULL, port); } -/** - * Determine IPv4/v6 socket address length. - * \param sa Container of IPv4 or IPv6 address. - * \return Address-family dependent address length. - */ +/* Compute the address-family dependent address length of an IPv4/v6 socket. */ static socklen_t salen(const struct sockaddr *sa) { assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6); @@ -585,7 +592,7 @@ static socklen_t salen(const struct sockaddr *sa) : sizeof(struct sockaddr_in); } -/** True if @ss holds a v6-mapped-v4 address (RFC 4291, 2.5.5.2) */ +/* True if ss holds a v6-mapped-v4 address (RFC 4291, 2.5.5.2) */ static bool SS_IS_ADDR_V4MAPPED(const struct sockaddr_storage *ss) { const struct sockaddr_in6 *ia6 = (const struct sockaddr_in6 *)ss; @@ -593,10 +600,10 @@ static bool SS_IS_ADDR_V4MAPPED(const struct sockaddr_storage *ss) return ss->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&ia6->sin6_addr); } -/** +/* * Process IPv4/v6 address, turn v6-mapped-v4 address into normal IPv4 address. - * \param ss Container of IPv4/6 address. - * \return Pointer to normalized address (may be static storage). + * ss: Container of IPv4/6 address. + * Returns: Pointer to normalized address (may be static storage). * * \sa RFC 3493. */ @@ -617,7 +624,7 @@ normalize_ip_address(const struct sockaddr_storage *ss) return (const struct sockaddr *)ss; } -/** +/* * Generic/fallback MTU values * * These are taken from RFC 1122, RFC 2460, and RFC 5405. @@ -632,7 +639,7 @@ static inline int generic_mtu(const int af_type) return af_type == AF_INET6 ? 1280 : 576; } -/** Crude approximation of IP header overhead - neglecting options. */ +/* Crude approximation of IP header overhead - neglecting options. */ static inline int estimated_header_overhead(const int af_type) { return af_type == AF_INET6 ? 40 : 20; @@ -829,6 +836,10 @@ int para_accept(int fd, void *addr, socklen_t size, int *new_fd) return -ERRNO_TO_PARA_ERROR(errno); } +#ifndef DCCP_SOCKOPT_AVAILABLE_CCIDS +#define DCCP_SOCKOPT_AVAILABLE_CCIDS 12 /**< List of supported CCIDs. */ +#endif + /** * Probe the list of DCCP CCIDs configured on this host. * \param ccid_array Pointer to return statically allocated array in. @@ -843,7 +854,7 @@ int dccp_available_ccids(uint8_t **ccid_array) socklen_t nccids = sizeof(ccids); int ret, fd; - ret = fd = makesock(IPPROTO_DCCP, 1, NULL, 0, NULL); + ret = fd = makesock(IPPROTO_DCCP, true /* passive */, NULL, 0, NULL); if (ret < 0) return ret; @@ -861,6 +872,18 @@ int dccp_available_ccids(uint8_t **ccid_array) return nccids; } +/** + * The buffer size of the sun_path component of struct sockaddr_un. + * + * While glibc doesn't define UNIX_PATH_MAX, it documents it has being limited + * to 108 bytes. On NetBSD it is only 104 bytes though. We trust UNIX_PATH_MAX + * if it is defined and use the size of the ->sun_path member otherwise. This + * should be safe everywhere. + */ +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)0)->sun_path)) +#endif + /* * Prepare a structure for AF_UNIX socket addresses. * diff --git a/net.h b/net.h index fd89dc5d..d206881c 100644 --- a/net.h +++ b/net.h @@ -1,106 +1,32 @@ /* Copyright (C) 2006 Andre Noll , see file COPYING. */ /** \file net.h exported symbols from net.c */ -/** - * The buffer size of the sun_path component of struct sockaddr_un. - * - * While glibc doesn't define \p UNIX_PATH_MAX, it documents it has being - * limited to 108 bytes. On NetBSD it is only 104 bytes though. We trust \p - * UNIX_PATH_MAX if it is defined and use the size of the ->sun_path member - * otherwise. This should be safe everywhere. - */ -#ifndef UNIX_PATH_MAX -#define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)0)->sun_path)) -#endif - /* Userland defines for Linux DCCP support. */ -#ifndef IPPROTO_DCCP -#define IPPROTO_DCCP 33 /**< IANA assigned value. */ -#endif - -#ifndef SOCK_DCCP -#define SOCK_DCCP 6 /**< Linux socket type. */ -#endif - -#ifndef DCCP_SOCKOPT_RX_CCID -/** Per-connection CCID support (set/get the RX CCID, since v2.6.30-rc1). */ -#define DCCP_SOCKOPT_RX_CCID 15 -#endif - #ifndef SOL_DCCP #define SOL_DCCP 269 /**< Linux socket level. */ #endif -#ifndef DCCP_SOCKOPT_GET_CUR_MPS -#define DCCP_SOCKOPT_GET_CUR_MPS 5 /**< Max packet size, RFC 4340, 14. */ -#endif - -#ifndef DCCP_SOCKOPT_AVAILABLE_CCIDS -#define DCCP_SOCKOPT_AVAILABLE_CCIDS 12 /**< List of supported CCIDs. */ -#endif - -#ifndef DCCP_SOCKOPT_CCID -#define DCCP_SOCKOPT_CCID 13 /**< Sets both TX/RX CCID. */ -#endif - -#ifndef DCCP_SOCKOPT_TX_CCID -#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. - */ +/* Opaque, only known to net.c. */ struct flowopts; -extern struct flowopts *flowopt_new(void); -extern void flowopt_add(struct flowopts *fo, int level, int opt, +struct flowopts *flowopt_new(void); +void flowopt_add(struct flowopts *fo, int level, int opt, const char *name, const void *val, int len); void flowopt_cleanup(struct flowopts *fo); -/** Flowopt shortcut macros */ -#define OPT_ADD(fo, lev, opt, val, len) flowopt_add(fo, lev, opt, #opt, val, len) /** * Functions to parse and validate (parts of) URLs. */ -extern char *parse_cidr(const char *cidr, - char *addr, ssize_t addrlen, int32_t *netmask); -extern char *parse_url(const char *url, - char *host, ssize_t hostlen, int32_t *port); +char *parse_cidr(const char *cidr, + char *addr, ssize_t addrlen, int32_t *netmask); +char *parse_url(const char *url, + char *host, ssize_t hostlen, int32_t *port); char *format_url(const char *url, int default_port); -extern const char *stringify_port(int port, const char *transport); -/** - * Ensure that string conforms to the IPv4 address format. - * - * \param address The address string to check. - * - * \return 1 if \a address conforms to the IPv4 address format, else 0. - */ -_static_inline_ bool is_valid_ipv4_address(const char *address) -{ - struct in_addr test_it; - - return inet_pton(AF_INET, address, &test_it) != 0; -} - -/** - * Ensure that string conforms to IPv6 address format. - * - * \param address The address string to check. - * - * \return 1 if string has a valid IPv6 address syntax, 0 if not. - * \sa RFC 4291. - */ -_static_inline_ bool is_valid_ipv6_address(const char *address) -{ - struct in6_addr test_it; - - return inet_pton(AF_INET6, address, &test_it) != 0; -} +const char *stringify_port(int port, const char *transport); int lookup_address(unsigned l4type, bool passive, const char *host, int port_number, struct addrinfo **result); @@ -114,10 +40,9 @@ int makesock(unsigned l4type, bool passive, const char *host, int makesock_addrinfo(unsigned l4type, bool passive, struct addrinfo *ai, struct flowopts *fo); -static inline int para_connect_simple(unsigned l4type, - const char *host, uint16_t port) +static inline int para_connect(unsigned l4type, const char *host, uint16_t port) { - return makesock(l4type, 0, host, port, NULL); + return makesock(l4type, false, host, port, NULL); } void extract_v4_addr(const struct sockaddr_storage *ss, struct in_addr *ia); @@ -133,12 +58,12 @@ int para_listen(unsigned l4type, const char *addr, uint16_t port); int para_listen_simple(unsigned l4type, uint16_t port); /** Pretty-printing of IPv4/6 socket addresses */ -extern char *remote_name(int sockfd); +char *remote_name(int sockfd); /** * Determining maximum payload (packet) size */ -extern int generic_max_transport_msg_size(int sockfd); +int generic_max_transport_msg_size(int sockfd); int recv_bin_buffer(int fd, char *buf, size_t size); int recv_buffer(int fd, char *buf, size_t size); @@ -152,8 +77,6 @@ ssize_t send_cred_buffer(int, char*); /** * Functions and definitions to support \p IPPROTO_DCCP */ -/** Estimated worst-case length of a DCCP header including options. */ -#define DCCP_MAX_HEADER 128 /** Hardcoded maximum number of separate CCID modules compiled into a host. */ #define DCCP_MAX_HOST_CCIDS 20 -extern int dccp_available_ccids(uint8_t **ccid_array); +int dccp_available_ccids(uint8_t **ccid_array); diff --git a/para.h b/para.h index bbf91330..280c2823 100644 --- a/para.h +++ b/para.h @@ -222,6 +222,7 @@ enum loglevels {LOGLEVELS, NUM_LOGLEVELS}; #define PARA_CRIT_LOG(f,...) para_log(LL_CRIT, "%s: " f, __FUNCTION__, ## __VA_ARGS__) #define PARA_EMERG_LOG(f,...) para_log(LL_EMERG, "%s: " f, __FUNCTION__, ## __VA_ARGS__) +/** \cond status_items */ #define STATUS_ITEMS \ STATUS_ITEM(basename) \ STATUS_ITEM(status) \ @@ -269,6 +270,7 @@ enum loglevels {LOGLEVELS, NUM_LOGLEVELS}; enum status_items {STATUS_ITEMS NUM_STAT_ITEMS}; #undef STATUS_ITEM #define STATUS_ITEM(_name) #_name, +/** \endcond status items */ extern const char *status_item_list[]; /** Loop over each status item. */ diff --git a/playlist.c b/playlist.c index 5f83b0fe..d02ade3b 100644 --- a/playlist.c +++ b/playlist.c @@ -15,13 +15,13 @@ /** \file playlist.c Functions for loading and saving playlists. */ /** Structure used for adding entries to a playlist. */ -struct playlist_info { +struct playlist_instance { /** The name of the playlist. */ char *name; /** The number of entries currently in the playlist. */ unsigned length; }; -static struct playlist_info current_playlist; +static struct playlist_instance current_playlist; /** * Re-insert an audio file into the tree of admissible files. @@ -38,7 +38,7 @@ static int playlist_update_audio_file(const struct osl_row *aft_row) static int add_playlist_entry(char *path, void *data) { - struct playlist_info *playlist = data; + struct playlist_instance *playlist = data; struct osl_row *aft_row; int ret = aft_get_row_of_path(path, &aft_row); @@ -55,64 +55,34 @@ static int add_playlist_entry(char *path, void *data) return 1; } -/* returns -E_PLAYLIST_LOADED on _success_ to terminate the loop */ -static int load_playlist(struct osl_row *row, void *data) -{ - struct playlist_info *playlist = data; - struct osl_object playlist_def; - char *playlist_name; - int ret; - - ret = pl_get_name_and_def_by_row(row, &playlist_name, &playlist_def); - if (ret < 0) - goto err; - playlist->length = 0; - ret = for_each_line(FELF_READ_ONLY, playlist_def.data, - playlist_def.size, add_playlist_entry, playlist); - osl_close_disk_object(&playlist_def); - if (ret < 0) - goto err; - ret = -E_PLAYLIST_EMPTY; - if (!playlist->length) - goto err; - playlist->name = para_strdup(playlist_name); - PARA_NOTICE_LOG("loaded playlist %s (%u files)\n", playlist->name, - playlist->length); - return -E_PLAYLIST_LOADED; -err: - if (ret != -E_DUMMY_ROW) - PARA_NOTICE_LOG("unable to load playlist (%s)\n", - para_strerror(-ret)); - return 1; -} - static int check_playlist_path(char *path, void *data) { - struct para_buffer *pb = data; + struct afs_callback_arg *aca = data; struct osl_row *aft_row; int ret = aft_get_row_of_path(path, &aft_row); if (ret < 0) - para_printf(pb, "%s: %s\n", path, para_strerror(-ret)); + afs_error(aca, "%s: %s\n", path, para_strerror(-ret)); return 1; /* do not fail the loop on bad paths */ } static int check_playlist(struct osl_row *row, void *data) { - struct para_buffer *pb = data; + struct afs_callback_arg *aca = data; + struct para_buffer *pb = &aca->pbout; struct osl_object playlist_def; char *playlist_name; int ret = pl_get_name_and_def_by_row(row, &playlist_name, &playlist_def); if (ret < 0) { /* log error, but continue */ - para_printf(pb, "failed to get playlist data: %s\n", + afs_error(aca, "failed to get playlist data: %s\n", para_strerror(-ret)); return 1; } if (*playlist_name) { /* skip dummy row */ para_printf(pb, "checking playlist %s...\n", playlist_name); for_each_line(FELF_READ_ONLY, playlist_def.data, - playlist_def.size, check_playlist_path, pb); + playlist_def.size, check_playlist_path, aca); } osl_close_disk_object(&playlist_def); return 1; @@ -129,49 +99,64 @@ static int check_playlist(struct osl_row *row, void *data) int playlist_check_callback(struct afs_callback_arg *aca) { para_printf(&aca->pbout, "checking playlists...\n"); - return osl(osl_rbtree_loop(playlists_table, BLOBCOL_ID, &aca->pbout, + return osl(osl_rbtree_loop(playlists_table, BLOBCOL_ID, aca, check_playlist)); } -/** - * Close the current playlist. - * - * \sa \ref playlist_open(). - */ -void playlist_close(void) +/** Free all resources of the current playlist, if any. */ +void playlist_unload(void) { if (!current_playlist.name) return; free(current_playlist.name); current_playlist.name = NULL; + current_playlist.length = 0; } /** - * Open the given playlist. + * Populate the score table from the paths of a playlist database object. * - * \param name The name of the playlist to open. + * This loads the blob object which corresponds to the given name from the + * playlist table. Each line of the blob is regarded as a path which is looked + * up in the audio file table. If the path lookup succeeds, a reference to the + * corresponding row of the audio file table is added to the score table. * - * Files which are listed in the playlist, but not contained in the database - * are ignored. This is not considered an error. + * \param name The name of the playlist to load. + * \param msg Error message or playlist info is returned here. * - * \return Standard. + * \return The length of the loaded playlist on success, negative error code + * else. Files which are listed in the playlist, but are not contained in the + * database are ignored. This is not considered an error. */ -int playlist_open(const char *name) +int playlist_load(const char *name, char **msg) { - struct osl_object obj; int ret; - struct osl_row *row; + struct playlist_instance *playlist = ¤t_playlist; + struct osl_object playlist_def; - obj.data = (char *)name; - obj.size = strlen(obj.data); - ret = osl(osl_get_row(playlists_table, BLOBCOL_NAME, &obj, &row)); + ret = pl_get_def_by_name(name, &playlist_def); if (ret < 0) { - PARA_NOTICE_LOG("failed to load playlist %s\n", name); + *msg = make_message("could not read playlist %s\n", name); return ret; } - playlist_close(); - ret = load_playlist(row, ¤t_playlist); - return (ret == -E_PLAYLIST_LOADED)? current_playlist.length : ret; + playlist_unload(); + ret = for_each_line(FELF_READ_ONLY, playlist_def.data, + playlist_def.size, add_playlist_entry, playlist); + osl_close_disk_object(&playlist_def); + if (ret < 0) + goto err; + ret = -E_PLAYLIST_EMPTY; + if (!playlist->length) + goto err; + playlist->name = para_strdup(name); + *msg = make_message("loaded playlist %s (%u files)\n", playlist->name, + playlist->length); + /* success */ + return current_playlist.length; +err: + PARA_NOTICE_LOG("unable to load playlist %s\n", name); + *msg = make_message("unable to load playlist %s\n", name); + return ret; } static int search_path(char *path, void *data) @@ -183,17 +168,14 @@ static int search_path(char *path, void *data) static int handle_audio_file_event(enum afs_events event, void *data) { - int ret, was_admissible = 0, is_admissible; + int ret; + bool was_admissible = false, is_admissible; struct osl_object playlist_def; char *new_path; const struct osl_row *row = data; - if (event == AUDIO_FILE_RENAME) { - ret = row_belongs_to_score_table(row, NULL); - if (ret < 0) - return ret; - was_admissible = ret; - } + if (event == AUDIO_FILE_RENAME) + was_admissible = row_belongs_to_score_table(row); ret = get_audio_file_path_of_row(row, &new_path); if (ret < 0) return ret; @@ -229,7 +211,6 @@ static int handle_audio_file_event(enum afs_events event, void *data) int playlists_event_handler(enum afs_events event, __a_unused struct para_buffer *pb, void *data) { - int ret; struct afsi_change_event_data *aced = data; if (!current_playlist.name) @@ -241,10 +222,7 @@ int playlists_event_handler(enum afs_events event, case AUDIO_FILE_ADD: return handle_audio_file_event(event, data); case AUDIO_FILE_REMOVE: - ret = row_belongs_to_score_table(data, NULL); - if (ret < 0) - return ret; - if (!ret) + if (!row_belongs_to_score_table(data)) return 1; current_playlist.length--; return score_delete(data); diff --git a/score.c b/score.c index 54af56f7..10cd254a 100644 --- a/score.c +++ b/score.c @@ -76,18 +76,6 @@ static struct osl_table_description score_table_desc = { .column_descriptions = score_cols }; -/** - * Compute the number of files in score table. - * - * \param num Result is returned here. - * - * \return Positive on success, negative on errors. - */ -int get_num_admissible_files(unsigned *num) -{ - return osl(osl_get_num_rows(score_table, num)); -} - /* On errors (negative return value) the content of score is undefined. */ static int get_score_of_row(void *score_row, long *score) { @@ -132,16 +120,6 @@ int score_add(const struct osl_row *aft_row, long score) return ret; } -static int get_nth_score(unsigned n, long *score) -{ - struct osl_row *row; - int ret = osl(osl_get_nth_row(score_table, SCORECOL_SCORE, n, &row)); - - if (ret < 0) - return ret; - return get_score_of_row(row, score); -} - /** * Replace a row of the score table. * @@ -156,7 +134,7 @@ static int get_nth_score(unsigned n, long *score) */ int score_update(const struct osl_row *aft_row, long percent) { - struct osl_row *row; + struct osl_row *row, *rrow; /* score row, reference row */ long new_score; unsigned n, new_pos; struct osl_object obj = {.data = (struct osl_row *)aft_row, @@ -167,11 +145,14 @@ int score_update(const struct osl_row *aft_row, long percent) return 1; if (ret < 0) return ret; - ret = get_num_admissible_files(&n); + ret = osl(osl_get_num_rows(score_table, &n)); if (ret < 0) return ret; new_pos = 1 + (n - 1) * percent / 100; - ret = get_nth_score(new_pos, &new_score); + ret = osl(osl_get_nth_row(score_table, SCORECOL_SCORE, new_pos, &rrow)); + if (ret < 0) + return ret; + ret = get_score_of_row(rrow, &new_score); if (ret < 0) return ret; new_score--; @@ -215,17 +196,15 @@ static int get_score_row_from_aft_row(const struct osl_row *aft_row, } /** - * Loop over all files in the score table. - * - * \param data A pointer to arbitrary data. - * \param func Function to be called for each admissible file. + * Call the given function for each row of the score table. * - * \return The return value of the underlying call to osl_rbtree_loop(). + * \param func Callback, called once per row. + * \param data Passed verbatim to the callback. * - * This is used for the ls command. The \a data parameter is passed as the - * second argument to \a func. + * \return The return value of the underlying call to osl_rbtree_loop(). The + * loop terminates early if the callback returns negative. */ -int admissible_file_loop(void *data, osl_rbtree_loop_func *func) +int score_loop(osl_rbtree_loop_func *func, void *data) { return osl(osl_rbtree_loop(score_table, SCORECOL_SCORE, data, func)); } @@ -276,27 +255,20 @@ int score_delete(const struct osl_row *aft_row) * Find out whether an audio file is contained in the score table. * * \param aft_row The row of the audio file table. - * \param rank Result pointer * - * \return Positive, if \a aft_row belongs to the audio file table, - * zero if not, negative on errors. If \a aft_row was found, and \a rank - * is not \p NULL, the rank of \a aft_row is returned in \a rank. + * \return If the lookup operation fails for any other reason than "not found", + * the function aborts the current process (afs), since this is considered a + * fatal error that should never happen. */ -int row_belongs_to_score_table(const struct osl_row *aft_row, unsigned *rank) +bool row_belongs_to_score_table(const struct osl_row *aft_row) { struct osl_row *score_row; int ret = get_score_row_from_aft_row(aft_row, &score_row); if (ret == -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND)) - return 0; - if (ret < 0) - return ret; - if (!rank) - return 1; - ret = osl(osl_get_rank(score_table, score_row, SCORECOL_SCORE, rank)); - if (ret < 0) - return ret; - return 1; + return false; + assert(ret >= 0); + return true; } static void score_close(void) @@ -307,36 +279,21 @@ static void score_close(void) static int score_open(__a_unused const char *dir) { - score_table_desc.dir = NULL; /* this table has only volatile columns */ - return osl(osl_open_table(&score_table_desc, &score_table)); + assert(osl_open_table(&score_table_desc, &score_table) >= 0); + return 1; } /** * Remove all entries from the score table, but keep the table open. - * - * \return Standard. */ -int clear_score_table(void) +void score_clear(void) { score_close(); - return score_open(NULL); + score_open(NULL); } -static int score_event_handler(__a_unused enum afs_events event, - __a_unused struct para_buffer *pb, __a_unused void *data) -{ - return 1; -} - -/** - * Initialize the scoring subsystem. - * - * \param t The members of \a t are filled in by the function. - */ -void score_init(struct afs_table *t) -{ - t->name = score_table_desc.name; - t->open = score_open; - t->close = score_close; - t->event_handler = score_event_handler; -} +/** The score table stores (aft row, score) pairs in memory. */ +const struct afs_table_operations score_ops = { + .open = score_open, + .close = score_close, +}; diff --git a/signal.c b/signal.c index bdafeaf2..d9a6aa37 100644 --- a/signal.c +++ b/signal.c @@ -72,10 +72,13 @@ static void generic_signal_handler(int s) errno = save_errno; return; } - if (ret < 0) - PARA_EMERG_LOG("%s\n", strerror(errno)); - else - PARA_EMERG_LOG("short write to signal pipe\n"); + /* + * This is a fatal error which should never happen. We must not call + * PARA_XXX_LOG() here because this might acquire the log mutex which + * is already taken by the main program if the interrupt occurs while a + * log message is being printed. The mutex will not be released as long + * as this signal handler is running, so a deadlock ensues. + */ exit(EXIT_FAILURE); } diff --git a/udp_recv.c b/udp_recv.c index 8d1274bc..365b6863 100644 --- a/udp_recv.c +++ b/udp_recv.c @@ -168,7 +168,7 @@ static int udp_recv_open(struct receiver_node *rn) uint32_t port = RECV_CMD_OPT_UINT32_VAL(UDP, PORT, lpr); int ret; - ret = makesock(IPPROTO_UDP, 1, host, port, NULL); + ret = makesock(IPPROTO_UDP, true /* passive */, host, port, NULL); if (ret < 0) return ret; rn->fd = ret; diff --git a/udp_send.c b/udp_send.c index 28947987..fe001025 100644 --- a/udp_send.c +++ b/udp_send.c @@ -187,7 +187,7 @@ static int udp_resolve_target(const char *url, struct sender_command_data *scd) return ret; port = scd->port > 0 ? scd->port : OPT_UINT32_VAL(UDP_DEFAULT_PORT); - ret = para_connect_simple(IPPROTO_UDP, scd->host, port); + ret = para_connect(IPPROTO_UDP, scd->host, port); if (ret < 0) return ret; @@ -336,7 +336,7 @@ static int udp_com_add(struct sender_command_data *scd) sc->private_data = ut; sc->fd = -1; - ret = para_connect_simple(IPPROTO_UDP, scd->host, scd->port); + ret = para_connect(IPPROTO_UDP, scd->host, scd->port); if (ret < 0) goto err; sc->fd = ret; diff --git a/vss.c b/vss.c index dd4ac2fb..cd55851c 100644 --- a/vss.c +++ b/vss.c @@ -1014,13 +1014,8 @@ err: } /** - * Main sending function. - * - * This function gets called from vss_post_monitor(). It checks whether the next - * chunk of data should be pushed out. It obtains a pointer to the data to be - * sent out as well as its length from mmd->afd.afhi. This information is then - * passed to each supported sender's send() function as well as to the send() - * functions of each registered fec client. + * If the next chunk needs to be sent, pass a pointer to the chunk data to all + * registered fec clients and to each sender's ->send() method. */ static void vss_send(struct vss_task *vsst) {