Asterisk - The Open Source Telephony Project GIT-master-f36a736
res_pjproject.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * David M. Lee, II <dlee@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Bridge PJPROJECT logging to Asterisk logging.
22 * \author David M. Lee, II <dlee@digium.com>
23 *
24 * PJPROJECT logging doesn't exactly match Asterisk logging, but mapping the two is
25 * not too bad. PJPROJECT log levels are identified by a single int. Limits are
26 * not specified by PJPROJECT, but their implementation used 1 through 6.
27 *
28 * The mapping is as follows:
29 * - 0: LOG_ERROR
30 * - 1: LOG_ERROR
31 * - 2: LOG_WARNING
32 * - 3: equivalent to ast_debug(level, ...) for res_pjproject.so
33 * - 4: equivalent to ast_debug(level, ...) for res_pjproject.so
34 * - 5: equivalent to ast_trace(level, ...) for res_pjproject.so
35 * - 6: equivalent to ast_trace(level, ...) for res_pjproject.so
36 */
37
38/*** MODULEINFO
39 <depend>pjproject</depend>
40 <depend>res_sorcery_config</depend>
41 <support_level>core</support_level>
42 ***/
43
44/*** DOCUMENTATION
45 <configInfo name="res_pjproject" language="en_US">
46 <synopsis>pjproject common configuration</synopsis>
47 <configFile name="pjproject.conf">
48 <configObject name="startup">
49 <synopsis>Asterisk startup time options for PJPROJECT</synopsis>
50 <description>
51 <note><para>The id of this object, as well as its type, must be
52 'startup' or it won't be found.</para></note>
53 </description>
54 <configOption name="type">
55 <synopsis>Must be of type 'startup'.</synopsis>
56 </configOption>
57 <configOption name="log_level" default="2">
58 <synopsis>Initial maximum pjproject logging level to log.</synopsis>
59 <description>
60 <para>Valid values are: 0-6, and default</para>
61 <note><para>
62 This option is needed very early in the startup process
63 so it can only be read from config files because the
64 modules for other methods have not been loaded yet.
65 </para></note>
66 </description>
67 </configOption>
68 </configObject>
69 <configObject name="log_mappings">
70 <synopsis>PJPROJECT to Asterisk Log Level Mapping</synopsis>
71 <description><para>Warnings and errors in the pjproject libraries are generally handled
72 by Asterisk. In many cases, Asterisk wouldn't even consider them to
73 be warnings or errors so the messages emitted by pjproject directly
74 are either superfluous or misleading. The 'log_mappings'
75 object allows mapping the pjproject levels to Asterisk levels, or nothing.
76 </para>
77 <note><para>The id of this object, as well as its type, must be
78 'log_mappings' or it won't be found.</para></note>
79 </description>
80 <configOption name="type">
81 <synopsis>Must be of type 'log_mappings'.</synopsis>
82 </configOption>
83 <configOption name="asterisk_error" default="0,1">
84 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_ERROR.</synopsis>
85 </configOption>
86 <configOption name="asterisk_warning" default="2">
87 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_WARNING.</synopsis>
88 </configOption>
89 <configOption name="asterisk_notice" default="">
90 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_NOTICE.</synopsis>
91 </configOption>
92 <configOption name="asterisk_verbose" default="">
93 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_VERBOSE.</synopsis>
94 </configOption>
95 <configOption name="asterisk_debug" default="3,4">
96 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_DEBUG.</synopsis>
97 </configOption>
98 <configOption name="asterisk_trace" default="5,6">
99 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_TRACE.</synopsis>
100 </configOption>
101 </configObject>
102 </configFile>
103 </configInfo>
104 ***/
105
106#include "asterisk.h"
107
108#include <stdarg.h>
109#include <pjlib.h>
110#include <pjsip.h>
111#include <pj/log.h>
112
113#include "asterisk/options.h"
114#include "asterisk/logger.h"
115#include "asterisk/module.h"
116#include "asterisk/cli.h"
118#include "asterisk/vector.h"
119#include "asterisk/sorcery.h"
120#include "asterisk/test.h"
121#include "asterisk/netsock2.h"
122
124static pj_log_func *log_cb_orig;
125static unsigned decor_orig;
126
128
129/*! Protection from other log intercept instances. There can be only one at a time. */
131
133 pthread_t thread;
134 int fd;
135};
136
139 .fd = -1,
140};
141
143 /*! Sorcery object details */
145 /*! These are all comma-separated lists of pjproject log levels */
147 /*! pjproject log levels mapped to Asterisk ERROR */
149 /*! pjproject log levels mapped to Asterisk WARNING */
151 /*! pjproject log levels mapped to Asterisk NOTICE */
153 /*! pjproject log levels mapped to Asterisk VERBOSE */
155 /*! pjproject log levels mapped to Asterisk DEBUG */
157 /*! pjproject log levels mapped to Asterisk TRACE */
159 );
160};
161
163
164static struct log_mappings *get_log_mappings(void)
165{
166 struct log_mappings *mappings;
167
168 mappings = ast_sorcery_retrieve_by_id(pjproject_sorcery, "log_mappings", "log_mappings");
169 if (!mappings) {
171 }
172
173 return mappings;
174}
175
176#define __LOG_SUPPRESS -1
177
178static int get_log_level(int pj_level)
179{
180 int mapped_level;
181 unsigned char l;
182 struct log_mappings *mappings;
183
185 if (!mappings) {
186 return __LOG_ERROR;
187 }
188
189 l = '0' + fmin(pj_level, 9);
190
191 if (strchr(mappings->asterisk_error, l)) {
192 mapped_level = __LOG_ERROR;
193 } else if (strchr(mappings->asterisk_warning, l)) {
194 mapped_level = __LOG_WARNING;
195 } else if (strchr(mappings->asterisk_notice, l)) {
196 mapped_level = __LOG_NOTICE;
197 } else if (strchr(mappings->asterisk_verbose, l)) {
198 mapped_level = __LOG_VERBOSE;
199 } else if (strchr(mappings->asterisk_debug, l)) {
200 mapped_level = __LOG_DEBUG;
201 } else if (strchr(mappings->asterisk_trace, l)) {
202 mapped_level = __LOG_TRACE;
203 } else {
204 mapped_level = __LOG_SUPPRESS;
205 }
206
207 ao2_ref(mappings, -1);
208 return mapped_level;
209}
210
211static void log_forwarder(int level, const char *data, int len)
212{
213 int ast_level;
214 /* PJPROJECT doesn't provide much in the way of source info */
215 const char * log_source = "pjproject";
216 int log_line = 0;
217 const char *log_func = "<?>";
218
220 && pjproject_log_intercept.thread == pthread_self()) {
221 /*
222 * We are handling a CLI command intercepting PJPROJECT
223 * log output.
224 */
225 ast_cli(pjproject_log_intercept.fd, "%s\n", data);
226 return;
227 }
228
229 ast_level = get_log_level(level);
230
231 if (ast_level == __LOG_SUPPRESS) {
232 return;
233 }
234
235 /* PJPROJECT uses indention to indicate function call depth. We'll prepend
236 * log statements with a tab so they'll have a better shot at lining
237 * up */
238 ast_log(ast_level, log_source, log_line, log_func, "\t%s\n", data);
239}
240
241static void capture_buildopts_cb(int level, const char *data, int len)
242{
243 char *dup;
244
245 if (strstr(data, "Teluu") || strstr(data, "Dumping")) {
246 return;
247 }
248
249 dup = ast_strdup(ast_skip_blanks(data));
250 if (dup && AST_VECTOR_ADD_SORTED(&buildopts, dup, strcmp)) {
251 ast_free(dup);
252 }
253}
254
255#pragma GCC diagnostic ignored "-Wformat-nonliteral"
256int ast_pjproject_get_buildopt(char *option, char *format_string, ...)
257{
258 int res = 0;
259 char *format_temp;
260 int i;
261
262 format_temp = ast_alloca(strlen(option) + strlen(" : ") + strlen(format_string) + 1);
263 sprintf(format_temp, "%s : %s", option, format_string);
264
265 for (i = 0; i < AST_VECTOR_SIZE(&buildopts); i++) {
266 va_list arg_ptr;
267 va_start(arg_ptr, format_string);
268 res = vsscanf(AST_VECTOR_GET(&buildopts, i), format_temp, arg_ptr);
269 va_end(arg_ptr);
270 if (res) {
271 break;
272 }
273 }
274
275 return res;
276}
277#pragma GCC diagnostic warning "-Wformat-nonliteral"
278
280{
281 /* Protect from other CLI instances trying to do this at the same time. */
283
284 pjproject_log_intercept.thread = pthread_self();
286}
287
289{
292
294}
295
296static char *handle_pjproject_show_buildopts(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
297{
298 int i;
299
300 switch (cmd) {
301 case CLI_INIT:
302 e->command = "pjproject show buildopts";
303 e->usage =
304 "Usage: pjproject show buildopts\n"
305 " Show the compile time config of the pjproject that Asterisk is\n"
306 " running against.\n";
307 return NULL;
308 case CLI_GENERATE:
309 return NULL;
310 }
311
312 ast_cli(a->fd, "PJPROJECT compile time config currently running against:\n");
313
314 for (i = 0; i < AST_VECTOR_SIZE(&buildopts); i++) {
315 ast_cli(a->fd, "%s\n", AST_VECTOR_GET(&buildopts, i));
316 }
317
318 return CLI_SUCCESS;
319}
320
321static void mapping_destroy(void *object)
322{
323 struct log_mappings *mappings = object;
324
326}
327
328static void *mapping_alloc(const char *name)
329{
331 if (!mappings) {
332 return NULL;
333 }
335
336 return mappings;
337}
338
339static char *handle_pjproject_show_log_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
340{
341 struct ast_variable *objset;
342 struct ast_variable *i;
343 struct log_mappings *mappings;
344
345 switch (cmd) {
346 case CLI_INIT:
347 e->command = "pjproject show log mappings";
348 e->usage =
349 "Usage: pjproject show log mappings\n"
350 " Show pjproject to Asterisk log mappings\n";
351 return NULL;
352 case CLI_GENERATE:
353 return NULL;
354 }
355
356 ast_cli(a->fd, "PJPROJECT to Asterisk log mappings:\n");
357 ast_cli(a->fd, "Asterisk Level : PJPROJECT log levels\n");
358
360 if (!mappings) {
361 ast_log(LOG_ERROR, "Unable to retrieve pjproject log_mappings\n");
362 return CLI_SUCCESS;
363 }
364
366 if (!objset) {
367 ao2_ref(mappings, -1);
368 return CLI_SUCCESS;
369 }
370
371 for (i = objset; i; i = i->next) {
372 ast_cli(a->fd, "%-16s : %s\n", i->name, i->value);
373 }
374 ast_variables_destroy(objset);
375
376 ao2_ref(mappings, -1);
377 return CLI_SUCCESS;
378}
379
381 /*!
382 * Compile time sanity check to determine if
383 * MAX_PJ_LOG_MAX_LEVEL matches CLI syntax.
384 */
385 char check[1 / (6 == MAX_PJ_LOG_MAX_LEVEL)];
386};
387
388static char *handle_pjproject_set_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
389{
390 int level_new;
391 int level_old;
392
393 switch (cmd) {
394 case CLI_INIT:
395 e->command = "pjproject set log level {default|0|1|2|3|4|5|6}";
396 e->usage =
397 "Usage: pjproject set log level {default|<level>}\n"
398 "\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";
404 return NULL;
405 case CLI_GENERATE:
406 return NULL;
407 }
408
409 if (a->argc != 5) {
410 return CLI_SHOWUSAGE;
411 }
412
413 if (!strcasecmp(a->argv[4], "default")) {
414 level_new = DEFAULT_PJ_LOG_MAX_LEVEL;
415 } else {
416 if (sscanf(a->argv[4], "%30d", &level_new) != 1
417 || level_new < 0 || MAX_PJ_LOG_MAX_LEVEL < level_new) {
418 return CLI_SHOWUSAGE;
419 }
420 }
421
422 /* Update pjproject logging level */
423 if (ast_pjproject_max_log_level < level_new) {
424 level_new = ast_pjproject_max_log_level;
425 ast_cli(a->fd,
426 "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d.\n"
427 "Lowering request to the max supported level.\n",
429 }
431 if (level_old == level_new) {
432 ast_cli(a->fd, "pjproject log level is still %d.\n", level_old);
433 } else {
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);
438 }
439
440 return CLI_SUCCESS;
441}
442
443static char *handle_pjproject_show_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
444{
445 switch (cmd) {
446 case CLI_INIT:
447 e->command = "pjproject show log level";
448 e->usage =
449 "Usage: pjproject show log level\n"
450 "\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";
454 return NULL;
455 case CLI_GENERATE:
456 return NULL;
457 }
458
459 if (a->argc != 4) {
460 return CLI_SHOWUSAGE;
461 }
462
463 ast_cli(a->fd, "pjproject log level is %d.%s\n",
466
467 return CLI_SUCCESS;
468}
469
470static struct ast_cli_entry pjproject_cli[] = {
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"),
475};
476
477void ast_pjproject_caching_pool_init(pj_caching_pool *cp,
478 const pj_pool_factory_policy *policy, pj_size_t max_capacity)
479{
480 /* Passing a max_capacity of zero disables caching pools */
481 pj_caching_pool_init(cp, policy, ast_option_pjproject_cache_pools ? max_capacity : 0);
482}
483
484void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
485{
486 pj_caching_pool_destroy(cp);
487}
488
489int ast_sockaddr_to_pj_sockaddr(const struct ast_sockaddr *addr, pj_sockaddr *pjaddr)
490{
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;
496#else
497 pjaddr->ipv4.sin_addr.s_addr = sin->sin_addr.s_addr;
498#endif
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));
507 } else {
508 memset(pjaddr, 0, sizeof(*pjaddr));
509 return -1;
510 }
511 return 0;
512}
513
514int ast_sockaddr_from_pj_sockaddr(struct ast_sockaddr *addr, const pj_sockaddr *pjaddr)
515{
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;
521#else
522 sin->sin_addr.s_addr = pjaddr->ipv4.sin_addr.s_addr;
523#endif
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);
535 } else {
536 memset(addr, 0, sizeof(*addr));
537 return -1;
538 }
539 return 0;
540}
541
543 const pj_sockaddr *pjaddr)
544{
545 struct ast_sockaddr temp_pjaddr;
546 int rc = 0;
547
548 rc = ast_sockaddr_from_pj_sockaddr(&temp_pjaddr, pjaddr);
549 if (rc != 0) {
550 return -1;
551 }
552
553 rc = ast_sockaddr_cmp(addr, &temp_pjaddr);
554 if (DEBUG_ATLEAST(4)) {
555 char *a_str = ast_strdupa(ast_sockaddr_stringify(addr));
556 char *pj_str = ast_strdupa(ast_sockaddr_stringify(&temp_pjaddr));
557 ast_debug(4, "Comparing %s -> %s rc: %d\n", a_str, pj_str, rc);
558 }
559
560 return rc;
561}
562
563#ifdef TEST_FRAMEWORK
564static void fill_with_garbage(void *x, ssize_t len)
565{
566 unsigned char *w = x;
567 while (len > 0) {
568 int r = ast_random();
569 memcpy(w, &r, len > sizeof(r) ? sizeof(r) : len);
570 w += sizeof(r);
571 len -= sizeof(r);
572 }
573}
574
575AST_TEST_DEFINE(ast_sockaddr_to_pj_sockaddr_test)
576{
577 char *candidates[] = {
578 "127.0.0.1:5555",
579 "[::]:4444",
580 "192.168.0.100:0",
581 "[fec0::1:80]:0",
582 "[fec0::1]:80",
583 NULL,
584 }, **candidate = candidates;
585
586 switch (cmd) {
587 case TEST_INIT:
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;
594 case TEST_EXECUTE:
595 break;
596 }
597
598 while (*candidate) {
599 struct ast_sockaddr addr = {{0,}};
600 pj_sockaddr pjaddr;
601 char buffer[512];
602
603 fill_with_garbage(&pjaddr, sizeof(pj_sockaddr));
604
605 if (!ast_sockaddr_parse(&addr, *candidate, 0)) {
606 ast_test_status_update(test, "Failed to parse candidate IP: %s\n", *candidate);
607 return AST_TEST_FAIL;
608 }
609
610 if (ast_sockaddr_to_pj_sockaddr(&addr, &pjaddr)) {
611 ast_test_status_update(test, "Failed to convert ast_sockaddr to pj_sockaddr: %s\n", *candidate);
612 return AST_TEST_FAIL;
613 }
614
615 pj_sockaddr_print(&pjaddr, buffer, sizeof(buffer), 1 | 2);
616
617 if (strcmp(*candidate, buffer)) {
618 ast_test_status_update(test, "Converted sockaddrs do not match: \"%s\" and \"%s\"\n",
619 *candidate,
620 buffer);
621 return AST_TEST_FAIL;
622 }
623
624 candidate++;
625 }
626
627 return AST_TEST_PASS;
628}
629
630AST_TEST_DEFINE(ast_sockaddr_from_pj_sockaddr_test)
631{
632 char *candidates[] = {
633 "127.0.0.1:5555",
634 "[::]:4444",
635 "192.168.0.100:0",
636 "[fec0::1:80]:0",
637 "[fec0::1]:80",
638 NULL,
639 }, **candidate = candidates;
640
641 switch (cmd) {
642 case TEST_INIT:
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;
649 case TEST_EXECUTE:
650 break;
651 }
652
653 while (*candidate) {
654 struct ast_sockaddr addr = {{0,}};
655 pj_sockaddr pjaddr;
656 pj_str_t t;
657 char buffer[512];
658
659 fill_with_garbage(&addr, sizeof(addr));
660
661 pj_strset(&t, *candidate, strlen(*candidate));
662
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;
666 }
667
668 if (ast_sockaddr_from_pj_sockaddr(&addr, &pjaddr)) {
669 ast_test_status_update(test, "Failed to convert pj_sockaddr to ast_sockaddr: %s\n", *candidate);
670 return AST_TEST_FAIL;
671 }
672
673 snprintf(buffer, sizeof(buffer), "%s", ast_sockaddr_stringify(&addr));
674
675 if (strcmp(*candidate, buffer)) {
676 ast_test_status_update(test, "Converted sockaddrs do not match: \"%s\" and \"%s\"\n",
677 *candidate,
678 buffer);
679 return AST_TEST_FAIL;
680 }
681
682 candidate++;
683 }
684
685 return AST_TEST_PASS;
686}
687#endif
688
689static int load_module(void)
690{
691 ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n");
692
694 ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
696 }
697
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");
704 }
705
706 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "type", "", OPT_NOOP_T, 0, 0);
707 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_debug", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_debug));
708 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_error", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_error));
709 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_warning", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_warning));
710 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_notice", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_notice));
711 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_verbose", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_verbose));
712 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_trace", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_trace));
713
714 default_log_mappings = ast_sorcery_alloc(pjproject_sorcery, "log_mappings", "log_mappings");
716 ast_log(LOG_ERROR, "Unable to allocate memory for pjproject log_mappings\n");
718 }
719 ast_string_field_set(default_log_mappings, asterisk_error, "0,1");
720 ast_string_field_set(default_log_mappings, asterisk_warning, "2");
721 ast_string_field_set(default_log_mappings, asterisk_debug, "3,4");
722 ast_string_field_set(default_log_mappings, asterisk_trace, "5,6");
723
725
727 pj_init();
728
729 decor_orig = pj_log_get_decor();
730 log_cb_orig = pj_log_get_log_func();
731
732 if (AST_VECTOR_INIT(&buildopts, 64)) {
734 }
735
736 /*
737 * On startup, we want to capture the dump once and store it.
738 */
739 pj_log_set_log_func(capture_buildopts_cb);
740 pj_log_set_decor(0);
741 pj_log_set_level(MAX_PJ_LOG_MAX_LEVEL);/* Set level to guarantee the dump output. */
742 pj_dump_config();
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",
750 }
751 pj_log_set_level(ast_option_pjproject_log_level);
752 if (!AST_VECTOR_SIZE(&buildopts)) {
754 "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d which is too low to get buildopts.\n",
756 }
757
759
760 AST_TEST_REGISTER(ast_sockaddr_to_pj_sockaddr_test);
761 AST_TEST_REGISTER(ast_sockaddr_from_pj_sockaddr_test);
762
764}
765
766#define NOT_EQUALS(a, b) (a != b)
767
768static int unload_module(void)
769{
771 pj_log_set_log_func(log_cb_orig);
772 pj_log_set_decor(decor_orig);
773
776
777 ast_debug(3, "Stopped PJPROJECT logging to Asterisk logger\n");
778
779 pj_shutdown();
780
783
785
786 AST_TEST_UNREGISTER(ast_sockaddr_to_pj_sockaddr_test);
787 AST_TEST_UNREGISTER(ast_sockaddr_from_pj_sockaddr_test);
788
789 return 0;
790}
791
792static int reload_module(void)
793{
794 if (pjproject_sorcery) {
796 }
797
799}
800
802 .support_level = AST_MODULE_SUPPORT_CORE,
803 .load = load_module,
804 .unload = unload_module,
806 .load_pri = AST_MODPRI_CHANNEL_DEPEND - 6,
807 .requires = "res_sorcery_config",
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int ast_pjproject_max_log_level
Definition: options.c:73
int ast_option_pjproject_log_level
Definition: options.c:74
int ast_option_pjproject_cache_pools
Definition: options.c:75
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
Support for logging to various files, console and syslog Configuration in file logger....
#define __LOG_ERROR
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
#define __LOG_TRACE
#define __LOG_VERBOSE
#define __LOG_NOTICE
#define __LOG_DEBUG
#define __LOG_WARNING
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:330
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_CHANNEL_DEPEND
Definition: module.h:340
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
def info(msg)
Network socket handling.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:388
Options provided by main asterisk program.
#define MAX_PJ_LOG_MAX_LEVEL
Definition: options.h:141
#define AST_PJPROJECT_INIT_LOG_LEVEL()
Get maximum log level pjproject was compiled with.
Definition: options.h:167
#define DEFAULT_PJ_LOG_MAX_LEVEL
Definition: options.h:149
static struct mappings mappings
static int reload(void)
static struct ast_sorcery * pjproject_sorcery
static char * handle_pjproject_show_buildopts(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
void ast_pjproject_log_intercept_begin(int fd)
Begin PJPROJECT log interception for CLI output.
void ast_pjproject_log_intercept_end(void)
End PJPROJECT log interception for CLI output.
static pj_log_func * log_cb_orig
int ast_sockaddr_to_pj_sockaddr(const struct ast_sockaddr *addr, pj_sockaddr *pjaddr)
Fill a pj_sockaddr from an ast_sockaddr.
static unsigned decor_orig
void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
Destroy caching pool factory and all cached pools.
static void mapping_destroy(void *object)
int ast_sockaddr_pj_sockaddr_cmp(const struct ast_sockaddr *addr, const pj_sockaddr *pjaddr)
Compare an ast_sockaddr to a pj_sockaddr.
static struct pjproject_log_intercept_data pjproject_log_intercept
static void * mapping_alloc(const char *name)
static char * handle_pjproject_show_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void capture_buildopts_cb(int level, const char *data, int len)
static char * handle_pjproject_show_log_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int reload_module(void)
static struct buildopts buildopts
static struct ast_cli_entry pjproject_cli[]
#define __LOG_SUPPRESS
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.
int ast_pjproject_get_buildopt(char *option, char *format_string,...)
Retrieve a pjproject build option.
static ast_mutex_t pjproject_log_intercept_lock
int ast_sockaddr_from_pj_sockaddr(struct ast_sockaddr *addr, const pj_sockaddr *pjaddr)
Fill an ast_sockaddr from a pj_sockaddr.
static int get_log_level(int pj_level)
static void log_forwarder(int level, const char *data, int len)
static int load_module(void)
static struct log_mappings * default_log_mappings
static struct log_mappings * get_log_mappings(void)
static int unload_module(void)
static char * handle_pjproject_set_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define NULL
Definition: resample.c:96
Sorcery Data Access Layer API.
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1137
void ast_sorcery_load(const struct ast_sorcery *sorcery)
Inform any wizards to load persistent objects.
Definition: sorcery.c:1377
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
void ast_sorcery_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects.
Definition: sorcery.c:1408
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
#define ast_sorcery_open()
Open a new sorcery structure.
Definition: sorcery.h:406
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Socket address structure.
Definition: netsock2.h:97
struct sockaddr_storage ss
Definition: netsock2.h:98
socklen_t len
Definition: netsock2.h:99
Full structure for sorcery.
Definition: sorcery.c:230
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
SORCERY_OBJECT(details)
const ast_string_field asterisk_debug
const ast_string_field asterisk_trace
const ast_string_field asterisk_error
const ast_string_field asterisk_verbose
const ast_string_field asterisk_warning
const ast_string_field asterisk_notice
char check[1/(6==MAX_PJ_LOG_MAX_LEVEL)]
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
static struct test_val a
long int ast_random(void)
Definition: utils.c:2312
#define ARRAY_LEN(a)
Definition: utils.h:666
Vector container support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Definition: vector.h:371
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680