summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/res_pjproject.h36
-rw-r--r--res/res_pjproject.c40
-rw-r--r--res/res_pjsip.c64
3 files changed, 137 insertions, 3 deletions
diff --git a/include/asterisk/res_pjproject.h b/include/asterisk/res_pjproject.h
index 2095caed2..8828b340c 100644
--- a/include/asterisk/res_pjproject.h
+++ b/include/asterisk/res_pjproject.h
@@ -19,6 +19,14 @@
#ifndef _RES_PJPROJECT_H
#define _RES_PJPROJECT_H
+/*! \brief Determines whether the res_pjproject module is loaded */
+#define CHECK_PJPROJECT_MODULE_LOADED() \
+ do { \
+ if (!ast_module_check("res_pjproject.so")) { \
+ return AST_MODULE_LOAD_DECLINE; \
+ } \
+ } while(0)
+
/*!
* \brief Retrieve a pjproject build option
*
@@ -43,7 +51,33 @@
* \endcode
*
*/
-int ast_pjproject_get_buildopt(char *option, char *format_string, ...) __attribute__((format(scanf, 2,3)));
+int ast_pjproject_get_buildopt(char *option, char *format_string, ...) __attribute__((format(scanf, 2, 3)));
+
+/*!
+ * \brief Begin PJPROJECT log interception for CLI output.
+ * \since 13.8.0
+ *
+ * \param fd CLI file descriptior to send intercepted output.
+ *
+ * \note ast_pjproject_log_intercept_begin() and
+ * ast_pjproject_log_intercept_end() must always be called
+ * in pairs.
+ *
+ * \return Nothing
+ */
+void ast_pjproject_log_intercept_begin(int fd);
+
+/*!
+ * \brief End PJPROJECT log interception for CLI output.
+ * \since 13.8.0
+ *
+ * \note ast_pjproject_log_intercept_begin() and
+ * ast_pjproject_log_intercept_end() must always be called
+ * in pairs.
+ *
+ * \return Nothing
+ */
+void ast_pjproject_log_intercept_end(void);
/*!
* \brief Increment the res_pjproject reference count.
diff --git a/res/res_pjproject.c b/res/res_pjproject.c
index de1cecbc8..e9f0d15c4 100644
--- a/res/res_pjproject.c
+++ b/res/res_pjproject.c
@@ -57,6 +57,19 @@ static unsigned decor_orig;
static AST_VECTOR(buildopts, char *) buildopts;
+/*! Protection from other log intercept instances. There can be only one at a time. */
+AST_MUTEX_DEFINE_STATIC(pjproject_log_intercept_lock);
+
+struct pjproject_log_intercept_data {
+ pthread_t thread;
+ int fd;
+};
+
+static struct pjproject_log_intercept_data pjproject_log_intercept = {
+ .thread = AST_PTHREADT_NULL,
+ .fd = -1,
+};
+
static void log_forwarder(int level, const char *data, int len)
{
int ast_level;
@@ -66,6 +79,16 @@ static void log_forwarder(int level, const char *data, int len)
const char *log_func = "<?>";
int mod_level;
+ if (pjproject_log_intercept.fd != -1
+ && pjproject_log_intercept.thread == pthread_self()) {
+ /*
+ * We are handling a CLI command intercepting PJPROJECT
+ * log output.
+ */
+ ast_cli(pjproject_log_intercept.fd, "%s\n", data);
+ return;
+ }
+
/* Lower number indicates higher importance */
switch (level) {
case 0: /* level zero indicates fatal error, according to docs */
@@ -124,6 +147,23 @@ int ast_pjproject_get_buildopt(char *option, char *format_string, ...)
return res;
}
+void ast_pjproject_log_intercept_begin(int fd)
+{
+ /* Protect from other CLI instances trying to do this at the same time. */
+ ast_mutex_lock(&pjproject_log_intercept_lock);
+
+ pjproject_log_intercept.thread = pthread_self();
+ pjproject_log_intercept.fd = fd;
+}
+
+void ast_pjproject_log_intercept_end(void)
+{
+ pjproject_log_intercept.fd = -1;
+ pjproject_log_intercept.thread = AST_PTHREADT_NULL;
+
+ ast_mutex_unlock(&pjproject_log_intercept_lock);
+}
+
void ast_pjproject_ref(void)
{
ast_module_ref(ast_module_info->self);
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index b3c6773b4..2b7625aba 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -42,9 +42,11 @@
#include "asterisk/res_pjsip_cli.h"
#include "asterisk/test.h"
#include "asterisk/res_pjsip_presence_xml.h"
+#include "asterisk/res_pjproject.h"
/*** MODULEINFO
<depend>pjproject</depend>
+ <depend>res_pjproject</depend>
<depend>res_sorcery_config</depend>
<depend>res_sorcery_memory</depend>
<depend>res_sorcery_astdb</depend>
@@ -2216,6 +2218,57 @@ struct ast_sip_endpoint *ast_sip_identify_endpoint(pjsip_rx_data *rdata)
return endpoint;
}
+static int do_cli_dump_endpt(void *v_a)
+{
+ struct ast_cli_args *a = v_a;
+
+ ast_pjproject_log_intercept_begin(a->fd);
+ pjsip_endpt_dump(ast_sip_get_pjsip_endpoint(), a->argc == 4 ? PJ_TRUE : PJ_FALSE);
+ ast_pjproject_log_intercept_end();
+
+ return 0;
+}
+
+static char *cli_dump_endpt(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+#ifdef AST_DEVMODE
+ e->command = "pjsip dump endpt [details]";
+ e->usage =
+ "Usage: pjsip dump endpt [details]\n"
+ " Dump the res_pjsip endpt internals.\n"
+ "\n"
+ "Warning: PJPROJECT documents that the function used by this\n"
+ "CLI command may cause a crash when asking for details because\n"
+ "it tries to access all active memory pools.\n";
+#else
+ /*
+ * In non-developer mode we will not document or make easily accessible
+ * the details option even though it is still available. The user has
+ * to know it exists to use it. Presumably they would also be aware of
+ * the potential crash warning.
+ */
+ e->command = "pjsip dump endpt";
+ e->usage =
+ "Usage: pjsip dump endpt\n"
+ " Dump the res_pjsip endpt internals.\n";
+#endif /* AST_DEVMODE */
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (4 < a->argc
+ || (a->argc == 4 && strcasecmp(a->argv[3], "details"))) {
+ return CLI_SHOWUSAGE;
+ }
+
+ ast_sip_push_task_synchronous(NULL, do_cli_dump_endpt, a);
+
+ return CLI_SUCCESS;
+}
+
static char *cli_show_endpoint_identifiers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
#define ENDPOINT_IDENTIFIER_FORMAT "%-20.20s\n"
@@ -2279,8 +2332,9 @@ static char *cli_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
}
static struct ast_cli_entry cli_commands[] = {
- AST_CLI_DEFINE(cli_show_settings, "Show global and system configuration options"),
- AST_CLI_DEFINE(cli_show_endpoint_identifiers, "List registered endpoint identifiers")
+ AST_CLI_DEFINE(cli_dump_endpt, "Dump the res_pjsip endpt internals"),
+ AST_CLI_DEFINE(cli_show_settings, "Show global and system configuration options"),
+ AST_CLI_DEFINE(cli_show_endpoint_identifiers, "List registered endpoint identifiers")
};
AST_RWLIST_HEAD_STATIC(endpoint_formatters, ast_sip_endpoint_formatter);
@@ -3895,6 +3949,8 @@ static int load_module(void)
pj_status_t status;
struct ast_threadpool_options options;
+ CHECK_PJPROJECT_MODULE_LOADED();
+
if (pj_init() != PJ_SUCCESS) {
return AST_MODULE_LOAD_DECLINE;
}
@@ -4041,6 +4097,8 @@ static int load_module(void)
AST_TEST_REGISTER(xml_sanitization_end_null);
AST_TEST_REGISTER(xml_sanitization_exceeds_buffer);
+ ast_pjproject_ref();
+
return AST_MODULE_LOAD_SUCCESS;
}
@@ -4094,6 +4152,8 @@ static int unload_module(void)
ast_threadpool_shutdown(sip_threadpool);
ast_sip_destroy_cli();
+ ast_pjproject_unref();
+
return 0;
}