diff options
Diffstat (limited to 'res')
-rw-r--r-- | res/res_config_sqlite3.c | 16 | ||||
-rw-r--r-- | res/res_pjproject.c | 224 | ||||
-rw-r--r-- | res/res_pjsip_config_wizard.c | 111 | ||||
-rw-r--r-- | res/res_sorcery_memory_cache.c | 6 |
4 files changed, 337 insertions, 20 deletions
diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index 04b8e374c..4c4b82051 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -127,8 +127,14 @@ static inline const char *sqlite3_escape_string_helper(struct ast_threadstorage * add two quotes, and convert NULL pointers to the word "NULL", but we * don't allow those anyway. Just going to use %q for now. */ struct ast_str *buf = ast_str_thread_get(ts, maxlen); - char *tmp = ast_str_buffer(buf); char q = ts == &escape_value_buf ? '\'' : '"'; + char *tmp; + + if (ast_str_size(buf) < maxlen) { + /* realloc if buf is too small */ + ast_str_make_space(&buf, maxlen); + } + tmp = ast_str_buffer(buf); ast_str_reset(buf); *tmp++ = q; /* Initial quote */ @@ -160,9 +166,15 @@ static const char *sqlite3_escape_column_op(const char *param) { size_t maxlen = strlen(param) * 2 + sizeof("\"\" ="); struct ast_str *buf = ast_str_thread_get(&escape_column_buf, maxlen); - char *tmp = ast_str_buffer(buf); + char *tmp; int space = 0; + if (ast_str_size(buf) < maxlen) { + /* realloc if buf is too small */ + ast_str_make_space(&buf, maxlen); + } + tmp = ast_str_buffer(buf); + ast_str_reset(buf); *tmp++ = '"'; while ((*tmp++ = *param++)) { diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 7bf9003f9..f54c3713e 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -37,6 +37,44 @@ <support_level>core</support_level> ***/ +/*** DOCUMENTATION + <configInfo name="res_pjproject" language="en_US"> + <synopsis>pjproject common configuration</synopsis> + <configFile name="pjproject.conf"> + <configObject name="log_mappings"> + <synopsis>PJPROJECT to Asterisk Log Level Mapping</synopsis> + <description><para>Warnings and errors in the pjproject libraries are generally handled + by Asterisk. In many cases, Asterisk wouldn't even consider them to + be warnings or errors so the messages emitted by pjproject directly + are either superfluous or misleading. The 'log_mappings' + object allows mapping the pjproject levels to Asterisk levels, or nothing. + </para> + <note><para>The id of this object, as well as its type, must be + 'log_mappings' or it won't be found.</para></note> + </description> + <configOption name="type"> + <synopsis>Must be of type 'log_mappings'.</synopsis> + </configOption> + <configOption name="asterisk_error" default="0,1"> + <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_ERROR.</synopsis> + </configOption> + <configOption name="asterisk_warning" default="2"> + <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_WARNING.</synopsis> + </configOption> + <configOption name="asterisk_notice" default=""> + <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_NOTICE.</synopsis> + </configOption> + <configOption name="asterisk_debug" default="3,4,5"> + <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_DEBUG.</synopsis> + </configOption> + <configOption name="asterisk_verbose" default=""> + <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_VERBOSE.</synopsis> + </configOption> + </configObject> + </configFile> + </configInfo> + ***/ + #include "asterisk.h" ASTERISK_REGISTER_FILE() @@ -51,7 +89,9 @@ ASTERISK_REGISTER_FILE() #include "asterisk/cli.h" #include "asterisk/res_pjproject.h" #include "asterisk/vector.h" +#include "asterisk/sorcery.h" +static struct ast_sorcery *pjproject_sorcery; static pj_log_func *log_cb_orig; static unsigned decor_orig; @@ -70,6 +110,66 @@ static struct pjproject_log_intercept_data pjproject_log_intercept = { .fd = -1, }; +struct log_mappings { + /*! Sorcery object details */ + SORCERY_OBJECT(details); + /*! These are all comma-separated lists of pjproject log levels */ + AST_DECLARE_STRING_FIELDS( + /*! pjproject log levels mapped to Asterisk ERROR */ + AST_STRING_FIELD(asterisk_error); + /*! pjproject log levels mapped to Asterisk WARNING */ + AST_STRING_FIELD(asterisk_warning); + /*! pjproject log levels mapped to Asterisk NOTICE */ + AST_STRING_FIELD(asterisk_notice); + /*! pjproject log levels mapped to Asterisk VERBOSE */ + AST_STRING_FIELD(asterisk_verbose); + /*! pjproject log levels mapped to Asterisk DEBUG */ + AST_STRING_FIELD(asterisk_debug); + ); +}; + +static struct log_mappings *default_log_mappings; + +static struct log_mappings *get_log_mappings(void) +{ + struct log_mappings *mappings; + + mappings = ast_sorcery_retrieve_by_id(pjproject_sorcery, "log_mappings", "log_mappings"); + if (!mappings) { + return ao2_bump(default_log_mappings); + } + + return mappings; +} + +#define __LOG_SUPPRESS -1 + +static int get_log_level(int pj_level) +{ + RAII_VAR(struct log_mappings *, mappings, get_log_mappings(), ao2_cleanup); + unsigned char l; + + if (!mappings) { + return __LOG_ERROR; + } + + l = '0' + fmin(pj_level, 9); + + if (strchr(mappings->asterisk_error, l)) { + return __LOG_ERROR; + } else if (strchr(mappings->asterisk_warning, l)) { + return __LOG_WARNING; + } else if (strchr(mappings->asterisk_notice, l)) { + return __LOG_NOTICE; + } else if (strchr(mappings->asterisk_verbose, l)) { + return __LOG_VERBOSE; + } else if (strchr(mappings->asterisk_debug, l)) { + return __LOG_DEBUG; + } + + return __LOG_SUPPRESS; +} + static void log_forwarder(int level, const char *data, int len) { int ast_level; @@ -89,25 +189,19 @@ static void log_forwarder(int level, const char *data, int len) return; } - /* Lower number indicates higher importance */ - switch (level) { - case 0: /* level zero indicates fatal error, according to docs */ - case 1: /* 1 seems to be used for errors */ - ast_level = __LOG_ERROR; - break; - case 2: /* 2 seems to be used for warnings and errors */ - ast_level = __LOG_WARNING; - break; - default: - ast_level = __LOG_DEBUG; + ast_level = get_log_level(level); + + if (ast_level == __LOG_SUPPRESS) { + return; + } + if (ast_level == __LOG_DEBUG) { /* For levels 3 and up, obey the debug level for res_pjproject */ mod_level = ast_opt_dbg_module ? ast_debug_get_by_module("res_pjproject") : 0; if (option_debug < level && mod_level < level) { return; } - break; } /* PJPROJECT uses indention to indicate function call depth. We'll prepend @@ -201,14 +295,105 @@ static char *handle_pjproject_show_buildopts(struct ast_cli_entry *e, int cmd, s return CLI_SUCCESS; } +static void mapping_destroy(void *object) +{ + struct log_mappings *mappings = object; + + ast_string_field_free_memory(mappings); +} + +static void *mapping_alloc(const char *name) +{ + struct log_mappings *mappings = ast_sorcery_generic_alloc(sizeof(*mappings), mapping_destroy); + if (!mappings) { + return NULL; + } + ast_string_field_init(mappings, 128); + + return mappings; +} + +static char *handle_pjproject_show_log_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct ast_variable *objset; + struct ast_variable *i; + struct log_mappings *mappings; + + switch (cmd) { + case CLI_INIT: + e->command = "pjproject show log mappings"; + e->usage = + "Usage: pjproject show log mappings\n" + " Show pjproject to Asterisk log mappings\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + ast_cli(a->fd, "PJPROJECT to Asterisk log mappings:\n"); + ast_cli(a->fd, "Asterisk Level : PJPROJECT log levels\n"); + + mappings = get_log_mappings(); + if (!mappings) { + ast_log(LOG_ERROR, "Unable to retrieve pjproject log_mappings\n"); + return CLI_SUCCESS; + } + + objset = ast_sorcery_objectset_create(pjproject_sorcery, mappings); + if (!objset) { + ao2_ref(mappings, -1); + return CLI_SUCCESS; + } + + for (i = objset; i; i = i->next) { + ast_cli(a->fd, "%-16s : %s\n", i->name, i->value); + } + ast_variables_destroy(objset); + + ao2_ref(mappings, -1); + return CLI_SUCCESS; +} + static struct ast_cli_entry pjproject_cli[] = { AST_CLI_DEFINE(handle_pjproject_show_buildopts, "Show the compiled config of the pjproject in use"), + AST_CLI_DEFINE(handle_pjproject_show_log_mappings, "Show pjproject to Asterisk log mappings"), }; static int load_module(void) { ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n"); + if (!(pjproject_sorcery = ast_sorcery_open())) { + ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n"); + return AST_MODULE_LOAD_DECLINE; + } + + ast_sorcery_apply_default(pjproject_sorcery, "log_mappings", "config", "pjproject.conf,criteria=type=log_mappings"); + if (ast_sorcery_object_register(pjproject_sorcery, "log_mappings", mapping_alloc, NULL, NULL)) { + ast_log(LOG_WARNING, "Failed to register pjproject log_mappings object with sorcery\n"); + ast_sorcery_unref(pjproject_sorcery); + pjproject_sorcery = NULL; + return AST_MODULE_LOAD_DECLINE; + } + + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "type", "", OPT_NOOP_T, 0, 0); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_debug", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_debug)); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_error", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_error)); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_warning", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_warning)); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_notice", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_notice)); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_verbose", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_verbose)); + + default_log_mappings = ast_sorcery_alloc(pjproject_sorcery, "log_mappings", "log_mappings"); + if (!default_log_mappings) { + ast_log(LOG_ERROR, "Unable to allocate memory for pjproject log_mappings\n"); + return AST_MODULE_LOAD_DECLINE; + } + ast_string_field_set(default_log_mappings, asterisk_error, "0,1"); + ast_string_field_set(default_log_mappings, asterisk_warning, "2"); + ast_string_field_set(default_log_mappings, asterisk_debug, "3,4,5"); + + ast_sorcery_load(pjproject_sorcery); + pj_init(); decor_orig = pj_log_get_decor(); @@ -247,12 +432,27 @@ static int unload_module(void) pj_shutdown(); + ao2_cleanup(default_log_mappings); + default_log_mappings = NULL; + + ast_sorcery_unref(pjproject_sorcery); + return 0; } +static int reload_module(void) +{ + if (pjproject_sorcery) { + ast_sorcery_reload(pjproject_sorcery); + } + + return AST_MODULE_LOAD_SUCCESS; +} + AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJPROJECT Log and Utility Support", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, + .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 6, ); diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c index 39d3c3f64..e263437d7 100644 --- a/res/res_pjsip_config_wizard.c +++ b/res/res_pjsip_config_wizard.c @@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include <pjsip.h> #include "asterisk/astobj2.h" +#include "asterisk/cli.h" #include "asterisk/res_pjsip.h" #include "asterisk/module.h" #include "asterisk/pbx.h" @@ -276,7 +277,7 @@ struct object_type_wizard { struct ast_config *last_config; char object_type[]; }; -static AST_VECTOR(object_type_wizards, struct object_type_wizard *) object_type_wizards; +static AST_VECTOR_RW(object_type_wizards, struct object_type_wizard *) object_type_wizards; /*! \brief Callbacks for vector deletes */ #define NOT_EQUALS(a, b) (a != b) @@ -304,12 +305,15 @@ static struct object_type_wizard *find_wizard(const char *object_type) { int idx; + AST_VECTOR_RW_RDLOCK(&object_type_wizards); for(idx = 0; idx < AST_VECTOR_SIZE(&object_type_wizards); idx++) { struct object_type_wizard *otw = AST_VECTOR_GET(&object_type_wizards, idx); if (!strcmp(otw->object_type, object_type)) { + AST_VECTOR_RW_UNLOCK(&object_type_wizards); return otw; } } + AST_VECTOR_RW_UNLOCK(&object_type_wizards); return NULL; } @@ -1137,7 +1141,9 @@ static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery otw->wizard_data = wizard_data; otw->last_config = NULL; strcpy(otw->object_type, object_type); /* Safe */ + AST_VECTOR_RW_WRLOCK(&object_type_wizards); AST_VECTOR_APPEND(&object_type_wizards, otw); + AST_VECTOR_RW_UNLOCK(&object_type_wizards); ast_debug(1, "Wizard mapped for object_type '%s'\n", object_type); } } @@ -1177,19 +1183,118 @@ static void instance_destroying_observer(const char *name, struct ast_sorcery *s ast_module_unref(ast_module_info->self); } +static char *handle_export_primitives(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct ast_sorcery *sorcery; + int idx; + FILE *f = NULL; + const char *fn = NULL; + + switch (cmd) { + case CLI_INIT: + e->command = "pjsip export config_wizard primitives [to]"; + e->usage = + "Usage: pjsip export config_wizard primitives [ to <filename ]\n" + " Export the config_wizard objects as pjsip primitives to\n" + " the console or to <filename>\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc > 5) { + char date[256]=""; + time_t t; + fn = a->argv[5]; + + time(&t); + ast_copy_string(date, ctime(&t), sizeof(date)); + f = fopen(fn, "w"); + if (!f) { + ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno)); + return CLI_FAILURE; + } + + fprintf(f, ";!\n"); + fprintf(f, ";! Automatically generated configuration file\n"); + fprintf(f, ";! Filename: %s\n", fn); + fprintf(f, ";! Generator: %s\n", "'pjsip export config_wizard primitives'"); + fprintf(f, ";! Creation Date: %s", date); + fprintf(f, ";!\n"); + } + + sorcery = ast_sip_get_sorcery(); + + AST_VECTOR_RW_RDLOCK(&object_type_wizards); + for(idx = 0; idx < AST_VECTOR_SIZE(&object_type_wizards); idx++) { + struct object_type_wizard *otw = AST_VECTOR_GET(&object_type_wizards, idx); + struct ao2_container *container; + struct ao2_iterator i; + void *o; + + container = ast_sorcery_retrieve_by_fields(sorcery, otw->object_type, AST_RETRIEVE_FLAG_MULTIPLE, NULL); + if (!container) { + continue; + } + + i = ao2_iterator_init(container, 0); + while ((o = ao2_iterator_next(&i))) { + struct ast_variable *vars; + struct ast_variable *v; + + vars = ast_sorcery_objectset_create(sorcery, o); + if (vars && ast_variable_find_in_list(vars, "@pjsip_wizard")) { + if (f) { + fprintf(f, "\n[%s]\ntype = %s\n", ast_sorcery_object_get_id(o), otw->object_type); + } else { + ast_cli(a->fd, "\n[%s]\ntype = %s\n", ast_sorcery_object_get_id(o), otw->object_type); + } + for (v = vars; v; v = v->next) { + if (!ast_strlen_zero(v->value)) { + if (f) { + fprintf(f, "%s = %s\n", v->name, v->value); + } else { + ast_cli(a->fd, "%s = %s\n", v->name, v->value); + } + } + } + } + ast_variables_destroy(vars); + ao2_ref(o, -1); + } + ao2_iterator_destroy(&i); + ao2_cleanup(container); + } + AST_VECTOR_RW_UNLOCK(&object_type_wizards); + + if (f) { + fclose(f); + ast_cli(a->fd, "Wrote configuration to %s\n", fn); + } + + + return CLI_SUCCESS; +} + +static struct ast_cli_entry config_wizard_cli[] = { + AST_CLI_DEFINE(handle_export_primitives, "Export config wizard primitives"), +}; + static int load_module(void) { - AST_VECTOR_INIT(&object_type_wizards, 12); + AST_VECTOR_RW_INIT(&object_type_wizards, 12); ast_sorcery_global_observer_add(&global_observer); + ast_cli_register_multiple(config_wizard_cli, ARRAY_LEN(config_wizard_cli)); return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { + ast_cli_unregister_multiple(config_wizard_cli, ARRAY_LEN(config_wizard_cli)); ast_sorcery_global_observer_remove(&global_observer); AST_VECTOR_REMOVE_CMP_UNORDERED(&object_type_wizards, NULL, NOT_EQUALS, OTW_DELETE_CB); - AST_VECTOR_FREE(&object_type_wizards); + AST_VECTOR_RW_FREE(&object_type_wizards); return 0; } diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index 99db0ce9c..f2ed5d5c8 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -1830,7 +1830,7 @@ static char *sorcery_memory_cache_expire(struct ast_cli_entry *e, int cmd, struc } } - if (a->argc > 6) { + if (a->argc < 5 || a->argc > 6) { return CLI_SHOWUSAGE; } @@ -1884,7 +1884,7 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct } } - if (a->argc > 6) { + if (a->argc < 5 || a->argc > 6) { return CLI_SHOWUSAGE; } @@ -1943,7 +1943,7 @@ static char *sorcery_memory_cache_populate(struct ast_cli_entry *e, int cmd, str } } - if (a->argc > 5) { + if (a->argc != 5) { return CLI_SHOWUSAGE; } |