summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/module.h20
-rw-r--r--main/Makefile2
-rw-r--r--main/aoc.c2
-rw-r--r--main/channel.c18
-rw-r--r--main/cli.c44
-rw-r--r--main/loader.c119
-rw-r--r--main/sorcery.c1
-rw-r--r--res/ari/resource_asterisk.c7
-rw-r--r--res/ari/resource_bridges.h4
-rw-r--r--res/ari/resource_sounds.c1
-rw-r--r--res/res_ari.c4
-rw-r--r--res/res_pjsip/pjsip_configuration.c4
-rw-r--r--res/res_pjsip/pjsip_message_filter.c2
-rw-r--r--res/res_stasis_device_state.c20
-rw-r--r--res/res_stasis_mailbox.c1
-rw-r--r--res/stasis/messaging.c4
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;
}