From: Andre Noll Date: Sun, 4 Mar 2012 21:40:27 +0000 (+0100) Subject: Merge branch 't/audioc_cleanups' X-Git-Tag: v0.4.10~8 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=0703f75a276020f9645f987134d49402f7c019c0;hp=e83cbfdcc9f5671cab0b1dae5cb81b956d0ab5ce Merge branch 't/audioc_cleanups' Has been cooking for long enough. --- diff --git a/NEWS b/NEWS index 16e8e4e8..d9e0d0a3 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,16 @@ 0.4.10 (to be announced) "heterogeneous vacuum" ----------------------------------------------- + - The --no_default_filters option of para_filter has been + depricated. It still works but has no effect and will be + removed in the next version. + - Cleanup and consolidation of the various wrappers for + write(), writev(), send() and friends. + - The obscure error messages on mmap() failures have been + replaced by meaningful messages. This affects mainly + para_afh. + - para_audioc: Cleanups and memory leak fixes. + ------------------------------------- 0.4.9 (2011-12-06) "hybrid causality" ------------------------------------- diff --git a/afh.c b/afh.c index f2745b61..bffe6321 100644 --- a/afh.c +++ b/afh.c @@ -124,7 +124,7 @@ static int cat_file(struct afh_info *afhi, int audio_format_id, &header, &size); if (size > 0) { PARA_INFO_LOG("writing header (%zu bytes)\n", size); - ret = write(STDOUT_FILENO, header, size); /* FIXME */ + ret = write_all(STDOUT_FILENO, header, size); afh_free_header(header, audio_format_id); if (ret < 0) return ret; @@ -152,7 +152,7 @@ static int cat_file(struct afh_info *afhi, int audio_format_id, if (!size) continue; PARA_INFO_LOG("writing chunk %lu\n", i); - ret = write_all(STDOUT_FILENO, buf, &size); + ret = write_all(STDOUT_FILENO, buf, size); if (ret < 0) return ret; } @@ -187,8 +187,10 @@ int main(int argc, char **argv) int ret2; ret = mmap_full_file(conf.inputs[i], O_RDONLY, &audio_file_data, &audio_file_size, &fd); - if (ret < 0) + if (ret < 0) { + PARA_ERROR_LOG("failed to mmap \"%s\"\n", conf.inputs[i]); goto out; + } ret = compute_afhi(conf.inputs[i], audio_file_data, audio_file_size, fd, &afhi); if (ret < 0) diff --git a/afs.c b/afs.c index 263f1818..5939cbe6 100644 --- a/afs.c +++ b/afs.c @@ -26,6 +26,7 @@ #include "signal.h" #include "fd.h" #include "mood.h" +#include "command.h" /** The osl tables used by afs. \sa blob.c. */ enum afs_table_num { @@ -233,7 +234,7 @@ int send_callback_request(callback_function *f, struct osl_object *query, if (ret < 0) goto out; fd = ret; - ret = send_bin_buffer(fd, buf, sizeof(buf)); + ret = write_all(fd, buf, sizeof(buf)); if (ret < 0) goto out; /* @@ -495,7 +496,7 @@ destroy: no_admissible_files: *(uint32_t *)buf = NO_ADMISSIBLE_FILES; *(uint32_t *)(buf + 4) = (uint32_t)0; - return send_bin_buffer(server_socket, buf, 8); + return write_all(server_socket, buf, 8); } /* Never fails if arg == NULL */ @@ -592,23 +593,27 @@ out: */ int sc_send_result(struct osl_object *result, void *private) { - struct stream_cipher_context *scc = private; + struct command_context *cc = private; + int ret; if (!result->size) return 1; - return sc_send_bin_buffer(scc, result->data, result->size); + ret = sc_send_bin_buffer(&cc->scc, result->data, result->size); + if (ret < 0 || ret == result->size) + return ret; + return -E_SHORT_WRITE; } -int com_select(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_select(struct command_context *cc) { struct osl_object query; - if (argc != 2) + if (cc->argc != 2) return -E_AFS_SYNTAX; - query.data = argv[1]; - query.size = strlen(argv[1]) + 1; + query.data = cc->argv[1]; + query.size = strlen(cc->argv[1]) + 1; return send_callback_request(com_select_callback, &query, - &sc_send_result, scc); + &sc_send_result, cc); } static void init_admissible_files(char *arg) @@ -814,7 +819,7 @@ int pass_buffer_as_shm(char *buf, size_t size, void *fd_ptr) ret = shm_detach(shm); if (ret < 0) goto err; - ret = send_bin_buffer(fd, (char *)&shmid, sizeof(int)); + ret = write_all(fd, (char *)&shmid, sizeof(int)); if (ret >= 0) return ret; err: @@ -1022,7 +1027,7 @@ out: free(pb.buf); } -int com_init(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_init(struct command_context *cc) { int i, j, ret; uint32_t table_mask = (1 << (NUM_AFS_TABLES + 1)) - 1; @@ -1032,13 +1037,13 @@ int com_init(struct stream_cipher_context *scc, int argc, char * const * const a ret = make_database_dir(); if (ret < 0) return ret; - if (argc != 1) { + if (cc->argc != 1) { table_mask = 0; - for (i = 1; i < argc; i++) { + for (i = 1; i < cc->argc; i++) { for (j = 0; j < NUM_AFS_TABLES; j++) { struct afs_table *t = &afs_tables[j]; - if (strcmp(argv[i], t->name)) + if (strcmp(cc->argv[i], t->name)) continue; table_mask |= (1 << j); break; @@ -1048,10 +1053,10 @@ int com_init(struct stream_cipher_context *scc, int argc, char * const * const a } } ret = send_callback_request(create_tables_callback, &query, - sc_send_result, scc); + sc_send_result, cc); if (ret < 0) /* ignore return value */ - sc_send_va_buffer(scc, "%s\n", para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret)); return ret; } @@ -1069,13 +1074,13 @@ enum com_check_flags { CHECK_PLAYLISTS = 4 }; -int com_check(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_check(struct command_context *cc) { unsigned flags = 0; int i, ret; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + for (i = 1; i < cc->argc; i++) { + const char *arg = cc->argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { @@ -1096,25 +1101,25 @@ int com_check(struct stream_cipher_context *scc, int argc, char * const * const } return -E_AFS_SYNTAX; } - if (i < argc) + if (i < cc->argc) return -E_AFS_SYNTAX; if (!flags) flags = ~0U; if (flags & CHECK_AFT) { ret = send_callback_request(aft_check_callback, NULL, - sc_send_result, scc); + sc_send_result, cc); if (ret < 0) return ret; } if (flags & CHECK_PLAYLISTS) { ret = send_callback_request(playlist_check_callback, - NULL, sc_send_result, scc); + NULL, sc_send_result, cc); if (ret < 0) return ret; } if (flags & CHECK_MOODS) { ret = send_callback_request(mood_check_callback, NULL, - sc_send_result, scc); + sc_send_result, cc); if (ret < 0) return ret; } diff --git a/afs.cmd b/afs.cmd index 22a0786b..c7808040 100644 --- a/afs.cmd +++ b/afs.cmd @@ -260,7 +260,7 @@ H: loads the mood named 'foo'. --- T: add N: add@member@ -O: int com_add@member@(struct stream_cipher_context *scc, int argc, char * const * const argv); +O: int com_add@member@(struct command_context *cc); P: AFS_READ | AFS_WRITE D: Read data from stdin and add it as a blob to the @member@ table. U: add@member@ @member@_name @@ -273,7 +273,7 @@ H: given name already exists, its contents are replaced by the new data. --- T: cat N: cat@member@ -O: int com_cat@member@(struct stream_cipher_context *scc, int argc, char * const * const argv); +O: int com_cat@member@(struct command_context *cc); P: AFS_READ D: Dump the contents of a blob of type @member@ to stdout. U: cat@member@ @member@_name @@ -283,7 +283,7 @@ H: they were previously added. --- T: ls N: ls@member@ -O: int com_ls@member@(struct stream_cipher_context *scc, int argc, char * const * const argv); +O: int com_ls@member@(struct command_context *cc); P: AFS_READ D: List blobs of type @member@ matching a pattern. U: ls@member@ [-i] [-l] [-r] [pattern] @@ -303,7 +303,7 @@ H: -r Reverse sort order. --- T: rm N: rm@member@ -O: int com_rm@member@(struct stream_cipher_context *scc, int argc, char * const * const argv); +O: int com_rm@member@(struct command_context *cc); P: AFS_READ | AFS_WRITE D: Remove blob(s) of type @member@ from the @member@ table. U: rm@member@ pattern... @@ -312,7 +312,7 @@ H: any given pattern. --- T: mv N: mv@member@ -O: int com_mv@member@(struct stream_cipher_context *scc, int argc, char * const * const argv); +O: int com_mv@member@(struct command_context *cc); P: AFS_READ | AFS_WRITE D: Rename a blob of type @member@. U: mv@member@ old_@member@_name new_@member@_name diff --git a/aft.c b/aft.c index 9d87c748..f89235a4 100644 --- a/aft.c +++ b/aft.c @@ -21,6 +21,7 @@ #include "fd.h" #include "ipc.h" #include "portable_io.h" +#include "command.h" static struct osl_table *audio_file_table; static char *status_items; @@ -1402,7 +1403,7 @@ out: /* * TODO: flags -h (sort by hash) */ -int com_ls(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_ls(struct command_context *cc) { int i, ret; unsigned flags = 0; @@ -1411,8 +1412,8 @@ int com_ls(struct stream_cipher_context *scc, int argc, char * const * const arg struct ls_options opts = {.patterns = NULL}; struct osl_object query = {.data = &opts, .size = sizeof(opts)}; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + for (i = 1; i < cc->argc; i++) { + const char *arg = cc->argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { @@ -1512,9 +1513,9 @@ int com_ls(struct stream_cipher_context *scc, int argc, char * const * const arg opts.flags = flags; opts.sorting = sort; opts.mode = mode; - opts.num_patterns = argc - i; + opts.num_patterns = cc->argc - i; ret = send_option_arg_callback_request(&query, opts.num_patterns, - argv + i, com_ls_callback, sc_send_result, scc); + cc->argv + i, com_ls_callback, sc_send_result, cc); return ret; } @@ -1801,8 +1802,8 @@ out: /** Used by com_add(). */ struct private_add_data { - /** The socket file descriptor, including stream cipher keys. */ - struct stream_cipher_context *scc; + /** The pointer passed to the original command handler. */ + struct command_context *cc; /** The given add flags. */ uint32_t flags; }; @@ -1857,7 +1858,7 @@ static int add_one_audio_file(const char *path, void *private_data) ret = 1; if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */ if (pad->flags & ADD_FLAG_VERBOSE) - send_ret = sc_send_va_buffer(pad->scc, + send_ret = sc_send_va_buffer(&pad->cc->scc, "lazy-ignore: %s\n", path); goto out_free; } @@ -1878,7 +1879,7 @@ static int add_one_audio_file(const char *path, void *private_data) ret = 1; if (pb && hs && hs == pb && !(pad->flags & ADD_FLAG_FORCE)) { if (pad->flags & ADD_FLAG_VERBOSE) - send_ret = sc_send_va_buffer(pad->scc, + send_ret = sc_send_va_buffer(&pad->cc->scc, "%s exists, not forcing update\n", path); goto out_unmap; } @@ -1896,13 +1897,13 @@ static int add_one_audio_file(const char *path, void *private_data) munmap(map.data, map.size); close(fd); if (pad->flags & ADD_FLAG_VERBOSE) { - send_ret = sc_send_va_buffer(pad->scc, "adding %s\n", path); + send_ret = sc_send_va_buffer(&pad->cc->scc, "adding %s\n", path); if (send_ret < 0) goto out_free; } save_add_callback_buffer(hash, path, afhi_ptr, pad->flags, format_num, &obj); /* Ask afs to consider this entry for adding. */ - ret = send_callback_request(com_add_callback, &obj, sc_send_result, pad->scc); + ret = send_callback_request(com_add_callback, &obj, sc_send_result, pad->cc); goto out_free; out_unmap: @@ -1910,7 +1911,7 @@ out_unmap: munmap(map.data, map.size); out_free: if (ret < 0 && send_ret >= 0) - send_ret = sc_send_va_buffer(pad->scc, + send_ret = sc_send_va_buffer(&pad->cc->scc, "failed to add %s (%s)\n", path, para_strerror(-ret)); free(obj.data); if (afhi_ptr) { @@ -1926,14 +1927,14 @@ out_free: return send_ret; } -int com_add(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_add(struct command_context *cc) { int i, ret; - struct private_add_data pad = {.scc = scc, .flags = 0}; + struct private_add_data pad = {.cc = cc, .flags = 0}; struct stat statbuf; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + for (i = 1; i < cc->argc; i++) { + const char *arg = cc->argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { @@ -1957,21 +1958,22 @@ int com_add(struct stream_cipher_context *scc, int argc, char * const * const ar continue; } } - if (argc <= i) + if (cc->argc <= i) return -E_AFT_SYNTAX; - for (; i < argc; i++) { + for (; i < cc->argc; i++) { char *path; - ret = verify_path(argv[i], &path); + ret = verify_path(cc->argv[i], &path); if (ret < 0) { - ret = sc_send_va_buffer(scc, "%s: %s\n", argv[i], - para_strerror(-ret)); + ret = sc_send_va_buffer(&cc->scc, "%s: %s\n", + cc->argv[i], para_strerror(-ret)); if (ret < 0) return ret; continue; } ret = stat(path, &statbuf); if (ret < 0) { - ret = sc_send_va_buffer(scc, "failed to stat %s (%s)\n", path, + ret = sc_send_va_buffer(&cc->scc, + "failed to stat %s (%s)\n", path, strerror(errno)); free(path); if (ret < 0) @@ -1984,7 +1986,8 @@ int com_add(struct stream_cipher_context *scc, int argc, char * const * const ar else ret = add_one_audio_file(path, &pad); if (ret < 0) { - sc_send_va_buffer(scc, "%s: %s\n", path, para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s: %s\n", path, + para_strerror(-ret)); free(path); return ret; } @@ -2112,7 +2115,7 @@ static void com_touch_callback(int fd, const struct osl_object *query) free(tad.pb.buf); } -int com_touch(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_touch(struct command_context *cc) { struct com_touch_options cto = { .num_played = -1, @@ -2125,8 +2128,8 @@ int com_touch(struct stream_cipher_context *scc, int argc, char * const * const int i, ret; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + for (i = 1; i < cc->argc; i++) { + const char *arg = cc->argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { @@ -2177,12 +2180,12 @@ int com_touch(struct stream_cipher_context *scc, int argc, char * const * const } break; /* non-option starting with dash */ } - if (i >= argc) + if (i >= cc->argc) return -E_AFT_SYNTAX; - ret = send_option_arg_callback_request(&query, argc - i, - argv + i, com_touch_callback, sc_send_result, scc); + ret = send_option_arg_callback_request(&query, cc->argc - i, + cc->argv + i, com_touch_callback, sc_send_result, cc); if (ret < 0) - sc_send_va_buffer(scc, "%s\n", para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret)); return ret; } @@ -2260,14 +2263,14 @@ static void com_rm_callback(int fd, const struct osl_object *query) } /* TODO options: -r (recursive) */ -int com_rm(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_rm(struct command_context *cc) { uint32_t flags = 0; struct osl_object query = {.data = &flags, .size = sizeof(flags)}; int i, ret; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + for (i = 1; i < cc->argc; i++) { + const char *arg = cc->argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { @@ -2288,12 +2291,12 @@ int com_rm(struct stream_cipher_context *scc, int argc, char * const * const ar } break; } - if (i >= argc) + if (i >= cc->argc) return -E_AFT_SYNTAX; - ret = send_option_arg_callback_request(&query, argc - i, argv + i, - com_rm_callback, sc_send_result, scc); + ret = send_option_arg_callback_request(&query, cc->argc - i, + cc->argv + i, com_rm_callback, sc_send_result, cc); if (ret < 0) - sc_send_va_buffer(scc, "%s\n", para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret)); return ret; } @@ -2405,14 +2408,14 @@ out: free(cad.pb.buf); } -int com_cpsi(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_cpsi(struct command_context *cc) { unsigned flags = 0; int i, ret; struct osl_object options = {.data = &flags, .size = sizeof(flags)}; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + for (i = 1; i < cc->argc; i++) { + const char *arg = cc->argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { @@ -2445,14 +2448,14 @@ int com_cpsi(struct stream_cipher_context *scc, int argc, char * const * const } break; } - if (i + 1 >= argc) /* need at least source file and pattern */ + if (i + 1 >= cc->argc) /* need at least source file and pattern */ return -E_AFT_SYNTAX; if (!(flags & ~CPSI_FLAG_VERBOSE)) /* no copy flags given */ flags = ~(unsigned)CPSI_FLAG_VERBOSE | flags; - ret = send_option_arg_callback_request(&options, argc - i, argv + i, - com_cpsi_callback, sc_send_result, scc); + ret = send_option_arg_callback_request(&options, cc->argc - i, + cc->argv + i, com_cpsi_callback, sc_send_result, cc); if (ret < 0) - sc_send_va_buffer(scc, "%s\n", para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret)); return ret; } @@ -2470,7 +2473,7 @@ static void afs_stat_callback(int fd, const struct osl_object *query) /** * Get the current afs status items from the afs process and send it. * - * \param scc The stream cipher context for data encryption. + * \param cc The command context, used e.g. for data encryption. * \param parser_friendly Whether parser-friendly output format should be used. * * As the contents of the afs status items change in time and the command @@ -2481,12 +2484,12 @@ static void afs_stat_callback(int fd, const struct osl_object *query) * * \return The return value of the underyling call to \ref send_callback_request(). */ -int send_afs_status(struct stream_cipher_context *scc, int parser_friendly) +int send_afs_status(struct command_context *cc, int parser_friendly) { struct osl_object query = {.data = &parser_friendly, .size = sizeof(parser_friendly)}; - return send_callback_request(afs_stat_callback, &query, sc_send_result, scc); + return send_callback_request(afs_stat_callback, &query, sc_send_result, cc); } /* TODO: optionally fix problems by removing offending rows */ diff --git a/attribute.c b/attribute.c index b56a9574..19700944 100644 --- a/attribute.c +++ b/attribute.c @@ -16,6 +16,7 @@ #include "afh.h" #include "afs.h" #include "ipc.h" +#include "command.h" static struct osl_table *attribute_table; static int greatest_att_bitnum; @@ -175,14 +176,14 @@ static void com_lsatt_callback(int fd, const struct osl_object *query) free(laad.pb.buf); } -int com_lsatt(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_lsatt(struct command_context *cc) { unsigned flags = 0; struct osl_object options = {.data = &flags, .size = sizeof(flags)}; int ret, i; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + for (i = 1; i < cc->argc; i++) { + const char *arg = cc->argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { @@ -202,13 +203,13 @@ int com_lsatt(struct stream_cipher_context *scc, int argc, char * const * const continue; } } - ret = send_option_arg_callback_request(&options, argc - i, argv + i, - com_lsatt_callback, sc_send_result, scc); + ret = send_option_arg_callback_request(&options, cc->argc - i, cc->argv + i, + com_lsatt_callback, sc_send_result, cc); if (!ret) { - if (argc > 1) - ret = sc_send_va_buffer(scc, "no matches\n"); + if (cc->argc > 1) + ret = sc_send_va_buffer(&cc->scc, "no matches\n"); } else if (ret < 0) - sc_send_va_buffer(scc, "%s\n", para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret)); return ret; } @@ -276,12 +277,12 @@ out: PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); } -int com_setatt(__a_unused struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_setatt(struct command_context *cc) { - if (argc < 3) + if (cc->argc < 3) return -E_ATTR_SYNTAX; - return send_standard_callback_request(argc - 1, argv + 1, com_setatt_callback, - NULL, NULL); + return send_standard_callback_request(cc->argc - 1, cc->argv + 1, + com_setatt_callback, NULL, NULL); } struct addatt_event_data { @@ -357,16 +358,16 @@ out: free(pb.buf); } -int com_addatt(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_addatt(struct command_context *cc) { int ret; - if (argc < 2) + if (cc->argc < 2) return -E_ATTR_SYNTAX; - ret = send_standard_callback_request(argc - 1, argv + 1, com_addatt_callback, - sc_send_result, scc); + ret = send_standard_callback_request(cc->argc - 1, cc->argv + 1, + com_addatt_callback, sc_send_result, cc); if (ret < 0) - sc_send_va_buffer(scc, "%s\n", para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret)); return ret; } @@ -400,16 +401,16 @@ out: free(pb.buf); } -int com_mvatt(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_mvatt(struct command_context *cc) { int ret; - if (argc != 3) + if (cc->argc != 3) return -E_ATTR_SYNTAX; - ret = send_standard_callback_request(argc - 1, argv + 1, com_mvatt_callback, - sc_send_result, scc); + ret = send_standard_callback_request(cc->argc - 1, cc->argv + 1, + com_mvatt_callback, sc_send_result, cc); if (ret < 0) - sc_send_va_buffer(scc, "%s\n", para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret)); return ret; } @@ -472,16 +473,16 @@ static void com_rmatt_callback(int fd, const struct osl_object *query) free(raad.pb.buf); } -int com_rmatt(struct stream_cipher_context *scc, int argc, char * const * const argv) +int com_rmatt(struct command_context *cc) { int ret; - if (argc < 2) + if (cc->argc < 2) return -E_ATTR_SYNTAX; - ret = send_standard_callback_request(argc - 1, argv + 1, com_rmatt_callback, - sc_send_result, scc); + ret = send_standard_callback_request(cc->argc - 1, cc->argv + 1, + com_rmatt_callback, sc_send_result, cc); if (ret < 0) - sc_send_va_buffer(scc, "%s\n", para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret)); return ret; } diff --git a/audioc.c b/audioc.c index 09b21ba9..d3e092e2 100644 --- a/audioc.c +++ b/audioc.c @@ -341,7 +341,7 @@ int main(int argc, char *argv[]) size_t n = ret = recv_bin_buffer(fd, buf, bufsize); if (ret <= 0) break; - ret = write_all(STDOUT_FILENO, buf, &n); + ret = write_all(STDOUT_FILENO, buf, n); } while (ret >= 0); out: free(buf); diff --git a/audiod.c b/audiod.c index a78757b6..d7765e21 100644 --- a/audiod.c +++ b/audiod.c @@ -918,8 +918,10 @@ static int parse_filter_args(void) { int i, j, ret, af_mask; - if (!conf.no_default_filters_given) - return init_default_filters(); + if (conf.no_default_filters_given) { + PARA_WARNING_LOG("--no_default_filters is deprecated\n"); + PARA_WARNING_LOG("It has no effect and will be removed soon\n"); + } for (i = 0; i < conf.filter_given; i++) { char *arg; ret = parse_stream_command(conf.filter_arg[i], &arg); diff --git a/blob.c b/blob.c index ee4e405e..409e3487 100644 --- a/blob.c +++ b/blob.c @@ -18,6 +18,7 @@ #include "afs.h" #include "ipc.h" #include "portable_io.h" +#include "command.h" /** * Compare two osl objects pointing to unsigned integers of 32 bit size. @@ -163,14 +164,14 @@ static void com_lsblob_callback(struct osl_table *table, free(lbad.pb.buf); } -static int com_lsblob(callback_function *f, struct stream_cipher_context *scc, int argc, char * const * const argv) +static int com_lsblob(callback_function *f, struct command_context *cc) { uint32_t flags = 0; struct osl_object options = {.data = &flags, .size = sizeof(flags)}; int i; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + for (i = 1; i < cc->argc; i++) { + const char *arg = cc->argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { @@ -193,8 +194,8 @@ static int com_lsblob(callback_function *f, struct stream_cipher_context *scc, i } // if (argc > i) // return -E_BLOB_SYNTAX; - return send_option_arg_callback_request(&options, argc - i, - argv + i, f, sc_send_result, scc); + return send_option_arg_callback_request(&options, cc->argc - i, + cc->argv + i, f, sc_send_result, cc); } static int cat_blob(struct osl_table *table, struct osl_row *row, @@ -231,13 +232,12 @@ static void com_catblob_callback(struct osl_table *table, int fd, } } -static int com_catblob(callback_function *f, struct stream_cipher_context *scc, int argc, - char * const * const argv) +static int com_catblob(callback_function *f, struct command_context *cc) { - if (argc < 2) + if (cc->argc < 2) return -E_BLOB_SYNTAX; - return send_standard_callback_request(argc - 1, argv + 1, f, - sc_send_result, scc); + return send_standard_callback_request(cc->argc - 1, cc->argv + 1, f, + sc_send_result, cc); } /** Used for removing rows from a blob table. */ @@ -296,13 +296,12 @@ out: free(rmbd.pb.buf); } -static int com_rmblob(callback_function *f, struct stream_cipher_context *scc, int argc, - char * const * const argv) +static int com_rmblob(callback_function *f, struct command_context *cc) { - if (argc < 2) + if (cc->argc < 2) return -E_MOOD_SYNTAX; - return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f, - sc_send_result, scc); + return send_option_arg_callback_request(NULL, cc->argc - 1, cc->argv + 1, f, + sc_send_result, cc); } static void com_addblob_callback(struct osl_table *table, __a_unused int fd, @@ -425,7 +424,7 @@ static int fd2buf(struct stream_cipher_context *scc, unsigned max_size, struct o * \return Negative on errors, the return value of the underlying call to * send_callback_request() otherwise. */ -static int stdin_command(struct stream_cipher_context *scc, struct osl_object *arg_obj, +static int stdin_command(struct command_context *cc, struct osl_object *arg_obj, callback_function *f, unsigned max_len, callback_result_handler *result_handler, void *private_result_data) @@ -433,10 +432,10 @@ static int stdin_command(struct stream_cipher_context *scc, struct osl_object *a struct osl_object query, stdin_obj; int ret; - ret = sc_send_buffer(scc, AWAITING_DATA_MSG); + ret = sc_send_buffer(&cc->scc, AWAITING_DATA_MSG); if (ret < 0) return ret; - ret = fd2buf(scc, max_len, &stdin_obj); + ret = fd2buf(&cc->scc, max_len, &stdin_obj); if (ret < 0) return ret; query.size = arg_obj->size + stdin_obj.size; @@ -449,18 +448,17 @@ static int stdin_command(struct stream_cipher_context *scc, struct osl_object *a return ret; } -static int com_addblob(callback_function *f, struct stream_cipher_context *scc, int argc, - char * const * const argv) +static int com_addblob(callback_function *f, struct command_context *cc) { struct osl_object arg_obj; - if (argc != 2) + if (cc->argc != 2) return -E_BLOB_SYNTAX; - if (!*argv[1]) /* empty name is reserved for the dummy row */ + if (!*cc->argv[1]) /* empty name is reserved for the dummy row */ return -E_BLOB_SYNTAX; - arg_obj.size = strlen(argv[1]) + 1; - arg_obj.data = (char *)argv[1]; - return stdin_command(scc, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL); + arg_obj.size = strlen(cc->argv[1]) + 1; + arg_obj.data = (char *)cc->argv[1]; + return stdin_command(cc, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL); } /* FIXME: Print output to client, not to log file */ @@ -486,13 +484,12 @@ out: PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); } -static int com_mvblob(callback_function *f, __a_unused struct stream_cipher_context *scc, - int argc, char * const * const argv) +static int com_mvblob(callback_function *f, struct command_context *cc) { - if (argc != 3) + if (cc->argc != 3) return -E_MOOD_SYNTAX; - return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f, - NULL, NULL); + return send_option_arg_callback_request(NULL, cc->argc - 1, + cc->argv + 1, f, NULL, NULL); } #define DEFINE_BLOB_COMMAND(cmd_name, table_name, cmd_prefix) \ @@ -500,9 +497,9 @@ static int com_mvblob(callback_function *f, __a_unused struct stream_cipher_cont { \ return com_ ## cmd_name ## blob_callback(table_name ## _table, fd, query); \ } \ - int com_ ## cmd_name ## cmd_prefix(struct stream_cipher_context *scc, int argc, char * const * const argv) \ + int com_ ## cmd_name ## cmd_prefix(struct command_context *cc) \ { \ - return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, scc, argc, argv); \ + return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, cc); \ } static int blob_get_name_by_id(struct osl_table *table, uint32_t id, diff --git a/client_common.c b/client_common.c index bb421e3a..5bd2241b 100644 --- a/client_common.c +++ b/client_common.c @@ -188,7 +188,7 @@ static void client_post_select(struct sched *s, struct task *t) PARA_INFO_LOG("--> %s\n", buf); if (!FD_ISSET(ct->scc.fd, &s->wfds)) return; - ret = send_buffer(ct->scc.fd, buf); + ret = write_buffer(ct->scc.fd, buf); if (ret < 0) goto out; ct->status = CL_SENT_AUTH; @@ -218,8 +218,7 @@ static void client_post_select(struct sched *s, struct task *t) SESSION_KEY_LEN); hash_to_asc(challenge_hash, buf); PARA_INFO_LOG("--> %s\n", buf); - ret = send_bin_buffer(ct->scc.fd, (char *)challenge_hash, - HASH_SIZE); + ret = write_all(ct->scc.fd, (char *)challenge_hash, HASH_SIZE); if (ret < 0) goto out; ct->status = CL_SENT_CH_RESPONSE; diff --git a/command.c b/command.c index f194a7c1..4a464ebf 100644 --- a/command.c +++ b/command.c @@ -41,7 +41,7 @@ extern int mmd_mutex; extern struct misc_meta_data *mmd; extern struct sender senders[]; -int send_afs_status(struct stream_cipher_context *scc, int parser_friendly); +int send_afs_status(struct command_context *cc, int parser_friendly); const char *status_item_list[] = {STATUS_ITEM_ARRAY}; @@ -193,29 +193,29 @@ static int check_sender_args(int argc, char * const * argv, struct sender_comman return 1; } -int com_sender(struct stream_cipher_context *scc, int argc, char * const * argv) +int com_sender(struct command_context *cc) { int i, ret; char *msg = NULL; struct sender_command_data scd; - if (argc < 2) { + if (cc->argc < 2) { for (i = 0; senders[i].name; i++) { char *tmp = make_message("%s%s\n", msg? msg : "", senders[i].name); free(msg); msg = tmp; } - ret = sc_send_buffer(scc, msg); + ret = sc_send_buffer(&cc->scc, msg); free(msg); return ret; } - ret = check_sender_args(argc, argv, &scd); + ret = check_sender_args(cc->argc, cc->argv, &scd); if (ret < 0) { if (scd.sender_num < 0) return ret; msg = senders[scd.sender_num].help(); - ret = sc_send_buffer(scc, msg); + ret = sc_send_buffer(&cc->scc, msg); free(msg); return ret; } @@ -224,7 +224,7 @@ int com_sender(struct stream_cipher_context *scc, int argc, char * const * argv) case SENDER_ADD: case SENDER_DELETE: assert(senders[scd.sender_num].resolve_target); - ret = senders[scd.sender_num].resolve_target(argv[3], &scd); + ret = senders[scd.sender_num].resolve_target(cc->argv[3], &scd); if (ret < 0) return ret; } @@ -244,13 +244,13 @@ int com_sender(struct stream_cipher_context *scc, int argc, char * const * argv) } /* server info */ -int com_si(struct stream_cipher_context *scc, int argc, __a_unused char * const * argv) +int com_si(struct command_context *cc) { int i, ret; char *ut; char *sender_info = NULL; - if (argc != 1) + if (cc->argc != 1) return -E_COMMAND_SYNTAX; mutex_lock(mmd_mutex); for (i = 0; senders[i].name; i++) { @@ -259,7 +259,7 @@ int com_si(struct stream_cipher_context *scc, int argc, __a_unused char * const free(info); } ut = get_server_uptime_str(now); - ret = sc_send_va_buffer(scc, "version: " GIT_VERSION "\n" + ret = sc_send_va_buffer(&cc->scc, "version: " GIT_VERSION "\n" "up: %s\nplayed: %u\n" "server_pid: %d\n" "afs_pid: %d\n" @@ -284,11 +284,11 @@ int com_si(struct stream_cipher_context *scc, int argc, __a_unused char * const } /* version */ -int com_version(struct stream_cipher_context *scc, int argc, __a_unused char * const * argv) +int com_version(struct command_context *cc) { - if (argc != 1) + if (cc->argc != 1) return -E_COMMAND_SYNTAX; - return sc_send_buffer(scc, VERSION_TEXT("server") + return sc_send_buffer(&cc->scc, VERSION_TEXT("server") "built: " BUILD_DATE "\n" UNAME_RS ", " CC_VERSION "\n" ); @@ -350,7 +350,7 @@ static char *empty_status_items(int parser_friendly) #undef EMPTY_STATUS_ITEMS /* stat */ -int com_stat(struct stream_cipher_context *scc, int argc, char * const * argv) +int com_stat(struct command_context *cc) { int i, ret; struct misc_meta_data tmp, *nmmd = &tmp; @@ -360,8 +360,8 @@ int com_stat(struct stream_cipher_context *scc, int argc, char * const * argv) para_sigaction(SIGUSR1, dummy); - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + for (i = 1; i < cc->argc; i++) { + const char *arg = cc->argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { @@ -380,12 +380,12 @@ int com_stat(struct stream_cipher_context *scc, int argc, char * const * argv) } return -E_COMMAND_SYNTAX; } - if (i != argc) + if (i != cc->argc) return -E_COMMAND_SYNTAX; for (;;) { mmd_dup(nmmd); s = get_status(nmmd, parser_friendly); - ret = sc_send_buffer(scc, s); + ret = sc_send_buffer(&cc->scc, s); free(s); if (ret < 0) goto out; @@ -393,11 +393,11 @@ int com_stat(struct stream_cipher_context *scc, int argc, char * const * argv) static char *esi; if (!esi) esi = empty_status_items(parser_friendly); - ret = sc_send_buffer(scc, esi); + ret = sc_send_buffer(&cc->scc, esi); if (ret < 0) goto out; } else - send_afs_status(scc, parser_friendly); + send_afs_status(cc, parser_friendly); ret = 1; if (num > 0 && !--num) goto out; @@ -449,30 +449,30 @@ static struct server_command *get_cmd_ptr(const char *name, char **handler) } /* help */ -int com_help(struct stream_cipher_context *scc, int argc, char * const * argv) +int com_help(struct command_context *cc) { struct server_command *cmd; char *perms, *handler; int ret; - if (argc < 2) { + if (cc->argc < 2) { /* no argument given, print list of commands */ - if ((ret = send_list_of_commands(scc, server_cmds, "server")) < 0) + if ((ret = send_list_of_commands(&cc->scc, server_cmds, "server")) < 0) return ret; - return send_list_of_commands(scc, afs_cmds, "afs"); + return send_list_of_commands(&cc->scc, afs_cmds, "afs"); } /* argument given for help */ - cmd = get_cmd_ptr(argv[1], &handler); + cmd = get_cmd_ptr(cc->argv[1], &handler); if (!cmd) return -E_BAD_CMD; perms = cmd_perms_itohuman(cmd->perms); - ret = sc_send_va_buffer(scc, + ret = sc_send_va_buffer(&cc->scc, "%s - %s\n\n" "handler: %s\n" "permissions: %s\n" "usage: %s\n\n" "%s\n", - argv[1], + cc->argv[1], cmd->description, handler, perms, @@ -485,39 +485,38 @@ int com_help(struct stream_cipher_context *scc, int argc, char * const * argv) } /* hup */ -int com_hup(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv) +int com_hup(struct command_context *cc) { - if (argc != 1) + if (cc->argc != 1) return -E_COMMAND_SYNTAX; kill(getppid(), SIGHUP); return 1; } /* term */ -int com_term(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv) +int com_term(struct command_context *cc) { - if (argc != 1) + if (cc->argc != 1) return -E_COMMAND_SYNTAX; kill(getppid(), SIGTERM); return 1; } -int com_play(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv) +int com_play(struct command_context *cc) { - if (argc != 1) + if (cc->argc != 1) return -E_COMMAND_SYNTAX; mutex_lock(mmd_mutex); mmd->new_vss_status_flags |= VSS_PLAYING; mmd->new_vss_status_flags &= ~VSS_NOMORE; mutex_unlock(mmd_mutex); return 1; - } /* stop */ -int com_stop(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv) +int com_stop(struct command_context *cc) { - if (argc != 1) + if (cc->argc != 1) return -E_COMMAND_SYNTAX; mutex_lock(mmd_mutex); mmd->new_vss_status_flags &= ~VSS_PLAYING; @@ -528,9 +527,9 @@ int com_stop(__a_unused struct stream_cipher_context *scc, int argc, __a_unused } /* pause */ -int com_pause(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv) +int com_pause(struct command_context *cc) { - if (argc != 1) + if (cc->argc != 1) return -E_COMMAND_SYNTAX; mutex_lock(mmd_mutex); if (!vss_paused() && !vss_stopped()) { @@ -543,9 +542,9 @@ int com_pause(__a_unused struct stream_cipher_context *scc, int argc, __a_unused } /* next */ -int com_next(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv) +int com_next(struct command_context *cc) { - if (argc != 1) + if (cc->argc != 1) return -E_COMMAND_SYNTAX; mutex_lock(mmd_mutex); mmd->events++; @@ -555,9 +554,9 @@ int com_next(__a_unused struct stream_cipher_context *scc, int argc, __a_unused } /* nomore */ -int com_nomore(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv) +int com_nomore(struct command_context *cc) { - if (argc != 1) + if (cc->argc != 1) return -E_COMMAND_SYNTAX; mutex_lock(mmd_mutex); if (vss_playing() || vss_paused()) @@ -567,16 +566,16 @@ int com_nomore(__a_unused struct stream_cipher_context *scc, int argc, __a_unuse } /* ff */ -int com_ff(__a_unused struct stream_cipher_context *scc, int argc, char * const * argv) +int com_ff(struct command_context *cc) { long promille; int ret, backwards = 0; unsigned i; char c; - if (argc != 2) + if (cc->argc != 2) return -E_COMMAND_SYNTAX; - if (!(ret = sscanf(argv[1], "%u%c", &i, &c))) + if (!(ret = sscanf(cc->argv[1], "%u%c", &i, &c))) return -E_COMMAND_SYNTAX; if (ret > 1 && c == '-') backwards = 1; /* jmp backwards */ @@ -606,14 +605,14 @@ out: } /* jmp */ -int com_jmp(__a_unused struct stream_cipher_context *scc, int argc, char * const * argv) +int com_jmp(struct command_context *cc) { long unsigned int i; int ret; - if (argc != 2) + if (cc->argc != 2) return -E_COMMAND_SYNTAX; - if (sscanf(argv[1], "%lu", &i) <= 0) + if (sscanf(cc->argv[1], "%lu", &i) <= 0) return -E_COMMAND_SYNTAX; mutex_lock(mmd_mutex); ret = -E_NO_AUDIO_FILE; @@ -733,24 +732,22 @@ static void reset_signals(void) */ __noreturn void handle_connect(int fd, const char *peername) { - int ret, argc; + int ret; char buf[4096]; unsigned char rand_buf[CHALLENGE_SIZE + 2 * SESSION_KEY_LEN]; unsigned char challenge_hash[HASH_SIZE]; - struct user *u; - struct server_command *cmd = NULL; - char **argv = NULL; char *p, *command = NULL; size_t numbytes; - struct stream_cipher_context scc = {.fd = fd}; + struct command_context cc_struct = {.peer = peername}, *cc = &cc_struct; + cc->scc.fd = fd; reset_signals(); /* we need a blocking fd here as recv() might return EAGAIN otherwise. */ ret = mark_fd_blocking(fd); if (ret < 0) goto net_err; /* send Welcome message */ - ret = send_va_buffer(fd, "This is para_server, version " + ret = write_va_buffer(fd, "This is para_server, version " PACKAGE_VERSION ".\n" ); if (ret < 0) goto net_err; @@ -767,10 +764,10 @@ __noreturn void handle_connect(int fd, const char *peername) goto net_err; p = buf + strlen(AUTH_REQUEST_MSG); PARA_DEBUG_LOG("received auth request for user %s\n", p); - u = lookup_user(p); - if (u) { + cc->u = lookup_user(p); + if (cc->u) { get_random_bytes_or_die(rand_buf, sizeof(rand_buf)); - ret = pub_encrypt(u->pubkey, rand_buf, sizeof(rand_buf), + ret = pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf), (unsigned char *)buf); if (ret < 0) goto net_err; @@ -786,7 +783,7 @@ __noreturn void handle_connect(int fd, const char *peername) } PARA_DEBUG_LOG("sending %u byte challenge + rc4 keys (%zu bytes)\n", CHALLENGE_SIZE, numbytes); - ret = send_bin_buffer(fd, buf, numbytes); + ret = write_all(fd, buf, numbytes); if (ret < 0) goto net_err; /* recv challenge response */ @@ -796,7 +793,7 @@ __noreturn void handle_connect(int fd, const char *peername) numbytes = ret; PARA_DEBUG_LOG("received %d bytes challenge response\n", ret); ret = -E_BAD_USER; - if (!u) + if (!cc->u) goto net_err; /* * The correct response is the hash of the first CHALLENGE_SIZE bytes @@ -810,50 +807,50 @@ __noreturn void handle_connect(int fd, const char *peername) goto net_err; /* auth successful */ alarm(0); - PARA_INFO_LOG("good auth for %s\n", u->name); + PARA_INFO_LOG("good auth for %s\n", cc->u->name); /* init stream cipher keys with the second part of the random buffer */ - scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN); - scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN); - ret = sc_send_buffer(&scc, PROCEED_MSG); + cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN); + cc->scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN); + ret = sc_send_buffer(&cc->scc, PROCEED_MSG); if (ret < 0) goto net_err; - ret = read_command(&scc, &command); + ret = read_command(&cc->scc, &command); if (ret == -E_COMMAND_SYNTAX) goto err_out; if (ret < 0) goto net_err; ret = -E_BAD_CMD; - cmd = parse_cmd(command); - if (!cmd) + cc->cmd = parse_cmd(command); + if (!cc->cmd) goto err_out; /* valid command, check permissions */ - ret = check_perms(u->perms, cmd); + ret = check_perms(cc->u->perms, cc->cmd); if (ret < 0) goto err_out; /* valid command and sufficient perms */ - ret = create_argv(command, "\n", &argv); + ret = create_argv(command, "\n", &cc->argv); if (ret < 0) goto err_out; - argc = ret; - PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u->name, - peername); - ret = cmd->handler(&scc, argc, argv); - free_argv(argv); + cc->argc = ret; + PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cc->cmd->name, + cc->u->name, peername); + ret = cc->cmd->handler(cc); + free_argv(cc->argv); mutex_lock(mmd_mutex); mmd->num_commands++; mutex_unlock(mmd_mutex); if (ret >= 0) goto out; err_out: - sc_send_va_buffer(&scc, "%s\n", para_strerror(-ret)); + sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret)); net_err: PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); out: free(command); - sc_free(scc.recv); - sc_free(scc.send); + sc_free(cc->scc.recv); + sc_free(cc->scc.send); mutex_lock(mmd_mutex); - if (cmd && (cmd->perms & AFS_WRITE) && ret >= 0) + if (cc->cmd && (cc->cmd->perms & AFS_WRITE) && ret >= 0) mmd->events++; mmd->active_connections--; mutex_unlock(mmd_mutex); diff --git a/command.h b/command.h index fd879829..05510cc0 100644 --- a/command.h +++ b/command.h @@ -1,5 +1,21 @@ /** \file command.h The structure of server and afs commands. */ +/** Per connection data available to command handlers. */ +struct command_context { + /** Network address of the peer. */ + const char *peer; + /** The paraslash user that executes this command. */ + struct user *u; + /** Argument count. */ + int argc; + /** Argument vector. */ + char **argv; + /** The command being executed. */ + struct server_command *cmd; + /** File descriptor and crypto keys. */ + struct stream_cipher_context scc; +}; + /** * Defines one command of para_server. */ @@ -7,7 +23,7 @@ struct server_command { /** The name of the command. */ const char *name; /** Pointer to the function that handles the command. */ - int (*handler)(struct stream_cipher_context *, int, char * const * const); + int (*handler)(struct command_context *); /** The privileges a user must have to execute this command. */ unsigned int perms; /** One-line description of the command. */ diff --git a/configure.ac b/configure.ac index 89242d96..b5898ac8 100644 --- a/configure.ac +++ b/configure.ac @@ -748,7 +748,7 @@ if test -n "$with_flac_libs"; then LDFLAGS="$LDFLAGS $flac_libs" fi AC_CHECK_HEADER(FLAC/stream_decoder.h, [], have_flac=no) -AC_CHECK_LIB([FLAC], [FLAC__stream_decoder_init_file], [], have_flac=no) +AC_CHECK_LIB([FLAC], [FLAC__stream_decoder_init_file], [], have_flac=no, -logg -lm) if test "$have_flac" = "yes"; then AC_DEFINE(HAVE_FLAC, 1, define to 1 if you want to build the flacdec filter) all_errlist_objs="$all_errlist_objs flacdec_filter flac_afh" diff --git a/crypt.c b/crypt.c index 69e4a314..f33f769f 100644 --- a/crypt.c +++ b/crypt.c @@ -298,7 +298,7 @@ int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf, memcpy(remainder, buf + l1, len - l1); RC4(&scc->send->key, len - l1, remainder, tmp + l1); } - ret = write_all(scc->fd, (char *)tmp, &len); + ret = xwrite(scc->fd, (char *)tmp, len); free(tmp); return ret; } diff --git a/crypt_common.c b/crypt_common.c index e02dc6af..5ad4d43d 100644 --- a/crypt_common.c +++ b/crypt_common.c @@ -337,7 +337,12 @@ int sc_recv_buffer(struct stream_cipher_context *scc, char *buf, size_t size) int sc_send_buffer(struct stream_cipher_context *scc, char *buf) { - return sc_send_bin_buffer(scc, buf, strlen(buf)); + size_t len = strlen(buf); + int ret = sc_send_bin_buffer(scc, buf, len); + + if (ret < 0 || ret == len) + return ret; + return -E_SHORT_WRITE; } __printf_2_3 int sc_send_va_buffer(struct stream_cipher_context *scc, @@ -345,9 +350,12 @@ __printf_2_3 int sc_send_va_buffer(struct stream_cipher_context *scc, { char *msg; int ret; + va_list ap; - PARA_VSPRINTF(fmt, msg); - ret = sc_send_buffer(scc, msg); + va_start(ap, fmt); + ret = xvasprintf(&msg, fmt, ap); + va_end(ap); + ret = sc_send_bin_buffer(scc, msg, ret); free(msg); return ret; } diff --git a/dccp_send.c b/dccp_send.c index fa2a163c..cfbc4de7 100644 --- a/dccp_send.c +++ b/dccp_send.c @@ -104,7 +104,7 @@ static int dccp_init_fec(struct sender_client *sc) static void dccp_send_fec(struct sender_client *sc, char *buf, size_t len) { - int ret = write_nonblock(sc->fd, buf, len); + int ret = xwrite(sc->fd, buf, len); if (ret < 0) dccp_shutdown_client(sc); diff --git a/error.h b/error.h index 63d4d5db..e34d8094 100644 --- a/error.h +++ b/error.h @@ -441,6 +441,8 @@ extern const char **para_errlist[]; PARA_ERROR(FGETS, "fgets error"), \ PARA_ERROR(EOF, "end of file"), \ PARA_ERROR(READ_PATTERN, "did not read expected pattern"), \ + PARA_ERROR(SHORT_WRITE, "unexpected short write"), \ + PARA_ERROR(EMPTY, "file is empty"), \ #define ALSA_WRITE_ERRORS \ diff --git a/fd.c b/fd.c index 2e05313e..3a8406d9 100644 --- a/fd.c +++ b/fd.c @@ -19,60 +19,136 @@ #include "fd.h" /** - * Write a buffer to a file descriptor, re-write on short writes. + * Write an array of buffers to a file descriptor. * * \param fd The file descriptor. - * \param buf The buffer to be sent. - * \param len The length of \a buf. + * \param iov Pointer to one or more buffers. + * \param iovcnt The number of buffers. + * + * EAGAIN/EWOULDBLOCK is not considered a fatal error condition. For example + * DCCP CCID3 has a sending wait queue which fills up and is emptied + * asynchronously. The EAGAIN case means that there is currently no space in + * the wait queue, but this can change at any moment. + * + * \return Negative on fatal errors, number of bytes written else. * - * \return Standard. In any case, the number of bytes that have been written is - * stored in \a len. + * For blocking file descriptors, this function returns either the sum of all + * buffer sizes, or the error code of the fatal error that caused the last + * write call to fail. + * + * For nonblocking file descriptors there is a third possibility: Any positive + * return value less than the sum of the buffer sizes indicates that some bytes + * have been written but the next write would block. + * + * \sa writev(2), \ref xwrite(). */ -int write_all(int fd, const char *buf, size_t *len) +int xwritev(int fd, struct iovec *iov, int iovcnt) { - size_t total = *len; - - assert(total); - *len = 0; - while (*len < total) { - int ret = write(fd, buf + *len, total - *len); - if (ret == -1) - return -ERRNO_TO_PARA_ERROR(errno); - *len += ret; + size_t written = 0; + int i; + struct iovec saved_iov, *curiov; + + i = 0; + curiov = iov; + saved_iov = *curiov; + while (i < iovcnt && curiov->iov_len > 0) { + ssize_t ret = writev(fd, curiov, iovcnt - i); + if (ret >= 0) { + written += ret; + while (ret > 0) { + if (ret < curiov->iov_len) { + curiov->iov_base += ret; + curiov->iov_len -= ret; + break; + } + ret -= curiov->iov_len; + *curiov = saved_iov; + i++; + if (i >= iovcnt) + return written; + curiov++; + saved_iov = *curiov; + } + continue; + } + if (errno == EINTR) + /* + * The write() call was interrupted by a signal before + * any data was written. Try again. + */ + continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) + /* + * We don't consider this an error. Note that POSIX + * allows either error to be returned, and does not + * require these constants to have the same value. + */ + return written; + /* fatal error */ + return -ERRNO_TO_PARA_ERROR(errno); } - return 1; + return written; } /** - * Write a buffer to a non-blocking file descriptor. + * Write a buffer to a file descriptor, re-writing on short writes. * * \param fd The file descriptor. - * \param buf the buffer to write. - * \param len the number of bytes of \a buf. + * \param buf The buffer to write. + * \param len The number of bytes to write. * - * EAGAIN is not considered an error condition. For example CCID3 has a - * sending wait queue which fills up and is emptied asynchronously. The EAGAIN - * case means that there is currently no space in the wait queue, but this can - * change at any moment. + * This is a simple wrapper for \ref xwritev(). * - * \return Negative on errors, number of bytes written else. + * \return The return value of the underlying call to \ref xwritev(). */ -int write_nonblock(int fd, const char *buf, size_t len) +int xwrite(int fd, const char *buf, size_t len) { - size_t written = 0; - int ret = 0; + struct iovec iov = {.iov_base = (void *)buf, .iov_len = len}; + return xwritev(fd, &iov, 1); +} + +/** + * Write all data to a file descriptor. + * + * \param fd The file descriptor. + * \param buf The buffer to be sent. + * \param len The length of \a buf. + * + * This is like \ref xwrite() but returns \p -E_SHORT_WRITE if not + * all data could be written. + * + * \return Number of bytes written on success, negative error code else. + */ +int write_all(int fd, const char *buf, size_t len) +{ + int ret = xwrite(fd, buf, len); - while (written < len) { - size_t num = len - written; + if (ret < 0) + return ret; + if (ret != len) + return -E_SHORT_WRITE; + return ret; +} - ret = write(fd, buf + written, num); - if (ret < 0 && errno == EAGAIN) - return written; - if (ret < 0) - return -ERRNO_TO_PARA_ERROR(errno); - written += ret; - } - return written; +/** + * Write a buffer given by a format string. + * + * \param fd The file descriptor. + * \param fmt A format string. + * + * \return The return value of the underlying call to \ref write_all(). + */ +__printf_2_3 int write_va_buffer(int fd, const char *fmt, ...) +{ + char *msg; + int ret; + va_list ap; + + va_start(ap, fmt); + ret = xvasprintf(&msg, fmt, ap); + ret = write_all(fd, msg, ret); + free(msg); + return ret; } /** @@ -87,7 +163,7 @@ int write_nonblock(int fd, const char *buf, size_t len) * 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. As for - * write_nonblock(), EAGAIN is not considered an error condition. However, EOF + * xwrite(), EAGAIN is not considered an error condition. However, EOF * is. * * \return Zero or a negative error code. If the underlying call to readv(2) @@ -100,7 +176,7 @@ int write_nonblock(int fd, const char *buf, size_t len) * have been read before the error occurred. In this case \a num_bytes is * positive. * - * \sa \ref write_nonblock(), read(2), readv(2). + * \sa \ref xwrite(), read(2), readv(2). */ int readv_nonblock(int fd, struct iovec *iov, int iovcnt, fd_set *rfds, size_t *num_bytes) @@ -541,6 +617,22 @@ int mmap_full_file(const char *path, int open_mode, void **map, goto out; } *size = file_status.st_size; + /* + * If the file is empty, *size is zero and mmap() would return EINVAL + * (Invalid argument). This error is common enough to spend an extra + * error code which explicitly states the problem. + */ + ret = -E_EMPTY; + if (*size == 0) + goto out; + /* + * If fd refers to a directory, mmap() returns ENODEV (No such device), + * at least on Linux. "Is a directory" seems to be more to the point. + */ + ret = -ERRNO_TO_PARA_ERROR(EISDIR); + if (S_ISDIR(file_status.st_mode)) + goto out; + ret = para_mmap(*size, mmap_prot, mmap_flags, fd, 0, map); out: if (ret < 0 || !fd_ptr) diff --git a/fd.h b/fd.h index c87c0ea6..30b3411b 100644 --- a/fd.h +++ b/fd.h @@ -6,7 +6,8 @@ /** \file fd.h exported symbols from fd.c */ -int write_all(int fd, const char *buf, size_t *len); +int write_all(int fd, const char *buf, size_t len); +__printf_2_3 int write_va_buffer(int fd, const char *fmt, ...); int file_exists(const char *); int para_select(int n, fd_set *readfds, fd_set *writefds, struct timeval *timeout_tv); @@ -28,6 +29,21 @@ int readv_nonblock(int fd, struct iovec *iov, int iovcnt, fd_set *rfds, size_t *num_bytes); int read_nonblock(int fd, void *buf, size_t sz, fd_set *rfds, size_t *num_bytes); int read_pattern(int fd, const char *pattern, size_t bufsize, fd_set *rfds); -int write_nonblock(int fd, const char *buf, size_t len); +int xwrite(int fd, const char *buf, size_t len); +int xwritev(int fd, struct iovec *iov, int iovcnt); int for_each_file_in_dir(const char *dirname, int (*func)(const char *, void *), void *private_data); +/** + * Write a \p NULL-terminated buffer. + * + * \param fd The file descriptor. + * \param buf The null-terminated buffer to be send. + * + * This is equivalent to write_all(fd, buf, strlen(buf)). + * + * \return Standard. + */ +_static_inline_ int write_buffer(int fd, const char *buf) +{ + return write_all(fd, buf, strlen(buf)); +} diff --git a/gcc-compat.h b/gcc-compat.h index ba1d82ea..5d207288 100644 --- a/gcc-compat.h +++ b/gcc-compat.h @@ -5,15 +5,18 @@ #define __a_aligned(alignment) __attribute__((__aligned__(alignment))) /* - * p is the number of the "format string" parameter, and q is - * the number of the first variadic parameter. + * p is the number of the "format string" parameter, and q is the number of the + * first variadic parameter. If q is specified as zero, the compiler only + * checks the format string for consistency. */ # define __printf(p,q) __attribute__ ((format (printf, p, q))) # define __a_const __attribute__ ((const)) + /* - * as direct use of __printf(p,q) confuses doxygen, here are two extra macros - * for those values p,q that are actually used by paraslash. + * As direct use of __printf(p,q) confuses doxygen, here are some extra macros + * for those values p,q that are actually used. */ +#define __printf_2_0 __printf(2,0) #define __printf_1_2 __printf(1,2) #define __printf_2_3 __printf(2,3) diff --git a/gcrypt.c b/gcrypt.c index 2f38f1a6..d11e94c7 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -951,7 +951,7 @@ int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf, gret = gcry_cipher_encrypt(scc->send->handle, tmp, size, (unsigned char *)buf, size); assert(gret == 0); - ret = write_all(scc->fd, (char *)tmp, &size); + ret = xwrite(scc->fd, (char *)tmp, size); free(tmp); return ret; } diff --git a/ggo/audiod.m4 b/ggo/audiod.m4 index 1fe16959..1bc5db14 100644 --- a/ggo/audiod.m4 +++ b/ggo/audiod.m4 @@ -144,40 +144,37 @@ details=" option "no_default_filters" D #~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -"Configure filters manually" +"deprecated" flag off details = " - If (and only if) this option is set, the --filter options - (see below) take effect. Otherwise, the compiled-in defaults - apply. These defaults depend on the receiver being used as - described below. - - For http streams, only a single filter per audio format, - the decoder for that format, is activated. On the other hand, - since udp and dccp streams are sent fec-encoded by para_server, - the client side must feed the output of the receiver into - the fecdec filter first. Therefore the default for udp and - dccp streams is to activate the fecdec filter, followed by - the appropriate decoder. - - You must give this option if you want to use any other filter, - for example the amp or the compress filter. - + This option is was deprecated in paraslash-0.4.10 and has no + effect any more. It will be removed in the next version. " option "filter" f #~~~~~~~~~~~~~~~~ -"Use non-default filters" -string typestr="filter_spec" +"Specify the filter configuration." +string typestr = "filter_spec" optional multiple -dependon="no_default_filters" -details=" +details = " This option may be given multiple times. The \"filter_spec\" consists of an audio format specifier (see above), the name of the filter, and any options for that filter. Note that order matters. + The compiled-in defaults apply to all audio formats for which + no --filter option was given. These defaults depend on the + receiver being used. + + For HTTP streams, only the decoder for the current audio + format is activated. UDP and DCCP streams, on the other + hand, are sent FEC-encoded by para_server. In order to play + such streams, the receiver output must be FEC-decoded first, + i.e. fed to the fecdec filter. Therefore the default for UDP + and DCCP streams is to activate the fecdec filter, followed + by the decoding filter for the audio format. + Examples: --filter 'mp3:mp3dec' diff --git a/grab_client.c b/grab_client.c index e96fed36..07f779bd 100644 --- a/grab_client.c +++ b/grab_client.c @@ -76,7 +76,7 @@ static int gc_write(struct grab_client *gc, char *buf, size_t len) if (gc->mode == GM_SLOPPY) return len; } - ret = write_nonblock(gc->fd, buf, len); + ret = xwrite(gc->fd, buf, len); if (ret < 0) goto err; if (ret > 0) diff --git a/gui.c b/gui.c index b7823f0d..0316e365 100644 --- a/gui.c +++ b/gui.c @@ -336,11 +336,14 @@ static int align_str(WINDOW* win, char *str, unsigned int len, __printf_2_3 static void print_in_bar(int color, const char *fmt,...) { char *msg; + va_list ap; if (!curses_active) return; wattron(in.win, COLOR_PAIR(color)); - PARA_VSPRINTF(fmt, msg); + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); wmove(in.win, 0, 0); align_str(in.win, msg, sb.cols, LEFT); free(msg); @@ -471,10 +474,13 @@ static void rb_add_entry(int color, char *msg) __printf_2_3 static void outputf(int color, const char* fmt,...) { char *msg; + va_list ap; if (!curses_active) return; - PARA_VSPRINTF(fmt, msg); + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); rb_add_entry(color, msg); wrefresh(bot.win); } @@ -493,6 +499,7 @@ __printf_2_3 void curses_log(int ll, const char *fmt,...) { int color; char *msg; + va_list ap; if (ll < loglevel || !curses_active) return; @@ -505,7 +512,9 @@ __printf_2_3 void curses_log(int ll, const char *fmt,...) default: color = COLOR_ERRMSG; } - PARA_VSPRINTF(fmt, msg); + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); chop(msg); rb_add_entry(color, msg); wrefresh(bot.win); diff --git a/http_recv.c b/http_recv.c index 350f410d..c3d918c5 100644 --- a/http_recv.c +++ b/http_recv.c @@ -95,7 +95,7 @@ static void http_recv_post_select(struct sched *s, struct task *t) return; rq = make_request_msg(); PARA_INFO_LOG("sending http request\n"); - ret = send_va_buffer(rn->fd, "%s", rq); + ret = write_va_buffer(rn->fd, "%s", rq); free(rq); if (ret < 0) goto out; diff --git a/http_send.c b/http_send.c index 8b705d0d..eddc0295 100644 --- a/http_send.c +++ b/http_send.c @@ -53,7 +53,7 @@ static struct sender_status http_sender_status, *hss = &http_sender_status; static int http_send_msg(struct sender_client *sc, const char *msg) { - int ret = send_buffer(sc->fd, msg); + int ret = write_buffer(sc->fd, msg); if (ret < 0) shutdown_client(sc, hss); @@ -125,7 +125,7 @@ static void http_send_chunk(struct sender_client *sc, struct sender_status *ss, ret = queue_chunk_or_shutdown(sc, ss, buf, len); goto out; } - ret = write_nonblock(sc->fd, buf, len); + ret = xwrite(sc->fd, buf, len); if (ret < 0) { shutdown_client(sc, ss); goto out; diff --git a/interactive.c b/interactive.c index e17a7a10..6a29bffa 100644 --- a/interactive.c +++ b/interactive.c @@ -292,7 +292,7 @@ static void i9e_post_select(struct sched *s, struct task *t) sz = btr_next_buffer(btrn, &buf); if (sz == 0) goto out; - ret = write_nonblock(ici->fds[1], buf, sz); + ret = xwrite(ici->fds[1], buf, sz); if (ret < 0) goto rm_btrn; btr_consume(btrn, ret); diff --git a/net.c b/net.c index 3ce98ea4..92b43065 100644 --- a/net.c +++ b/net.c @@ -689,59 +689,6 @@ struct in_addr extract_v4_addr(const struct sockaddr_storage *ss) return ia; } -/** - * Send a binary buffer. - * - * \param fd The file descriptor. - * \param buf The buffer to be sent. - * \param len The length of \a buf. - * - * Send out the buffer and try to resend the remaining part in case of short - * writes. - * - * \return Standard. - */ -int send_bin_buffer(int fd, const char *buf, size_t len) -{ - if (!len) - PARA_CRIT_LOG("len == 0\n"); - return write_all(fd, buf, &len); -} - -/** - * Send a \p NULL-terminated buffer. - * - * \param fd The file descriptor. - * \param buf The null-terminated buffer to be send. - * - * This is equivalent to send_bin_buffer(fd, buf, strlen(buf)). - * - * \return Standard. - */ -int send_buffer(int fd, const char *buf) -{ - return send_bin_buffer(fd, buf, strlen(buf)); -} - -/** - * Send a buffer given by a format string. - * - * \param fd The file descriptor. - * \param fmt A format string. - * - * \return Standard. - */ -__printf_2_3 int send_va_buffer(int fd, const char *fmt, ...) -{ - char *msg; - int ret; - - PARA_VSPRINTF(fmt, msg); - ret = send_buffer(fd, msg); - free(msg); - return ret; -} - /** * Receive data from a file descriptor. * @@ -962,7 +909,7 @@ err: #ifndef HAVE_UCRED ssize_t send_cred_buffer(int sock, char *buf) { - return send_buffer(sock, buf); + return write_buffer(sock, buf); } int recv_cred_buffer(int fd, char *buf, size_t size) { diff --git a/net.h b/net.h index 8eba454c..a3ff49e9 100644 --- a/net.h +++ b/net.h @@ -141,10 +141,6 @@ extern char *remote_name(int sockfd); */ extern int generic_max_transport_msg_size(int sockfd); -int send_bin_buffer(int, const char *, size_t); -int send_buffer(int, const char *); -__printf_2_3 int send_va_buffer(int fd, const char *fmt, ...); - int recv_bin_buffer(int fd, char *buf, size_t size); int recv_buffer(int fd, char *buf, size_t size); diff --git a/oss_write.c b/oss_write.c index 85357f93..f075ce50 100644 --- a/oss_write.c +++ b/oss_write.c @@ -189,7 +189,7 @@ static void oss_post_select(__a_unused struct sched *s, ret = 0; if (!FD_ISSET(powd->fd, &s->wfds)) goto out; - ret = write_nonblock(powd->fd, data, frames * powd->bytes_per_frame); + ret = xwrite(powd->fd, data, frames * powd->bytes_per_frame); if (ret < 0) goto out; btr_consume(btrn, ret); diff --git a/para.h b/para.h index 25cbd16a..3b9559e1 100644 --- a/para.h +++ b/para.h @@ -113,38 +113,9 @@ extern const char *status_item_list[]; int for_each_stat_item(char *item_buf, size_t num_bytes, int (*item_handler)(int, char *)); -/** - * Write a log message to a dynamically allocated string. - * - * \param fmt Usual format string. - * \param p Result pointer. - * - * \sa printf(3). */ -#define PARA_VSPRINTF(fmt, p) \ -{ \ - int n; \ - size_t size = 100; \ - p = para_malloc(size); \ - while (1) { \ - va_list ap; \ - /* Try to print in the allocated space. */ \ - va_start(ap, fmt); \ - n = vsnprintf(p, size, fmt, ap); \ - va_end(ap); \ - /* If that worked, return the string. */ \ - if (n > -1 && n < size) \ - break; \ - /* Else try again with more space. */ \ - if (n > -1) /* glibc 2.1 */ \ - size = n + 1; /* precisely what is needed */ \ - else /* glibc 2.0 */ \ - size *= 2; /* twice the old size */ \ - p = para_realloc(p, size); \ - } \ -} /** - * Return a random non-negative integer in an interval. + * Return a random non-negative integer in an interval. * * \param max Determines maximal possible return value. * diff --git a/send_common.c b/send_common.c index 71e0852a..354c9ed5 100644 --- a/send_common.c +++ b/send_common.c @@ -113,7 +113,7 @@ int send_queued_chunks(int fd, struct chunk_queue *cq) int ret; cq_get(qc, &buf, &len); - ret = write_nonblock(fd, buf, len); + ret = xwrite(fd, buf, len); if (ret < 0) return ret; cq_update(cq, ret); diff --git a/stdout.c b/stdout.c index 0f0c0e53..abe7abc9 100644 --- a/stdout.c +++ b/stdout.c @@ -68,7 +68,7 @@ static void stdout_post_select(struct sched *s, struct task *t) sz = btr_next_buffer(btrn, &buf); if (sz == 0) break; - ret = write_nonblock(STDOUT_FILENO, buf, sz); + ret = xwrite(STDOUT_FILENO, buf, sz); if (ret <= 0) break; btr_consume(btrn, ret); diff --git a/string.c b/string.c index 8c8c50ac..a1f2a43c 100644 --- a/string.c +++ b/string.c @@ -114,6 +114,64 @@ __must_check __malloc char *para_strdup(const char *s) exit(EXIT_FAILURE); } +/** + * Print a formated message to a dynamically allocated string. + * + * \param result The formated string is returned here. + * \param fmt The format string. + * \param ap Initialized list of arguments. + * + * This function is similar to vasprintf(), a GNU extension which is not in C + * or POSIX. It allocates a string large enough to hold the output including + * the terminating null byte. The allocated string is returned via the first + * argument and must be freed by the caller. However, unlike vasprintf(), this + * function calls exit() if insufficient memory is available, while vasprintf() + * returns -1 in this case. + * + * \return Number of bytes written, not including the terminating '\0'. + * + * \sa printf(3), vsnprintf(3), va_start(3), vasprintf(3), \ref xasprintf(). + */ +__printf_2_0 unsigned xvasprintf(char **result, const char *fmt, va_list ap) +{ + int ret; + size_t size; + va_list aq; + + va_copy(aq, ap); + ret = vsnprintf(NULL, 0, fmt, aq); + va_end(aq); + assert(ret >= 0); + size = ret + 1; + *result = para_malloc(size); + va_copy(aq, ap); + ret = vsnprintf(*result, size, fmt, aq); + va_end(aq); + assert(ret >= 0 && ret < size); + return ret; +} + +/** + * Print to a dynamically allocated string, variable number of arguments. + * + * \param result See \ref xvasprintf(). + * \param fmt Usual format string. + * + * \return The return value of the underlying call to \ref xvasprintf(). + * + * \sa \ref xvasprintf() and the references mentioned there. + */ +__printf_2_3 unsigned xasprintf(char **result, const char *fmt, ...) +{ + va_list ap; + unsigned ret; + + va_start(ap, fmt); + ret = xvasprintf(result, fmt, ap); + va_end(ap); + return ret; +} + /** * Allocate a sufficiently large string and print into it. * @@ -125,13 +183,16 @@ __must_check __malloc char *para_strdup(const char *s) * \return This function either returns a pointer to a string that must be * freed by the caller or aborts without returning. * - * \sa printf(3). + * \sa printf(3), xasprintf(). */ __must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...) { char *msg; + va_list ap; - PARA_VSPRINTF(fmt, msg); + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); return msg; } diff --git a/string.h b/string.h index e5a4f9db..cdc55d2d 100644 --- a/string.h +++ b/string.h @@ -60,6 +60,9 @@ __must_check __malloc void *para_realloc(void *p, size_t size); __must_check __malloc void *para_malloc(size_t size); __must_check __malloc void *para_calloc(size_t size); __must_check __malloc char *para_strdup(const char *s); + +__printf_2_0 unsigned xvasprintf(char **result, const char *fmt, va_list ap); +__printf_2_3 unsigned xasprintf(char **result, const char *fmt, ...); __must_check __malloc __printf_1_2 char *make_message(const char *fmt, ...); __must_check __malloc char *para_strcat(char *a, const char *b); __must_check __malloc char *para_dirname(const char *name); diff --git a/udp_send.c b/udp_send.c index 1155bcb4..3e3950f9 100644 --- a/udp_send.c +++ b/udp_send.c @@ -288,7 +288,7 @@ static void udp_send_fec(struct sender_client *sc, char *buf, size_t len) ret = udp_check_socket_state(sc); if (ret < 0) goto fail; - ret = write_nonblock(sc->fd, buf, len); + ret = xwrite(sc->fd, buf, len); if (ret == -ERRNO_TO_PARA_ERROR(ECONNREFUSED)) { /* * Happens if meanwhile an ICMP Destination / Port Unreachable diff --git a/vss.c b/vss.c index bfea37a1..8f177bab 100644 --- a/vss.c +++ b/vss.c @@ -1136,7 +1136,7 @@ static void vss_post_select(struct sched *s, struct task *t) recv_afs_result(vsst, &s->rfds); else if (FD_ISSET(vsst->afs_socket, &s->wfds)) { PARA_NOTICE_LOG("requesting new fd from afs\n"); - ret = send_buffer(vsst->afs_socket, "new"); + ret = write_buffer(vsst->afs_socket, "new"); if (ret < 0) PARA_CRIT_LOG("%s\n", para_strerror(-ret)); else