diff options
-rw-r--r-- | include/asterisk/module.h | 20 | ||||
-rw-r--r-- | main/Makefile | 2 | ||||
-rw-r--r-- | main/aoc.c | 2 | ||||
-rw-r--r-- | main/channel.c | 18 | ||||
-rw-r--r-- | main/cli.c | 44 | ||||
-rw-r--r-- | main/loader.c | 119 | ||||
-rw-r--r-- | main/sorcery.c | 1 | ||||
-rw-r--r-- | res/ari/resource_asterisk.c | 7 | ||||
-rw-r--r-- | res/ari/resource_bridges.h | 4 | ||||
-rw-r--r-- | res/ari/resource_sounds.c | 1 | ||||
-rw-r--r-- | res/res_ari.c | 4 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 4 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_message_filter.c | 2 | ||||
-rw-r--r-- | res/res_stasis_device_state.c | 20 | ||||
-rw-r--r-- | res/res_stasis_mailbox.c | 1 | ||||
-rw-r--r-- | res/stasis/messaging.c | 4 |
16 files changed, 179 insertions, 74 deletions
diff --git a/include/asterisk/module.h b/include/asterisk/module.h index e614a726f..69ebb2640 100644 --- a/include/asterisk/module.h +++ b/include/asterisk/module.h @@ -94,6 +94,20 @@ enum ast_module_support_level { AST_MODULE_SUPPORT_DEPRECATED, }; +/*! Used to specify which modules should be returned by ast_module_helper. */ +enum ast_module_helper_type { + /*! Modules that are loaded by dlopen. */ + AST_MODULE_HELPER_LOADED = 0, + /*! Running modules that include a reload callback. */ + AST_MODULE_HELPER_RELOAD = 1, + /*! Modules that can be loaded or started. */ + AST_MODULE_HELPER_LOAD, + /*! Modules that can be unloaded. */ + AST_MODULE_HELPER_UNLOAD, + /*! Running modules */ + AST_MODULE_HELPER_RUNNING, +}; + /*! * \brief Load a module. * \param resource_name The name of the module to load. @@ -237,14 +251,12 @@ int ast_loader_unregister(int (*updater)(void)); * \param state The possible match to return. * \param rpos The position we should be matching. This should be the same as * pos. - * \param needsreload This should be 1 if we need to reload this module and 0 - * otherwise. This function will only return modules that are reloadble - * if this is 1. + * \param type The type of action that will be performed by CLI. * * \retval A possible completion of the partial match. * \retval NULL if no matches were found. */ -char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload); +char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type); /* Opaque type for module handles generated by the loader */ diff --git a/main/Makefile b/main/Makefile index 968f74658..08d1f6558 100644 --- a/main/Makefile +++ b/main/Makefile @@ -149,7 +149,7 @@ endif db.o: _ASTCFLAGS+=$(SQLITE3_INCLUDE) asterisk.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE) -cli.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE) +loader.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE) json.o: _ASTCFLAGS+=$(JANSSON_INCLUDE) bucket.o: _ASTCFLAGS+=$(URIPARSER_INCLUDE) crypt.o: _ASTCFLAGS+=$(CRYPT_INCLUDE) diff --git a/main/aoc.c b/main/aoc.c index d4b74ec92..451b21973 100644 --- a/main/aoc.c +++ b/main/aoc.c @@ -1713,7 +1713,7 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded) } for (i = 0; i < decoded->aoc_s_count; ++i) { - struct ast_json *rate = ast_json_object_create(); + struct ast_json *rate; RAII_VAR(struct ast_json *, type, NULL, ast_json_unref); RAII_VAR(struct ast_json *, currency, NULL, ast_json_unref); const char *charge_item = aoc_charged_item_str( diff --git a/main/channel.c b/main/channel.c index 7d6e5db07..7eb40d195 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5054,7 +5054,11 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame case AST_FRAME_VIDEO: /* XXX Handle translation of video codecs one day XXX */ if (ast_channel_tech(chan)->write_stream) { - res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr); + if (stream) { + res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr); + } else { + res = 0; + } } else if ((stream == default_stream) && ast_channel_tech(chan)->write_video) { res = ast_channel_tech(chan)->write_video(chan, fr); } else { @@ -5063,7 +5067,11 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame break; case AST_FRAME_MODEM: if (ast_channel_tech(chan)->write_stream) { - res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr); + if (stream) { + res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr); + } else { + res = 0; + } } else if ((stream == default_stream) && ast_channel_tech(chan)->write) { res = ast_channel_tech(chan)->write(chan, fr); } else { @@ -5251,7 +5259,11 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame f = NULL; } else { if (ast_channel_tech(chan)->write_stream) { - res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), f); + if (stream) { + res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), f); + } else { + res = 0; + } } else if ((stream == default_stream) && ast_channel_tech(chan)->write) { res = ast_channel_tech(chan)->write(chan, f); } else { diff --git a/main/cli.c b/main/cli.c index d9aab85cb..0896181b0 100644 --- a/main/cli.c +++ b/main/cli.c @@ -45,7 +45,6 @@ #include <regex.h> #include <pwd.h> #include <grp.h> -#include <editline/readline.h> #include "asterisk/cli.h" #include "asterisk/linkedlists.h" @@ -224,28 +223,6 @@ static int cli_has_permissions(int uid, int gid, const char *command) static AST_RWLIST_HEAD_STATIC(helpers, ast_cli_entry); -static char *complete_fn(const char *word, int state) -{ - char *c, *d; - char filename[PATH_MAX]; - - if (word[0] == '/') - ast_copy_string(filename, word, sizeof(filename)); - else - snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word); - - c = d = filename_completion_function(filename, state); - - if (c && word[0] != '/') - c += (strlen(ast_config_AST_MODULE_DIR) + 1); - if (c) - c = ast_strdup(c); - - ast_std_free(d); - - return c; -} - static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { /* "module load <mod>" */ @@ -258,12 +235,14 @@ static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args * return NULL; case CLI_GENERATE: - if (a->pos != e->args) + if (a->pos != e->args) { return NULL; - return complete_fn(a->word, a->n); + } + return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_LOAD); } - if (a->argc != e->args + 1) + if (a->argc != e->args + 1) { return CLI_SHOWUSAGE; + } if (ast_load_resource(a->argv[e->args])) { ast_cli(a->fd, "Unable to load module %s\n", a->argv[e->args]); return CLI_FAILURE; @@ -286,7 +265,7 @@ static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args return NULL; case CLI_GENERATE: - return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 1); + return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_RELOAD); } if (a->argc == e->args) { ast_module_reload(NULL); @@ -482,7 +461,7 @@ static char *handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args } } else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off") && strcasecmp(argv3, "channel")) || (a->pos == 5 && atleast)) { - return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0); + return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_RUNNING); } return NULL; } @@ -733,7 +712,7 @@ static char *handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args return NULL; case CLI_GENERATE: - return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0); + return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_UNLOAD); } if (a->argc < e->args + 1) return CLI_SHOWUSAGE; @@ -889,10 +868,11 @@ static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_arg return NULL; case CLI_GENERATE: - if (a->pos == e->args) - return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0); - else + if (a->pos == e->args) { + return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_LOADED); + } else { return NULL; + } } /* all the above return, so we proceed with the handler. * we are guaranteed to have argc >= e->args diff --git a/main/loader.c b/main/loader.c index 8250f1ffb..add6a4209 100644 --- a/main/loader.c +++ b/main/loader.c @@ -36,6 +36,7 @@ #include "asterisk/_private.h" #include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */ #include <dirent.h> +#include <editline/readline.h> #include "asterisk/dlinkedlists.h" #include "asterisk/module.h" @@ -702,35 +703,121 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f return res; } -char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload) +static int module_matches_helper_type(struct ast_module *mod, enum ast_module_helper_type type) { - struct ast_module *cur; - int i, which=0, l = strlen(word); - char *ret = NULL; + switch (type) { + case AST_MODULE_HELPER_UNLOAD: + return !mod->usecount && mod->flags.running && !mod->flags.declined; - if (pos != rpos) { - return NULL; + case AST_MODULE_HELPER_RELOAD: + return mod->flags.running && mod->info->reload; + + case AST_MODULE_HELPER_RUNNING: + return mod->flags.running; + + case AST_MODULE_HELPER_LOADED: + /* if we have a 'struct ast_module' then we're loaded. */ + return 1; + default: + /* This function is not called for AST_MODULE_HELPER_LOAD. */ + /* Unknown ast_module_helper_type. Assume it doesn't match. */ + ast_assert(0); + + return 0; } +} + +static char *module_load_helper(const char *word, int state) +{ + struct ast_module *mod; + int which = 0; + char *name; + char *ret = NULL; + char *editline_ret; + char fullpath[PATH_MAX]; + int idx = 0; + /* This is needed to avoid listing modules that are already running. */ + AST_VECTOR(, char *) running_modules; + + AST_VECTOR_INIT(&running_modules, 200); AST_DLLIST_LOCK(&module_list); - AST_DLLIST_TRAVERSE(&module_list, cur, entry) { - if (!strncasecmp(word, cur->resource, l) && - (cur->info->reload || !needsreload) && - ++which > state) { - ret = ast_strdup(cur->resource); - break; + AST_DLLIST_TRAVERSE(&module_list, mod, entry) { + if (mod->flags.running) { + AST_VECTOR_APPEND(&running_modules, mod->resource); } } + + if (word[0] == '/') { + /* BUGBUG: we should not support this. */ + ast_copy_string(fullpath, word, sizeof(fullpath)); + } else { + snprintf(fullpath, sizeof(fullpath), "%s/%s", ast_config_AST_MODULE_DIR, word); + } + + /* + * This is ugly that we keep calling filename_completion_function. + * The only way to avoid this would be to make a copy of the function + * that skips matches found in the running_modules vector. + */ + while (!ret && (name = editline_ret = filename_completion_function(fullpath, idx++))) { + if (word[0] != '/') { + name += (strlen(ast_config_AST_MODULE_DIR) + 1); + } + + /* Don't list files that are already loaded! */ + if (!AST_VECTOR_GET_CMP(&running_modules, name, !strcasecmp) && ++which > state) { + ret = ast_strdup(name); + } + + ast_std_free(editline_ret); + } + + /* Do not clean-up the elements, they belong to module_list. */ + AST_VECTOR_FREE(&running_modules); AST_DLLIST_UNLOCK(&module_list); - if (!ret && needsreload) { - for (i=0; !ret && reload_classes[i].name; i++) { - if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state) { - ret = ast_strdup(reload_classes[i].name); + return ret; +} + +char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type) +{ + struct ast_module *mod; + int which = 0; + int wordlen = strlen(word); + char *ret = NULL; + + if (pos != rpos) { + return NULL; + } + + if (type == AST_MODULE_HELPER_LOAD) { + return module_load_helper(word, state); + } + + if (type == AST_MODULE_HELPER_RELOAD) { + int idx; + + for (idx = 0; reload_classes[idx].name; idx++) { + if (!strncasecmp(word, reload_classes[idx].name, wordlen) && ++which > state) { + return ast_strdup(reload_classes[idx].name); } } } + AST_DLLIST_LOCK(&module_list); + AST_DLLIST_TRAVERSE(&module_list, mod, entry) { + if (!module_matches_helper_type(mod, type)) { + continue; + } + + if (!strncasecmp(word, mod->resource, wordlen) && ++which > state) { + ret = ast_strdup(mod->resource); + break; + } + } + AST_DLLIST_UNLOCK(&module_list); + return ret; } diff --git a/main/sorcery.c b/main/sorcery.c index 6694167cd..01b77918d 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -1633,6 +1633,7 @@ struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sor int res = 0; if (!object_type || !json) { + ast_json_unref(json); return NULL; } diff --git a/res/ari/resource_asterisk.c b/res/ari/resource_asterisk.c index e76eb02bc..5c6a35af6 100644 --- a/res/ari/resource_asterisk.c +++ b/res/ari/resource_asterisk.c @@ -433,6 +433,10 @@ void ast_ari_asterisk_list_modules(struct ast_variable *headers, struct ast_json *json; json = ast_json_array_create(); + if (!json) { + ast_ari_response_alloc_failed(response); + return; + } ast_update_module_list_data(&process_module_list, NULL, json); ast_ari_response_ok(response, json); @@ -505,6 +509,7 @@ void ast_ari_asterisk_get_module(struct ast_variable *headers, ast_ari_response_error( response, 409, "Conflict", "Module information could not be retrieved"); + ast_json_unref(json); return; } @@ -667,10 +672,12 @@ void ast_ari_asterisk_list_log_channels(struct ast_variable *headers, if (res == AST_LOGGER_FAILURE) { ast_ari_response_error(response, 500, "Internal Server Error", "Response body is not valid"); + ast_json_unref(json); return; } else if (res == AST_LOGGER_ALLOC_ERROR) { ast_ari_response_error(response, 500, "Internal Server Error", "Allocation Failed"); + ast_json_unref(json); return; } diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h index 72dba1e0c..0d0286c31 100644 --- a/res/ari/resource_bridges.h +++ b/res/ari/resource_bridges.h @@ -52,7 +52,7 @@ struct ast_ari_bridges_list_args { void ast_ari_bridges_list(struct ast_variable *headers, struct ast_ari_bridges_list_args *args, struct ast_ari_response *response); /*! Argument struct for ast_ari_bridges_create() */ struct ast_ari_bridges_create_args { - /*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media). */ + /*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu). */ const char *type; /*! Unique ID to give to the bridge being created. */ const char *bridge_id; @@ -82,7 +82,7 @@ int ast_ari_bridges_create_parse_body( void ast_ari_bridges_create(struct ast_variable *headers, struct ast_ari_bridges_create_args *args, struct ast_ari_response *response); /*! Argument struct for ast_ari_bridges_create_with_id() */ struct ast_ari_bridges_create_with_id_args { - /*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media) to set. */ + /*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu) to set. */ const char *type; /*! Unique ID to give to the bridge being created. */ const char *bridge_id; diff --git a/res/ari/resource_sounds.c b/res/ari/resource_sounds.c index 59ace5d81..2cb35b620 100644 --- a/res/ari/resource_sounds.c +++ b/res/ari/resource_sounds.c @@ -202,6 +202,7 @@ void ast_ari_sounds_list(struct ast_variable *headers, if (!ast_json_array_size(sounds_blob)) { ast_ari_response_error(response, 404, "Not Found", "No sounds found that matched the query"); + ast_json_unref(sounds_blob); return; } diff --git a/res/res_ari.c b/res/res_ari.c index d4eb9f8f4..9104eded3 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -985,9 +985,11 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, struct ast_str *buf = ast_str_create(512); char *str = ast_json_dump_string_format(body, ast_ari_json_format()); - if (!buf) { + if (!buf || !str) { ast_http_request_close_on_completion(ser); ast_http_error(ser, 500, "Server Error", "Out of memory"); + ast_json_free(str); + ast_free(buf); goto request_failed; } diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 6db5b3898..269e03e3d 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1140,11 +1140,11 @@ static int from_user_handler(const struct aco_option *opt, { struct ast_sip_endpoint *endpoint = obj; /* Valid non-alphanumeric characters for URI */ - char *valid_uri_marks = "-_.!~*`()"; + char *valid_uri_marks = "-._~%!$&'()*+,;=:"; const char *val; for (val = var->value; *val; val++) { - if (!strchr(valid_uri_marks, *val) && !isdigit(*val) && !isalpha(*val)) { + if (!isalpha(*val) && !isdigit(*val) && !strchr(valid_uri_marks, *val)) { ast_log(LOG_ERROR, "Error configuring endpoint '%s' - '%s' field " "contains invalid character '%c'\n", ast_sorcery_object_get_id(endpoint), var->name, *val); diff --git a/res/res_pjsip/pjsip_message_filter.c b/res/res_pjsip/pjsip_message_filter.c index 978aeb070..085d9787e 100644 --- a/res/res_pjsip/pjsip_message_filter.c +++ b/res/res_pjsip/pjsip_message_filter.c @@ -236,7 +236,7 @@ static pj_status_t filter_on_tx_message(pjsip_tx_data *tdata) pjsip_tpmgr_fla2_param_default(&prm); prm.tp_type = tdata->tp_info.transport->key.type; pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); - prm.local_if = PJ_TRUE; + prm.local_if = is_bound_any(tdata->tp_info.transport); /* If we can't get the local address use best effort and let it pass */ if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c index 276a98b93..6527af4a6 100644 --- a/res/res_stasis_device_state.c +++ b/res/res_stasis_device_state.c @@ -168,22 +168,22 @@ struct ast_json *stasis_app_device_state_to_json( struct ast_json *stasis_app_device_states_to_json(void) { struct ast_json *array = ast_json_array_create(); - RAII_VAR(struct ast_db_entry *, tree, - ast_db_gettree(DEVICE_STATE_FAMILY, NULL), ast_db_freetree); + struct ast_db_entry *tree; struct ast_db_entry *entry; + tree = ast_db_gettree(DEVICE_STATE_FAMILY, NULL); for (entry = tree; entry; entry = entry->next) { const char *name = strrchr(entry->key, '/'); + if (!ast_strlen_zero(name)) { - struct ast_str *device = ast_str_alloca(DEVICE_STATE_SIZE); - ast_str_set(&device, 0, "%s%s", - DEVICE_STATE_SCHEME_STASIS, ++name); - ast_json_array_append( - array, stasis_app_device_state_to_json( - ast_str_buffer(device), - ast_device_state(ast_str_buffer(device)))); + char device[DEVICE_STATE_SIZE]; + + snprintf(device, sizeof(device), "%s%s", DEVICE_STATE_SCHEME_STASIS, ++name); + ast_json_array_append(array, + stasis_app_device_state_to_json(device, ast_device_state(device))); } } + ast_db_freetree(tree); return array; } @@ -291,7 +291,7 @@ static void populate_cache(void) static enum ast_device_state stasis_device_state_cb(const char *data) { - char buf[DEVICE_STATE_SIZE] = ""; + char buf[DEVICE_STATE_SIZE]; ast_db_get(DEVICE_STATE_FAMILY, data, buf, sizeof(buf)); diff --git a/res/res_stasis_mailbox.c b/res/res_stasis_mailbox.c index 4522adc10..5ed061de2 100644 --- a/res/res_stasis_mailbox.c +++ b/res/res_stasis_mailbox.c @@ -93,6 +93,7 @@ struct ast_json *stasis_app_mailboxes_to_json() } } ao2_iterator_destroy(&iter); + ao2_ref(mailboxes, -1); return array; } diff --git a/res/stasis/messaging.c b/res/stasis/messaging.c index 8dfd99608..d398bb6d4 100644 --- a/res/stasis/messaging.c +++ b/res/stasis/messaging.c @@ -264,6 +264,7 @@ static struct ast_json *msg_to_json(struct ast_msg *msg) json_vars = ast_json_array_create(); if (!json_vars) { + ast_msg_var_iterator_destroy(it_vars); return NULL; } @@ -272,7 +273,8 @@ static struct ast_json *msg_to_json(struct ast_msg *msg) json_tuple = ast_json_pack("{s: s}", name, value); if (!json_tuple) { - ast_json_free(json_vars); + ast_json_unref(json_vars); + ast_msg_var_iterator_destroy(it_vars); return NULL; } |