diff --git a/res/res_pjsip_logger.c b/res/res_pjsip_logger.c index 7245f16f469a185f8f6136f1d0e4effaf0e14063..90cb06fb898f820f58665dc5702561643a380c0c 100644 --- a/res/res_pjsip_logger.c +++ b/res/res_pjsip_logger.c @@ -19,7 +19,7 @@ /*** MODULEINFO <depend>pjproject</depend> <depend>res_pjsip</depend> - <defaultenabled>no</defaultenabled> + <defaultenabled>yes</defaultenabled> <support_level>core</support_level> ***/ @@ -30,9 +30,79 @@ #include "asterisk/res_pjsip.h" #include "asterisk/module.h" #include "asterisk/logger.h" +#include "asterisk/cli.h" +#include "asterisk/netsock2.h" + +enum pjsip_logging_mode { + LOGGING_MODE_DISABLED, /* No logging is enabled */ + LOGGING_MODE_ENABLED, /* Logging is enabled */ +}; + +static enum pjsip_logging_mode logging_mode; +static struct ast_sockaddr log_addr; + +/*! \brief Return the first entry from ast_sockaddr_resolve filtered by address family + * + * \warning Using this function probably means you have a faulty design. + * \note This function was taken from the function of the same name in chan_sip.c + */ +static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr, + const char* name, int flag, int family) +{ + struct ast_sockaddr *addrs; + int addrs_cnt; + + addrs_cnt = ast_sockaddr_resolve(&addrs, name, flag, family); + if (addrs_cnt <= 0) { + return 1; + } + if (addrs_cnt > 1) { + ast_debug(1, "Multiple addresses, using the first one only\n"); + } + + ast_sockaddr_copy(addr, &addrs[0]); + + ast_free(addrs); + return 0; +} + +/*! \brief See if we pass debug IP filter */ +static inline int pjsip_log_test_addr(const char *address, int port) +{ + struct ast_sockaddr test_addr; + if (logging_mode == LOGGING_MODE_DISABLED) { + return 0; + } + + /* A null logging address means we'll debug any address */ + if (ast_sockaddr_isnull(&log_addr)) { + return 1; + } + + /* A null address was passed in. Just reject it. */ + if (ast_strlen_zero(address)) { + return 0; + } + + ast_sockaddr_parse(&test_addr, address, PARSE_PORT_IGNORE); + ast_sockaddr_set_port(&test_addr, port); + + /* If no port was specified for a debug address, just compare the + * addresses, otherwise compare the address and port + */ + if (ast_sockaddr_port(&log_addr)) { + return !ast_sockaddr_cmp(&log_addr, &test_addr); + } else { + return !ast_sockaddr_cmp_addr(&log_addr, &test_addr); + } +} static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) { + if (!pjsip_log_test_addr(tdata->tp_info.dst_name, tdata->tp_info.dst_port)) { + return PJ_SUCCESS; + } + ast_verbose("<--- Transmitting SIP %s (%d bytes) to %s:%s:%d --->\n%.*s\n", tdata->msg->type == PJSIP_REQUEST_MSG ? "request" : "response", (int) (tdata->buf.cur - tdata->buf.start), @@ -45,6 +115,10 @@ static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) { + if (!pjsip_log_test_addr(rdata->pkt_info.src_name, rdata->pkt_info.src_port)) { + return PJ_FALSE; + } + ast_verbose("<--- Received SIP %s (%d bytes) from %s:%s:%d --->\n%s\n", rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ? "request" : "response", rdata->msg_info.len, @@ -64,14 +138,71 @@ static pjsip_module logging_module = { .on_tx_response = logging_on_tx_msg, }; +static char *pjsip_enable_logger_host(int fd, const char *arg) +{ + if (ast_sockaddr_resolve_first_af(&log_addr, arg, 0, AST_AF_UNSPEC)) { + return CLI_SHOWUSAGE; + } + + ast_cli(fd, "PJSIP Logging Enabled for host: %s\n", ast_sockaddr_stringify_addr(&log_addr)); + logging_mode = LOGGING_MODE_ENABLED; + + return CLI_SUCCESS; +} + +static char *pjsip_set_logger(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + const char *what; + + if (cmd == CLI_INIT) { + e->command = "pjsip set logger {on|off|host}"; + e->usage = + "Usage: pjsip set logger {on|off}\n" + " Enables or disabling logging of SIP packets\n" + " read on ports bound to PJSIP transports either\n" + " globally or enables logging for an individual\n" + " host.\n"; + return NULL; + } else if (cmd == CLI_GENERATE) { + return NULL; + } + + what = a->argv[e->args - 1]; /* Guaranteed to exist */ + + if (a->argc == e->args) { /* on/off */ + if (!strcasecmp(what, "on")) { + logging_mode = LOGGING_MODE_ENABLED; + ast_cli(a->fd, "PJSIP Logging enabled\n"); + ast_sockaddr_setnull(&log_addr); + return CLI_SUCCESS; + } else if (!strcasecmp(what, "off")) { + logging_mode = LOGGING_MODE_DISABLED; + ast_cli(a->fd, "PJSIP Logging disabled\n"); + return CLI_SUCCESS; + } + } else if (a->argc == e->args + 1) { + if (!strcasecmp(what, "host")) { + return pjsip_enable_logger_host(a->fd, a->argv[e->args]); + } + } + + return CLI_SHOWUSAGE; +} + +static struct ast_cli_entry cli_pjsip[] = { + AST_CLI_DEFINE(pjsip_set_logger, "Enable/Disable PJSIP Logger Output") +}; + static int load_module(void) { ast_sip_register_service(&logging_module); + ast_cli_register_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip)); return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { + ast_cli_unregister_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip)); ast_sip_unregister_service(&logging_module); return 0; }