Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 <since>
71 <version>13.8.0</version>
72 </since>
73 <synopsis>PJPROJECT to Asterisk Log Level Mapping</synopsis>
74 <description><para>Warnings and errors in the pjproject libraries are generally handled
75 by Asterisk. In many cases, Asterisk wouldn't even consider them to
76 be warnings or errors so the messages emitted by pjproject directly
77 are either superfluous or misleading. The 'log_mappings'
78 object allows mapping the pjproject levels to Asterisk levels, or nothing.
79 </para>
80 <note><para>The id of this object, as well as its type, must be
81 'log_mappings' or it won't be found.</para></note>
82 </description>
83 <configOption name="type">
84 <since>
85 <version>13.8.0</version>
86 </since>
87 <synopsis>Must be of type 'log_mappings'.</synopsis>
88 </configOption>
89 <configOption name="asterisk_error" default="0,1">
90 <since>
91 <version>13.8.0</version>
92 </since>
93 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_ERROR.</synopsis>
94 </configOption>
95 <configOption name="asterisk_warning" default="2">
96 <since>
97 <version>13.8.0</version>
98 </since>
99 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_WARNING.</synopsis>
100 </configOption>
101 <configOption name="asterisk_notice" default="">
102 <since>
103 <version>13.8.0</version>
104 </since>
105 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_NOTICE.</synopsis>
106 </configOption>
107 <configOption name="asterisk_verbose" default="">
108 <since>
109 <version>13.8.0</version>
110 </since>
111 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_VERBOSE.</synopsis>
112 </configOption>
113 <configOption name="asterisk_debug" default="3,4">
114 <since>
115 <version>13.8.0</version>
116 </since>
117 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_DEBUG.</synopsis>
118 </configOption>
119 <configOption name="asterisk_trace" default="5,6">
120 <since>
121 <version>16.21.0</version>
122 <version>18.7.0</version>
123 </since>
124 <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_TRACE.</synopsis>
125 </configOption>
126 </configObject>
127 </configFile>
128 </configInfo>
129 ***/
130
131#include "asterisk.h"
132
133#include <stdarg.h>
134#include <pjlib.h>
135#include <pjsip.h>
136#include <pj/log.h>
137
138#include "asterisk/options.h"
139#include "asterisk/logger.h"
140#include "asterisk/module.h"
141#include "asterisk/cli.h"
143#include "asterisk/vector.h"
144#include "asterisk/sorcery.h"
145#include "asterisk/test.h"
146#include "asterisk/netsock2.h"
147
149static pj_log_func *log_cb_orig;
150static unsigned decor_orig;
151
153
154/*! Protection from other log intercept instances. There can be only one at a time. */
156
158 pthread_t thread;
159 int fd;
160};
161
164 .fd = -1,
165};
166
168 /*! Sorcery object details */
170 /*! These are all comma-separated lists of pjproject log levels */
172 /*! pjproject log levels mapped to Asterisk ERROR */
174 /*! pjproject log levels mapped to Asterisk WARNING */
176 /*! pjproject log levels mapped to Asterisk NOTICE */
178 /*! pjproject log levels mapped to Asterisk VERBOSE */
180 /*! pjproject log levels mapped to Asterisk DEBUG */
182 /*! pjproject log levels mapped to Asterisk TRACE */
184 );
185};
186
188
189static struct log_mappings *get_log_mappings(void)
190{
191 struct log_mappings *mappings;
192
193 mappings = ast_sorcery_retrieve_by_id(pjproject_sorcery, "log_mappings", "log_mappings");
194 if (!mappings) {
196 }
197
198 return mappings;
199}
200
201#define __LOG_SUPPRESS -1
202
203static int get_log_level(int pj_level)
204{
205 int mapped_level;
206 unsigned char l;
207 struct log_mappings *mappings;
208
210 if (!mappings) {
211 return __LOG_ERROR;
212 }
213
214 l = '0' + fmin(pj_level, 9);
215
216 if (strchr(mappings->asterisk_error, l)) {
217 mapped_level = __LOG_ERROR;
218 } else if (strchr(mappings->asterisk_warning, l)) {
219 mapped_level = __LOG_WARNING;
220 } else if (strchr(mappings->asterisk_notice, l)) {
221 mapped_level = __LOG_NOTICE;
222 } else if (strchr(mappings->asterisk_verbose, l)) {
223 mapped_level = __LOG_VERBOSE;
224 } else if (strchr(mappings->asterisk_debug, l)) {
225 mapped_level = __LOG_DEBUG;
226 } else if (strchr(mappings->asterisk_trace, l)) {
227 mapped_level = __LOG_TRACE;
228 } else {
229 mapped_level = __LOG_SUPPRESS;
230 }
231
232 ao2_ref(mappings, -1);
233 return mapped_level;
234}
235
236static void log_forwarder(int level, const char *data, int len)
237{
238 int ast_level;
239 /* PJPROJECT doesn't provide much in the way of source info */
240 const char * log_source = "pjproject";
241 int log_line = 0;
242 const char *log_func = "<?>";
243
245 && pjproject_log_intercept.thread == pthread_self()) {
246 /*
247 * We are handling a CLI command intercepting PJPROJECT
248 * log output.
249 */
250 ast_cli(pjproject_log_intercept.fd, "%s\n", data);
251 return;
252 }
253
254 ast_level = get_log_level(level);
255
256 if (ast_level == __LOG_SUPPRESS) {
257 return;
258 }
259
260 /* PJPROJECT uses indention to indicate function call depth. We'll prepend
261 * log statements with a tab so they'll have a better shot at lining
262 * up */
263 ast_log(ast_level, log_source, log_line, log_func, "\t%s\n", data);
264}
265
266static void capture_buildopts_cb(int level, const char *data, int len)
267{
268 char *dup;
269
270 if (strstr(data, "Teluu") || strstr(data, "Dumping")) {
271 return;
272 }
273
274 dup = ast_strdup(ast_skip_blanks(data));
275 if (dup && AST_VECTOR_ADD_SORTED(&buildopts, dup, strcmp)) {
276 ast_free(dup);
277 }
278}
279
280#pragma GCC diagnostic ignored "-Wformat-nonliteral"
281int ast_pjproject_get_buildopt(char *option, char *format_string, ...)
282{
283 int res = 0;
284 char *format_temp;
285 int i;
286
287 format_temp = ast_alloca(strlen(option) + strlen(" : ") + strlen(format_string) + 1);
288 sprintf(format_temp, "%s : %s", option, format_string);
289
290 for (i = 0; i < AST_VECTOR_SIZE(&buildopts); i++) {
291 va_list arg_ptr;
292 va_start(arg_ptr, format_string);
293 res = vsscanf(AST_VECTOR_GET(&buildopts, i), format_temp, arg_ptr);
294 va_end(arg_ptr);
295 if (res) {
296 break;
297 }
298 }
299
300 return res;
301}
302#pragma GCC diagnostic warning "-Wformat-nonliteral"
303
305{
306 /* Protect from other CLI instances trying to do this at the same time. */
308
309 pjproject_log_intercept.thread = pthread_self();
311}
312
314{
317
319}
320
321static char *handle_pjproject_show_buildopts(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
322{
323 int i;
324
325 switch (cmd) {
326 case CLI_INIT:
327 e->command = "pjproject show buildopts";
328 e->usage =
329 "Usage: pjproject show buildopts\n"
330 " Show the compile time config of the pjproject that Asterisk is\n"
331 " running against.\n";
332 return NULL;
333 case CLI_GENERATE:
334 return NULL;
335 }
336
337 ast_cli(a->fd, "PJPROJECT compile time config currently running against:\n");
338
339 for (i = 0; i < AST_VECTOR_SIZE(&buildopts); i++) {
340 ast_cli(a->fd, "%s\n", AST_VECTOR_GET(&buildopts, i));
341 }
342
343#ifdef HAVE_PJSIP_AUTH_NEW_DIGESTS
344 {
345 struct ast_str *buf = ast_str_alloca(256);
347 const pjsip_auth_algorithm *algorithm = pjsip_auth_get_algorithm_by_type(i);
348 if (!ast_strlen_zero(algorithm->openssl_name)) {
349 if (pjsip_auth_is_algorithm_supported(i)) {
350 ast_str_append(&buf, 0, "%.*s/%s, ", (int)algorithm->iana_name.slen,
351 algorithm->iana_name.ptr, algorithm->openssl_name);
352 }
353 }
354 }
355 /* Trim off the trailing ", " */
357 ast_cli(a->fd, "Supported Digest Algorithms (IANA name/OpenSSL name): %s\n", ast_str_buffer(buf));
358 }
359#else
360 ast_cli(a->fd, "Supported Digest Algorithms (IANA name/OpenSSL name): MD5/MD5\n");
361#endif
362
363 return CLI_SUCCESS;
364}
365
366static void mapping_destroy(void *object)
367{
368 struct log_mappings *mappings = object;
369
371}
372
373static void *mapping_alloc(const char *name)
374{
376 if (!mappings) {
377 return NULL;
378 }
380
381 return mappings;
382}
383
384static char *handle_pjproject_show_log_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
385{
386 struct ast_variable *objset;
387 struct ast_variable *i;
388 struct log_mappings *mappings;
389
390 switch (cmd) {
391 case CLI_INIT:
392 e->command = "pjproject show log mappings";
393 e->usage =
394 "Usage: pjproject show log mappings\n"
395 " Show pjproject to Asterisk log mappings\n";
396 return NULL;
397 case CLI_GENERATE:
398 return NULL;
399 }
400
401 ast_cli(a->fd, "PJPROJECT to Asterisk log mappings:\n");
402 ast_cli(a->fd, "Asterisk Level : PJPROJECT log levels\n");
403
405 if (!mappings) {
406 ast_log(LOG_ERROR, "Unable to retrieve pjproject log_mappings\n");
407 return CLI_SUCCESS;
408 }
409
411 if (!objset) {
412 ao2_ref(mappings, -1);
413 return CLI_SUCCESS;
414 }
415
416 for (i = objset; i; i = i->next) {
417 ast_cli(a->fd, "%-16s : %s\n", i->name, i->value);
418 }
419 ast_variables_destroy(objset);
420
421 ao2_ref(mappings, -1);
422 return CLI_SUCCESS;
423}
424
426 /*!
427 * Compile time sanity check to determine if
428 * MAX_PJ_LOG_MAX_LEVEL matches CLI syntax.
429 */
430 char check[1 / (6 == MAX_PJ_LOG_MAX_LEVEL)];
431};
432
433static char *handle_pjproject_set_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
434{
435 int level_new;
436 int level_old;
437
438 switch (cmd) {
439 case CLI_INIT:
440 e->command = "pjproject set log level {default|0|1|2|3|4|5|6}";
441 e->usage =
442 "Usage: pjproject set log level {default|<level>}\n"
443 "\n"
444 " Set the maximum active pjproject logging level.\n"
445 " See pjproject.conf.sample for additional information\n"
446 " about the various levels pjproject uses.\n"
447 " Note: setting this level at 4 or above may result in\n"
448 " raw packet logging.\n";
449 return NULL;
450 case CLI_GENERATE:
451 return NULL;
452 }
453
454 if (a->argc != 5) {
455 return CLI_SHOWUSAGE;
456 }
457
458 if (!strcasecmp(a->argv[4], "default")) {
459 level_new = DEFAULT_PJ_LOG_MAX_LEVEL;
460 } else {
461 if (sscanf(a->argv[4], "%30d", &level_new) != 1
462 || level_new < 0 || MAX_PJ_LOG_MAX_LEVEL < level_new) {
463 return CLI_SHOWUSAGE;
464 }
465 }
466
467 /* Update pjproject logging level */
468 if (ast_pjproject_max_log_level < level_new) {
469 level_new = ast_pjproject_max_log_level;
470 ast_cli(a->fd,
471 "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d.\n"
472 "Lowering request to the max supported level.\n",
474 }
476 if (level_old == level_new) {
477 ast_cli(a->fd, "pjproject log level is still %d.\n", level_old);
478 } else {
479 ast_cli(a->fd, "pjproject log level was %d and is now %d.\n",
480 level_old, level_new);
482 pj_log_set_level(level_new);
483 }
484
485 return CLI_SUCCESS;
486}
487
488static char *handle_pjproject_show_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
489{
490 switch (cmd) {
491 case CLI_INIT:
492 e->command = "pjproject show log level";
493 e->usage =
494 "Usage: pjproject show log level\n"
495 "\n"
496 " Show the current maximum active pjproject logging level.\n"
497 " See pjproject.conf.sample for additional information\n"
498 " about the various levels pjproject uses.\n";
499 return NULL;
500 case CLI_GENERATE:
501 return NULL;
502 }
503
504 if (a->argc != 4) {
505 return CLI_SHOWUSAGE;
506 }
507
508 ast_cli(a->fd, "pjproject log level is %d.%s\n",
511
512 return CLI_SUCCESS;
513}
514
515static struct ast_cli_entry pjproject_cli[] = {
516 AST_CLI_DEFINE(handle_pjproject_set_log_level, "Set the maximum active pjproject logging level"),
517 AST_CLI_DEFINE(handle_pjproject_show_buildopts, "Show the compiled config of the pjproject in use"),
518 AST_CLI_DEFINE(handle_pjproject_show_log_mappings, "Show pjproject to Asterisk log mappings"),
519 AST_CLI_DEFINE(handle_pjproject_show_log_level, "Show the maximum active pjproject logging level"),
520};
521
522void ast_pjproject_caching_pool_init(pj_caching_pool *cp,
523 const pj_pool_factory_policy *policy, pj_size_t max_capacity)
524{
525 /* Passing a max_capacity of zero disables caching pools */
526 pj_caching_pool_init(cp, policy, ast_option_pjproject_cache_pools ? max_capacity : 0);
527}
528
529void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
530{
531 pj_caching_pool_destroy(cp);
532}
533
534int ast_sockaddr_to_pj_sockaddr(const struct ast_sockaddr *addr, pj_sockaddr *pjaddr)
535{
536 if (addr->ss.ss_family == AF_INET) {
537 struct sockaddr_in *sin = (struct sockaddr_in *) &addr->ss;
538 pjaddr->ipv4.sin_family = pj_AF_INET();
539#if defined(HAVE_PJPROJECT_BUNDLED) && !defined(HAVE_PJPROJECT_BUNDLED_OOT)
540 pjaddr->ipv4.sin_addr = sin->sin_addr;
541#else
542 pjaddr->ipv4.sin_addr.s_addr = sin->sin_addr.s_addr;
543#endif
544 pjaddr->ipv4.sin_port = sin->sin_port;
545 } else if (addr->ss.ss_family == AF_INET6) {
546 struct sockaddr_in6 *sin = (struct sockaddr_in6 *) &addr->ss;
547 pjaddr->ipv6.sin6_family = pj_AF_INET6();
548 pjaddr->ipv6.sin6_port = sin->sin6_port;
549 pjaddr->ipv6.sin6_flowinfo = sin->sin6_flowinfo;
550 pjaddr->ipv6.sin6_scope_id = sin->sin6_scope_id;
551 memcpy(&pjaddr->ipv6.sin6_addr, &sin->sin6_addr, sizeof(pjaddr->ipv6.sin6_addr));
552 } else {
553 memset(pjaddr, 0, sizeof(*pjaddr));
554 return -1;
555 }
556 return 0;
557}
558
559int ast_sockaddr_from_pj_sockaddr(struct ast_sockaddr *addr, const pj_sockaddr *pjaddr)
560{
561 if (pjaddr->addr.sa_family == pj_AF_INET()) {
562 struct sockaddr_in *sin = (struct sockaddr_in *) &addr->ss;
563#if defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
564 sin->sin_len = sizeof(struct sockaddr_in);
565#endif
566 sin->sin_family = AF_INET;
567#if defined(HAVE_PJPROJECT_BUNDLED) && !defined(HAVE_PJPROJECT_BUNDLED_OOT)
568 sin->sin_addr = pjaddr->ipv4.sin_addr;
569#else
570 sin->sin_addr.s_addr = pjaddr->ipv4.sin_addr.s_addr;
571#endif
572 sin->sin_port = pjaddr->ipv4.sin_port;
573 memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
574 addr->len = sizeof(struct sockaddr_in);
575 } else if (pjaddr->addr.sa_family == pj_AF_INET6()) {
576 struct sockaddr_in6 *sin = (struct sockaddr_in6 *) &addr->ss;
577#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN)
578 sin->sin6_len = sizeof(struct sockaddr_in6);
579#endif
580 sin->sin6_family = AF_INET6;
581 sin->sin6_port = pjaddr->ipv6.sin6_port;
582 sin->sin6_flowinfo = pjaddr->ipv6.sin6_flowinfo;
583 sin->sin6_scope_id = pjaddr->ipv6.sin6_scope_id;
584 memcpy(&sin->sin6_addr, &pjaddr->ipv6.sin6_addr, sizeof(sin->sin6_addr));
585 addr->len = sizeof(struct sockaddr_in6);
586 } else {
587 memset(addr, 0, sizeof(*addr));
588 return -1;
589 }
590 return 0;
591}
592
594 const pj_sockaddr *pjaddr)
595{
596 struct ast_sockaddr temp_pjaddr;
597 int rc = 0;
598
599 rc = ast_sockaddr_from_pj_sockaddr(&temp_pjaddr, pjaddr);
600 if (rc != 0) {
601 return -1;
602 }
603
604 rc = ast_sockaddr_cmp(addr, &temp_pjaddr);
605 if (DEBUG_ATLEAST(4)) {
606 char *a_str = ast_strdupa(ast_sockaddr_stringify(addr));
607 char *pj_str = ast_strdupa(ast_sockaddr_stringify(&temp_pjaddr));
608 ast_debug(4, "Comparing %s -> %s rc: %d\n", a_str, pj_str, rc);
609 }
610
611 return rc;
612}
613
614#ifdef TEST_FRAMEWORK
615static void fill_with_garbage(void *x, ssize_t len)
616{
617 unsigned char *w = x;
618 while (len > 0) {
619 int r = ast_random();
620 memcpy(w, &r, len > sizeof(r) ? sizeof(r) : len);
621 w += sizeof(r);
622 len -= sizeof(r);
623 }
624}
625
626AST_TEST_DEFINE(ast_sockaddr_to_pj_sockaddr_test)
627{
628 char *candidates[] = {
629 "127.0.0.1:5555",
630 "[::]:4444",
631 "192.168.0.100:0",
632 "[fec0::1:80]:0",
633 "[fec0::1]:80",
634 NULL,
635 }, **candidate = candidates;
636
637 switch (cmd) {
638 case TEST_INIT:
639 info->name = "ast_sockaddr_to_pj_sockaddr_test";
640 info->category = "/res/res_pjproject/";
641 info->summary = "Validate conversions from an ast_sockaddr to a pj_sockaddr";
642 info->description = "This test converts an ast_sockaddr to a pj_sockaddr and validates\n"
643 "that the two evaluate to the same string when formatted.";
644 return AST_TEST_NOT_RUN;
645 case TEST_EXECUTE:
646 break;
647 }
648
649 while (*candidate) {
650 struct ast_sockaddr addr = {{0,}};
651 pj_sockaddr pjaddr;
652 char buffer[512];
653
654 fill_with_garbage(&pjaddr, sizeof(pj_sockaddr));
655
656 if (!ast_sockaddr_parse(&addr, *candidate, 0)) {
657 ast_test_status_update(test, "Failed to parse candidate IP: %s\n", *candidate);
658 return AST_TEST_FAIL;
659 }
660
661 if (ast_sockaddr_to_pj_sockaddr(&addr, &pjaddr)) {
662 ast_test_status_update(test, "Failed to convert ast_sockaddr to pj_sockaddr: %s\n", *candidate);
663 return AST_TEST_FAIL;
664 }
665
666 pj_sockaddr_print(&pjaddr, buffer, sizeof(buffer), 1 | 2);
667
668 if (strcmp(*candidate, buffer)) {
669 ast_test_status_update(test, "Converted sockaddrs do not match: \"%s\" and \"%s\"\n",
670 *candidate,
671 buffer);
672 return AST_TEST_FAIL;
673 }
674
675 candidate++;
676 }
677
678 return AST_TEST_PASS;
679}
680
681AST_TEST_DEFINE(ast_sockaddr_from_pj_sockaddr_test)
682{
683 char *candidates[] = {
684 "127.0.0.1:5555",
685 "[::]:4444",
686 "192.168.0.100:0",
687 "[fec0::1:80]:0",
688 "[fec0::1]:80",
689 NULL,
690 }, **candidate = candidates;
691
692 switch (cmd) {
693 case TEST_INIT:
694 info->name = "ast_sockaddr_from_pj_sockaddr_test";
695 info->category = "/res/res_pjproject/";
696 info->summary = "Validate conversions from a pj_sockaddr to an ast_sockaddr";
697 info->description = "This test converts a pj_sockaddr to an ast_sockaddr and validates\n"
698 "that the two evaluate to the same string when formatted.";
699 return AST_TEST_NOT_RUN;
700 case TEST_EXECUTE:
701 break;
702 }
703
704 while (*candidate) {
705 struct ast_sockaddr addr = {{0,}};
706 pj_sockaddr pjaddr;
707 pj_str_t t;
708 char buffer[512];
709
710 fill_with_garbage(&addr, sizeof(addr));
711
712 pj_strset(&t, *candidate, strlen(*candidate));
713
714 if (pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &t, &pjaddr) != PJ_SUCCESS) {
715 ast_test_status_update(test, "Failed to parse candidate IP: %s\n", *candidate);
716 return AST_TEST_FAIL;
717 }
718
719 if (ast_sockaddr_from_pj_sockaddr(&addr, &pjaddr)) {
720 ast_test_status_update(test, "Failed to convert pj_sockaddr to ast_sockaddr: %s\n", *candidate);
721 return AST_TEST_FAIL;
722 }
723
724 snprintf(buffer, sizeof(buffer), "%s", ast_sockaddr_stringify(&addr));
725
726 if (strcmp(*candidate, buffer)) {
727 ast_test_status_update(test, "Converted sockaddrs do not match: \"%s\" and \"%s\"\n",
728 *candidate,
729 buffer);
730 return AST_TEST_FAIL;
731 }
732
733 candidate++;
734 }
735
736 return AST_TEST_PASS;
737}
738#endif
739
740static int load_module(void)
741{
742 ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n");
743
745 ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
747 }
748
749 ast_sorcery_apply_default(pjproject_sorcery, "log_mappings", "config", "pjproject.conf,criteria=type=log_mappings");
751 ast_log(LOG_WARNING, "Failed to register pjproject log_mappings object with sorcery\n");
755 }
756
757 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "type", "", OPT_NOOP_T, 0, 0);
758 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_debug", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_debug));
759 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_error", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_error));
760 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_warning", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_warning));
761 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_notice", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_notice));
762 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_verbose", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_verbose));
763 ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_trace", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_trace));
764
765 default_log_mappings = ast_sorcery_alloc(pjproject_sorcery, "log_mappings", "log_mappings");
767 ast_log(LOG_ERROR, "Unable to allocate memory for pjproject log_mappings\n");
769 }
770 ast_string_field_set(default_log_mappings, asterisk_error, "0,1");
771 ast_string_field_set(default_log_mappings, asterisk_warning, "2");
772 ast_string_field_set(default_log_mappings, asterisk_debug, "3,4");
773 ast_string_field_set(default_log_mappings, asterisk_trace, "5,6");
774
776
778 pj_init();
779
780 decor_orig = pj_log_get_decor();
781 log_cb_orig = pj_log_get_log_func();
782
783 if (AST_VECTOR_INIT(&buildopts, 64)) {
785 }
786
787 /*
788 * On startup, we want to capture the dump once and store it.
789 */
790 pj_log_set_log_func(capture_buildopts_cb);
791 pj_log_set_decor(0);
792 pj_log_set_level(MAX_PJ_LOG_MAX_LEVEL);/* Set level to guarantee the dump output. */
793 pj_dump_config();
794 pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_INDENT);
795 pj_log_set_log_func(log_forwarder);
798 "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d which is too low for startup level: %d.\n",
801 }
802 pj_log_set_level(ast_option_pjproject_log_level);
803 if (!AST_VECTOR_SIZE(&buildopts)) {
805 "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d which is too low to get buildopts.\n",
807 }
808
810
811 AST_TEST_REGISTER(ast_sockaddr_to_pj_sockaddr_test);
812 AST_TEST_REGISTER(ast_sockaddr_from_pj_sockaddr_test);
813
815}
816
817#define NOT_EQUALS(a, b) (a != b)
818
819static int unload_module(void)
820{
822 pj_log_set_log_func(log_cb_orig);
823 pj_log_set_decor(decor_orig);
824
827
828 ast_debug(3, "Stopped PJPROJECT logging to Asterisk logger\n");
829
830 pj_shutdown();
831
834
836
837 AST_TEST_UNREGISTER(ast_sockaddr_to_pj_sockaddr_test);
838 AST_TEST_UNREGISTER(ast_sockaddr_from_pj_sockaddr_test);
839
840 return 0;
841}
842
843static int reload_module(void)
844{
845 if (pjproject_sorcery) {
847 }
848
850}
851
853 .support_level = AST_MODULE_SUPPORT_CORE,
854 .load = load_module,
855 .unload = unload_module,
857 .load_pri = AST_MODPRI_CHANNEL_DEPEND - 6,
858 .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.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
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:70
#define ast_mutex_unlock(a)
Definition: lock.h:194
#define ast_mutex_lock(a)
Definition: lock.h:193
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:524
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)
@ PJSIP_AUTH_ALGORITHM_COUNT
Definition: res_pjsip.h:613
@ PJSIP_AUTH_ALGORITHM_NOT_SET
Definition: res_pjsip.h:608
#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_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_alloca(init_len)
Definition: strings.h:848
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
Support for dynamic strings.
Definition: strings.h:623
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)]
const char * openssl_name
Definition: res_pjsip.h:620
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