117 #include "asterisk/res_pjproject.h"
124 static pj_log_func *log_cb_orig;
125 static unsigned decor_orig;
138 .thread = AST_PTHREADT_NULL,
170 return ao2_bump(default_log_mappings);
176 #define __LOG_SUPPRESS -1
178 static int get_log_level(
int pj_level)
184 mappings = get_log_mappings();
189 l =
'0' + fmin(pj_level, 9);
192 mapped_level = __LOG_ERROR;
194 mapped_level = __LOG_WARNING;
196 mapped_level = __LOG_NOTICE;
198 mapped_level = __LOG_VERBOSE;
200 mapped_level = __LOG_DEBUG;
202 mapped_level = __LOG_TRACE;
204 mapped_level = __LOG_SUPPRESS;
211 static void log_forwarder(
int level,
const char *data,
int len)
215 const char * log_source =
"pjproject";
217 const char *log_func =
"<?>";
219 if (pjproject_log_intercept.fd != -1
220 && pjproject_log_intercept.thread == pthread_self()) {
225 ast_cli(pjproject_log_intercept.fd,
"%s\n", data);
229 ast_level = get_log_level(level);
231 if (ast_level == __LOG_SUPPRESS) {
238 ast_log(ast_level, log_source, log_line, log_func,
"\t%s\n", data);
241 static void capture_buildopts_cb(
int level,
const char *data,
int len)
245 if (strstr(data,
"Teluu") || strstr(data,
"Dumping")) {
255 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
262 format_temp =
ast_alloca(strlen(option) + strlen(
" : ") + strlen(format_string) + 1);
263 sprintf(format_temp,
"%s : %s", option, format_string);
267 va_start(arg_ptr, format_string);
277 #pragma GCC diagnostic warning "-Wformat-nonliteral"
284 pjproject_log_intercept.thread = pthread_self();
285 pjproject_log_intercept.fd = fd;
290 pjproject_log_intercept.fd = -1;
291 pjproject_log_intercept.thread = AST_PTHREADT_NULL;
302 e->
command =
"pjproject show buildopts";
304 "Usage: pjproject show buildopts\n"
305 " Show the compile time config of the pjproject that Asterisk is\n"
306 " running against.\n";
312 ast_cli(a->fd,
"PJPROJECT compile time config currently running against:\n");
321 static void mapping_destroy(
void *
object)
328 static void *mapping_alloc(
const char *name)
347 e->
command =
"pjproject show log mappings";
349 "Usage: pjproject show log mappings\n"
350 " Show pjproject to Asterisk log mappings\n";
356 ast_cli(a->fd,
"PJPROJECT to Asterisk log mappings:\n");
357 ast_cli(a->fd,
"Asterisk Level : PJPROJECT log levels\n");
359 mappings = get_log_mappings();
361 ast_log(LOG_ERROR,
"Unable to retrieve pjproject log_mappings\n");
371 for (i = objset; i; i = i->
next) {
372 ast_cli(a->fd,
"%-16s : %s\n", i->
name, i->
value);
395 e->
command =
"pjproject set log level {default|0|1|2|3|4|5|6}";
397 "Usage: pjproject set log level {default|<level>}\n"
399 " Set the maximum active pjproject logging level.\n"
400 " See pjproject.conf.sample for additional information\n"
401 " about the various levels pjproject uses.\n"
402 " Note: setting this level at 4 or above may result in\n"
403 " raw packet logging.\n";
410 return CLI_SHOWUSAGE;
413 if (!strcasecmp(a->argv[4],
"default")) {
416 if (sscanf(a->argv[4],
"%30d", &level_new) != 1
418 return CLI_SHOWUSAGE;
426 "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d.\n"
427 "Lowering request to the max supported level.\n",
431 if (level_old == level_new) {
432 ast_cli(a->fd,
"pjproject log level is still %d.\n", level_old);
434 ast_cli(a->fd,
"pjproject log level was %d and is now %d.\n",
435 level_old, level_new);
437 pj_log_set_level(level_new);
447 e->
command =
"pjproject show log level";
449 "Usage: pjproject show log level\n"
451 " Show the current maximum active pjproject logging level.\n"
452 " See pjproject.conf.sample for additional information\n"
453 " about the various levels pjproject uses.\n";
460 return CLI_SHOWUSAGE;
463 ast_cli(a->fd,
"pjproject log level is %d.%s\n",
471 AST_CLI_DEFINE(handle_pjproject_set_log_level,
"Set the maximum active pjproject logging level"),
472 AST_CLI_DEFINE(handle_pjproject_show_buildopts,
"Show the compiled config of the pjproject in use"),
473 AST_CLI_DEFINE(handle_pjproject_show_log_mappings,
"Show pjproject to Asterisk log mappings"),
474 AST_CLI_DEFINE(handle_pjproject_show_log_level,
"Show the maximum active pjproject logging level"),
478 const pj_pool_factory_policy *policy, pj_size_t max_capacity)
486 pj_caching_pool_destroy(cp);
491 if (addr->ss.ss_family == AF_INET) {
492 struct sockaddr_in *sin = (
struct sockaddr_in *) &addr->ss;
493 pjaddr->ipv4.sin_family = pj_AF_INET();
494 #if defined(HAVE_PJPROJECT_BUNDLED) && !defined(HAVE_PJPROJECT_BUNDLED_OOT)
495 pjaddr->ipv4.sin_addr = sin->sin_addr;
497 pjaddr->ipv4.sin_addr.s_addr = sin->sin_addr.s_addr;
499 pjaddr->ipv4.sin_port = sin->sin_port;
500 }
else if (addr->ss.ss_family == AF_INET6) {
501 struct sockaddr_in6 *sin = (
struct sockaddr_in6 *) &addr->ss;
502 pjaddr->ipv6.sin6_family = pj_AF_INET6();
503 pjaddr->ipv6.sin6_port = sin->sin6_port;
504 pjaddr->ipv6.sin6_flowinfo = sin->sin6_flowinfo;
505 pjaddr->ipv6.sin6_scope_id = sin->sin6_scope_id;
506 memcpy(&pjaddr->ipv6.sin6_addr, &sin->sin6_addr,
sizeof(pjaddr->ipv6.sin6_addr));
508 memset(pjaddr, 0,
sizeof(*pjaddr));
516 if (pjaddr->addr.sa_family == pj_AF_INET()) {
517 struct sockaddr_in *sin = (
struct sockaddr_in *) &addr->ss;
518 sin->sin_family = AF_INET;
519 #
if defined(HAVE_PJPROJECT_BUNDLED) && !defined(HAVE_PJPROJECT_BUNDLED_OOT)
520 sin->sin_addr = pjaddr->ipv4.sin_addr;
522 sin->sin_addr.s_addr = pjaddr->ipv4.sin_addr.s_addr;
524 sin->sin_port = pjaddr->ipv4.sin_port;
525 memset(sin->sin_zero, 0,
sizeof(sin->sin_zero));
526 addr->len =
sizeof(
struct sockaddr_in);
527 }
else if (pjaddr->addr.sa_family == pj_AF_INET6()) {
528 struct sockaddr_in6 *sin = (
struct sockaddr_in6 *) &addr->ss;
529 sin->sin6_family = AF_INET6;
530 sin->sin6_port = pjaddr->ipv6.sin6_port;
531 sin->sin6_flowinfo = pjaddr->ipv6.sin6_flowinfo;
532 sin->sin6_scope_id = pjaddr->ipv6.sin6_scope_id;
533 memcpy(&sin->sin6_addr, &pjaddr->ipv6.sin6_addr,
sizeof(sin->sin6_addr));
534 addr->len =
sizeof(
struct sockaddr_in6);
536 memset(addr, 0,
sizeof(*addr));
543 const pj_sockaddr *pjaddr)
554 if (DEBUG_ATLEAST(4)) {
557 ast_debug(4,
"Comparing %s -> %s rc: %d\n", a_str, pj_str, rc);
563 #ifdef TEST_FRAMEWORK
564 static void fill_with_garbage(
void *x, ssize_t len)
566 unsigned char *w = x;
568 int r = ast_random();
569 memcpy(w, &r, len >
sizeof(r) ?
sizeof(r) : len);
577 char *candidates[] = {
584 }, **candidate = candidates;
588 info->name =
"ast_sockaddr_to_pj_sockaddr_test";
589 info->category =
"/res/res_pjproject/";
590 info->summary =
"Validate conversions from an ast_sockaddr to a pj_sockaddr";
591 info->description =
"This test converts an ast_sockaddr to a pj_sockaddr and validates\n"
592 "that the two evaluate to the same string when formatted.";
593 return AST_TEST_NOT_RUN;
603 fill_with_garbage(&pjaddr,
sizeof(pj_sockaddr));
606 ast_test_status_update(
test,
"Failed to parse candidate IP: %s\n", *candidate);
607 return AST_TEST_FAIL;
611 ast_test_status_update(
test,
"Failed to convert ast_sockaddr to pj_sockaddr: %s\n", *candidate);
612 return AST_TEST_FAIL;
615 pj_sockaddr_print(&pjaddr, buffer,
sizeof(buffer), 1 | 2);
617 if (strcmp(*candidate, buffer)) {
618 ast_test_status_update(
test,
"Converted sockaddrs do not match: \"%s\" and \"%s\"\n",
621 return AST_TEST_FAIL;
627 return AST_TEST_PASS;
632 char *candidates[] = {
639 }, **candidate = candidates;
643 info->name =
"ast_sockaddr_from_pj_sockaddr_test";
644 info->category =
"/res/res_pjproject/";
645 info->summary =
"Validate conversions from a pj_sockaddr to an ast_sockaddr";
646 info->description =
"This test converts a pj_sockaddr to an ast_sockaddr and validates\n"
647 "that the two evaluate to the same string when formatted.";
648 return AST_TEST_NOT_RUN;
659 fill_with_garbage(&addr,
sizeof(addr));
661 pj_strset(&t, *candidate, strlen(*candidate));
663 if (pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &t, &pjaddr) != PJ_SUCCESS) {
664 ast_test_status_update(
test,
"Failed to parse candidate IP: %s\n", *candidate);
665 return AST_TEST_FAIL;
669 ast_test_status_update(
test,
"Failed to convert pj_sockaddr to ast_sockaddr: %s\n", *candidate);
670 return AST_TEST_FAIL;
675 if (strcmp(*candidate, buffer)) {
676 ast_test_status_update(
test,
"Converted sockaddrs do not match: \"%s\" and \"%s\"\n",
679 return AST_TEST_FAIL;
685 return AST_TEST_PASS;
689 static int load_module(
void)
691 ast_debug(3,
"Starting PJPROJECT logging to Asterisk logger\n");
694 ast_log(LOG_ERROR,
"Failed to open SIP sorcery failed to open\n");
698 ast_sorcery_apply_default(pjproject_sorcery,
"log_mappings",
"config",
"pjproject.conf,criteria=type=log_mappings");
700 ast_log(LOG_WARNING,
"Failed to register pjproject log_mappings object with sorcery\n");
702 pjproject_sorcery = NULL;
714 default_log_mappings =
ast_sorcery_alloc(pjproject_sorcery,
"log_mappings",
"log_mappings");
715 if (!default_log_mappings) {
716 ast_log(LOG_ERROR,
"Unable to allocate memory for pjproject log_mappings\n");
729 decor_orig = pj_log_get_decor();
730 log_cb_orig = pj_log_get_log_func();
739 pj_log_set_log_func(capture_buildopts_cb);
743 pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_INDENT);
744 pj_log_set_log_func(log_forwarder);
747 "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d which is too low for startup level: %d.\n",
754 "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d which is too low to get buildopts.\n",
760 AST_TEST_REGISTER(ast_sockaddr_to_pj_sockaddr_test);
761 AST_TEST_REGISTER(ast_sockaddr_from_pj_sockaddr_test);
766 #define NOT_EQUALS(a, b) (a != b)
768 static int unload_module(
void)
771 pj_log_set_log_func(log_cb_orig);
772 pj_log_set_decor(decor_orig);
777 ast_debug(3,
"Stopped PJPROJECT logging to Asterisk logger\n");
781 ao2_cleanup(default_log_mappings);
782 default_log_mappings = NULL;
786 AST_TEST_UNREGISTER(ast_sockaddr_to_pj_sockaddr_test);
787 AST_TEST_UNREGISTER(ast_sockaddr_from_pj_sockaddr_test);
792 static int reload_module(
void)
794 if (pjproject_sorcery) {
801 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"PJPROJECT Log and Utility Support",
802 .support_level = AST_MODULE_SUPPORT_CORE,
804 .unload = unload_module,
805 .reload = reload_module,
807 .requires =
"res_sorcery_config",
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
struct ast_variable * next
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Asterisk main include file. File version handling, generic pbx functions.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define DEFAULT_PJ_LOG_MAX_LEVEL
descriptor for a cli entry.
int ast_pjproject_max_log_level
const ast_string_field asterisk_notice
Structure for variables, used for configurations and for channel variables.
Full structure for sorcery.
Type for a default handler that should do nothing.
char check[1/(6==MAX_PJ_LOG_MAX_LEVEL)]
const ast_string_field asterisk_verbose
#define ast_cli_register_multiple(e, len)
Register multiple commands.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define ast_strdup(str)
A wrapper for strdup()
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
void ast_pjproject_caching_pool_init(pj_caching_pool *cp, const pj_pool_factory_policy *policy, pj_size_t max_capacity)
Initialize the caching pool factory.
Socket address structure.
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
static ast_mutex_t pjproject_log_intercept_lock
void ast_pjproject_log_intercept_end(void)
End PJPROJECT log interception for CLI output.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_STRING_FIELD(name)
Declare a string field.
int ast_option_pjproject_log_level
void ast_pjproject_log_intercept_begin(int fd)
Begin PJPROJECT log interception for CLI output.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_pjproject_get_buildopt(char *option, char *format_string,...)
Retrieve a pjproject build option.
#define AST_VECTOR(name, type)
Define a vector structure.
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
int ast_option_pjproject_cache_pools
#define AST_PJPROJECT_INIT_LOG_LEVEL()
Get maximum log level pjproject was compiled with.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
Destroy caching pool factory and all cached pools.
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
const ast_string_field asterisk_debug
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Support for logging to various files, console and syslog Configuration in file logger.conf.
Module has failed to load, may be in an inconsistent state.
Vector container support.
const ast_string_field asterisk_trace
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
void ast_sorcery_load(const struct ast_sorcery *sorcery)
Inform any wizards to load persistent objects.
void ast_sorcery_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects.
#define MAX_PJ_LOG_MAX_LEVEL
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
int ast_sockaddr_from_pj_sockaddr(struct ast_sockaddr *addr, const pj_sockaddr *pjaddr)
Fill an ast_sockaddr from a pj_sockaddr.
Standard Command Line Interface.
#define ast_sorcery_open()
Open a new sorcery structure.
#define AST_TEST_DEFINE(hdr)
Type for default option handler for stringfields.
Options provided by main asterisk program.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
int ast_sockaddr_pj_sockaddr_cmp(const struct ast_sockaddr *addr, const pj_sockaddr *pjaddr)
Compare an ast_sockaddr to a pj_sockaddr.
const ast_string_field asterisk_warning
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
const ast_string_field asterisk_error
int ast_sockaddr_to_pj_sockaddr(const struct ast_sockaddr *addr, pj_sockaddr *pjaddr)
Fill a pj_sockaddr from an ast_sockaddr.
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Sorcery Data Access Layer API.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.