38 #include "asterisk/res_pjsip.h"
45 #include "asterisk/res_pjproject.h"
47 #define HISTORY_INITIAL_SIZE 256
177 if (sscanf(op_right->field,
"%30d", &right) != 1) {
178 ast_log(LOG_WARNING,
"Unable to extract field '%s': not an integer\n", op_right->field);
181 return (*(
int *)op_left) == right;
187 if (sscanf(op_right->field,
"%lf", &right) != 1) {
188 ast_log(LOG_WARNING,
"Unable to extract field '%s': not a double\n", op_right->field);
191 return (*(
double *)op_left) == right;
196 return pj_strcmp2(op_left, op_right->field) == 0;
200 struct timeval right = { 0, };
203 ast_log(LOG_WARNING,
"Unable to extract field '%s': not a timestamp\n", op_right->field);
207 return ast_tvcmp(*(
struct timeval *)op_left, right) == 0;
215 pj_cstr(&str_right, op_right->field);
216 if (pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &str_right, &right) != PJ_SUCCESS) {
217 ast_log(LOG_WARNING,
"Unable to convert field '%s': not an IPv4 or IPv6 address\n", op_right->field);
221 return pj_sockaddr_cmp(op_left, &right) == 0;
224 ast_log(LOG_WARNING,
"Cannot evaluate field '%s': invalid type for operator '%s'\n",
225 op_right->field, op->symbol);
252 if (sscanf(op_right->
field,
"%30d", &right) != 1) {
253 ast_log(LOG_WARNING,
"Unable to extract field '%s': not an integer\n", op_right->
field);
256 return (*(
int *)op_left) < right;
262 if (sscanf(op_right->
field,
"%lf", &right) != 1) {
263 ast_log(LOG_WARNING,
"Unable to extract field '%s': not a double\n", op_right->
field);
266 return (*(
double *)op_left) < right;
271 struct timeval right = { 0, };
274 ast_log(LOG_WARNING,
"Unable to extract field '%s': not a timestamp\n", op_right->
field);
278 return ast_tvcmp(*(
struct timeval *)op_left, right) == -1;
281 ast_log(LOG_WARNING,
"Cannot evaluate field '%s': invalid type for operator '%s'\n",
282 op_right->
field, op->symbol);
301 if (sscanf(op_right->
field,
"%30d", &right) != 1) {
302 ast_log(LOG_WARNING,
"Unable to extract field '%s': not an integer\n", op_right->
field);
305 return (*(
int *)op_left) > right;
311 if (sscanf(op_right->
field,
"%lf", &right) != 1) {
312 ast_log(LOG_WARNING,
"Unable to extract field '%s': not a double\n", op_right->
field);
315 return (*(
double *)op_left) > right;
320 struct timeval right = { 0, };
323 ast_log(LOG_WARNING,
"Unable to extract field '%s': not a timestamp\n", op_right->
field);
327 return ast_tvcmp(*(
struct timeval *)op_left, right) == 1;
330 ast_log(LOG_WARNING,
"Cannot evaluate field '%s': invalid type for operator '%s'\n",
331 op_right->
field, op->symbol);
363 return !(*(
int *)operand);
365 ast_log(LOG_WARNING,
"Cannot evaluate: invalid operand type for operator '%s'\n", op->symbol);
381 return (*(
int *)op_left && op_right->
result);
383 ast_log(LOG_WARNING,
"Cannot evaluate: invalid operand type for operator '%s'\n", op->symbol);
399 return (*(
int *)op_left || op_right->
result);
401 ast_log(LOG_WARNING,
"Cannot evaluate: invalid operand type for operator '%s'\n", op->symbol);
419 char buf[pj_strlen(op_left) + 1];
421 ast_copy_pj_str(buf, op_left, pj_strlen(op_left));
422 if (regcomp(®exbuf, op_right->
field, REG_EXTENDED | REG_NOSUB)) {
423 ast_log(LOG_WARNING,
"Failed to compile '%s' into a regular expression\n", op_right->
field);
427 result = (regexec(®exbuf, buf, 0, NULL, 0) == 0);
433 ast_log(LOG_WARNING,
"Cannot evaluate: invalid operand type for operator '%s'\n", op->symbol);
455 { .symbol =
"==", .precedence = 7, .operands = 2, .evaluate =
evaluate_equal, },
461 { .symbol =
"!", .precedence = 2, .operands = 1, .right_to_left = 1, .evaluate_unary =
evaluate_not, },
462 { .symbol =
"&&", .precedence = 11, .operands = 2, .evaluate =
evaluate_and, },
463 { .symbol =
"||", .precedence = 12, .operands = 2, .evaluate =
evaluate_or, },
464 { .symbol =
"like", .precedence = 7, .operands = 2, .evaluate =
evaluate_like, },
465 { .symbol =
"and", .precedence = 11, .operands = 2, .evaluate =
evaluate_and, },
466 { .symbol =
"or", .precedence = 11, .operands = 2, .evaluate =
evaluate_or, },
467 { .symbol =
"not", .precedence = 2, .operands = 1, .right_to_left = 1, .evaluate_unary =
evaluate_not, },
495 if (entry->
msg->type != PJSIP_REQUEST_MSG) {
499 return &entry->
msg->line.req.method.name;
505 pjsip_cid_hdr *cid_hdr;
507 cid_hdr = PJSIP_MSG_CID_HDR(entry->
msg);
531 it_token = it_token->
next;
551 switch (token_type) {
557 token =
ast_calloc(1,
sizeof(*token) + strlen((
const char *)value) + 1);
569 switch (token_type) {
571 token->
result = *(
int *)value;
577 strcpy(token->
field, value);
593 for (i = 0; i < ARRAY_LEN(allowed_fields); i++) {
594 if (strcasecmp(allowed_fields[i].
symbol, token->
field)) {
598 return &allowed_fields[i];
613 pj_pool_t *temp_pool = entry->
pool;
616 pj_pool_release(temp_pool);
640 entry->
pool = pj_pool_create(&
cachingpool.factory, NULL, PJSIP_POOL_RDATA_LEN,
641 PJSIP_POOL_RDATA_INC, NULL);
647 entry->
msg = pjsip_msg_clone(entry->
pool, msg);
659 char addr[64], secs[AST_TIME_T_LEN];
662 pj_sockaddr_print(&entry->
dst, addr,
sizeof(addr), 3);
664 pj_sockaddr_print(&entry->
src, addr,
sizeof(addr), 3);
669 if (entry->
msg->type == PJSIP_REQUEST_MSG) {
672 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->
msg->line.req.uri, uri,
sizeof(uri));
673 snprintf(line, len,
"%-5.5d %-10.10s %-5.5s %-24.24s %.*s %s SIP/2.0",
678 (
int)pj_strlen(&entry->
msg->line.req.method.name),
679 pj_strbuf(&entry->
msg->line.req.method.name),
682 snprintf(line, len,
"%-5.5d %-10.10s %-5.5s %-24.24s SIP/2.0 %u %.*s",
687 entry->
msg->line.status.code,
688 (
int)pj_strlen(&entry->
msg->line.status.reason),
689 pj_strbuf(&entry->
msg->line.status.reason));
707 pj_sockaddr_cp(&entry->
src, &tdata->tp_info.transport->local_addr);
708 pj_sockaddr_cp(&entry->
dst, &tdata->tp_info.dst_addr);
736 if (!rdata->msg_info.msg) {
745 if (rdata->tp_info.transport->addr_len) {
746 pj_sockaddr_cp(&entry->
dst, &rdata->tp_info.transport->local_addr);
749 if (rdata->pkt_info.src_addr_len) {
750 pj_sockaddr_cp(&entry->
src, &rdata->pkt_info.src_addr);
811 #define APPEND_TO_OUTPUT(output, token) do { \
813 (output)->next = (token); \
814 (output) = (token); \
816 (output) = (token); \
825 for (i = 4; i < a->argc; i++) {
831 if (token[0] ==
'(') {
840 for (j = 0; j < ARRAY_LEN(allowed_operators); j++) {
843 if (strcasecmp(token, allowed_operators[j].symbol)) {
859 APPEND_TO_OUTPUT(output, out_token);
877 if (token[0] ==
')' || token[strlen(token) - 1] ==
')') {
879 if (token[strlen(token) - 1] ==
')') {
880 token[strlen(token) - 1] =
'\0';
885 APPEND_TO_OUTPUT(output, out_token);
893 if (top == &left_paren) {
900 APPEND_TO_OUTPUT(output, out_token);
909 APPEND_TO_OUTPUT(output, out_token);
921 if (top == &left_paren) {
922 ast_log(LOG_WARNING,
"Unbalanced '(' parentheses in expression!\n");
929 APPEND_TO_OUTPUT(output, out_token);
963 for (it_queue = queue; it_queue; it_queue = it_queue->
next) {
978 ast_log(LOG_WARNING,
"Unable to evaluate expression operator '%s': not enough operands\n",
991 ast_log(LOG_WARNING,
"Unable to evaluate '%s': operand is not the result of an operation\n",
1011 ast_log(LOG_WARNING,
"Unknown or unrecognized field: %s\n", op_two->
field);
1021 ast_log(LOG_WARNING,
"Attempting to evaluate an operator: %s\n", op_two->
op->
symbol);
1026 res = it_queue->
op->
evaluate(it_queue->
op, type, value, op_one) == 0 ? 0 : 1;
1031 ast_log(LOG_WARNING,
"Operator '%s' has an invalid number of operands\n", it_queue->
op->
symbol);
1062 ast_log(LOG_WARNING,
"Expression was unbalanced: %zu results remained after evaluation\n",
1069 ast_log(LOG_WARNING,
"Expression did not create a usable result\n");
1072 result =
final->result;
1084 ast_free(failed_token);
1154 char addr[64], secs[AST_TIME_T_LEN];
1157 buf =
ast_calloc(1, PJSIP_MAX_PKT_LEN *
sizeof(
char));
1162 if (pjsip_msg_print(entry->
msg, buf, PJSIP_MAX_PKT_LEN) == -1) {
1163 ast_log(LOG_WARNING,
"Unable to print SIP message %d: packet too large!\n", entry->
number);
1169 pj_sockaddr_print(&entry->
dst, addr,
sizeof(addr), 3);
1171 pj_sockaddr_print(&entry->
src, addr,
sizeof(addr), 3);
1175 ast_cli(a->fd,
"<--- History Entry %d %s %s at %-10.10s --->\n",
1180 ast_cli(a->fd,
"%s\n", buf);
1190 ast_cli(a->fd,
"%-5.5s %-10.10s %-30.30s %-35.35s\n",
1195 ast_cli(a->fd,
"===== ========== ============================== ===================================\n");
1204 ast_cli(a->fd,
"%s\n", line);
1225 if (cmd == CLI_INIT) {
1226 e->
command =
"pjsip show history";
1228 "Usage: pjsip show history [entry <num>|where [...]]\n"
1229 " Displays the currently collected history or an\n"
1230 " entry within the history.\n\n"
1231 " * Running the command with no options will display\n"
1232 " the entire history.\n"
1233 " * Providing 'entry <num>' will display the full\n"
1234 " detail of a particular entry in this history.\n"
1235 " * Providing 'where ...' will allow for filtering\n"
1236 " the history. The history can be filtered using\n"
1237 " any of the following fields:\n"
1238 " - number: The history entry number\n"
1239 " - timestamp: The time associated with the history entry\n"
1240 " - addr: The source/destination address of the SIP message\n"
1241 " - sip.msg.request.method: The request method type\n"
1242 " - sip.msg.call-id: The Call-ID header of the SIP message\n"
1244 " When filtering, standard Boolean operators can be used,\n"
1245 " as well as 'like' for regexs.\n"
1248 " 'pjsip show history where number > 5 and (addr = \"192.168.0.3:5060\" or addr = \"192.168.0.5:5060\")'\n";
1250 }
else if (cmd == CLI_GENERATE) {
1255 if (!strcasecmp(a->argv[3],
"entry") && a->argc == 5) {
1258 if (sscanf(a->argv[4],
"%30d", &num) != 1) {
1259 ast_cli(a->fd,
"'%s' is not a valid entry number\n", a->argv[4]);
1266 ast_cli(a->fd,
"Entry '%d' does not exist\n", num);
1272 }
else if (!strcasecmp(a->argv[3],
"where")) {
1278 return CLI_SHOWUSAGE;
1283 if (vec == &vector_history) {
1287 if (vec == &vector_history) {
1295 if (vec == &vector_history) {
1301 if (vec == &vector_history) {
1306 if (vec != &vector_history) {
1318 if (cmd == CLI_INIT) {
1319 e->
command =
"pjsip set history {on|off|clear}";
1321 "Usage: pjsip set history {on|off|clear}\n"
1322 " Enables/disables/clears the PJSIP history.\n\n"
1323 " Enabling the history will start recording transmitted/received\n"
1324 " packets. Disabling the history will stop recording, but keep\n"
1325 " the already received packets. Clearing the history will wipe\n"
1326 " the received packets from memory.\n\n"
1327 " As the PJSIP history is maintained in memory, and includes\n"
1328 " all received/transmitted requests and responses, it should\n"
1329 " only be enabled for debugging purposes, and cleared when done.\n";
1331 }
else if (cmd == CLI_GENERATE) {
1335 what = a->argv[e->
args - 1];
1337 if (a->argc == e->
args) {
1338 if (!strcasecmp(what,
"on")) {
1340 ast_cli(a->fd,
"PJSIP History enabled\n");
1342 }
else if (!strcasecmp(what,
"off")) {
1344 ast_cli(a->fd,
"PJSIP History disabled\n");
1346 }
else if (!strcasecmp(what,
"clear")) {
1348 ast_cli(a->fd,
"PJSIP History cleared\n");
1353 return CLI_SHOWUSAGE;
1356 static pjsip_module logging_module = {
1357 .name = {
"History Module", 14 },
1366 AST_CLI_DEFINE(pjsip_set_history,
"Enable/Disable PJSIP History"),
1367 AST_CLI_DEFINE(pjsip_show_history,
"Display PJSIP History"),
1370 static int load_module(
void)
1374 ast_log(LOG_WARNING,
"Unable to register history log level\n");
1381 ast_sip_register_service(&logging_module);
1387 static int unload_module(
void)
1390 ast_sip_unregister_service(&logging_module);
1405 .support_level = AST_MODULE_SUPPORT_EXTENDED,
1406 .load = load_module,
1407 .unload = unload_module,
1409 .requires =
"res_pjsip",
Type for default handler for ast_sockaddrs.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
time_t ast_string_to_time_t(const char *str)
Returns a time_t from a string containing seconds since the epoch.
static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expression_token *queue)
Evaluate a single entry in this history using a RPN expression.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int right_to_left
Non-zero if the operator is evaluated right-to-left.
static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int len)
Format single line history entry.
static int evaluate_and(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining logical AND.
static int packet_number
Packet count.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch. Returns -1 on failure, zero otherwise.
static int evaluate_greater_than(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining if one operand is greater than another.
static struct allowed_field allowed_fields[]
The fields we allow.
descriptor for a cli entry.
char field[]
The field in the expression.
static int clear_history_entries(void *obj)
Remove all entries from vector_history.
expression_token_type
The type of token that has been parsed out of an expression.
#define ast_log_dynamic_level(level,...)
Send a log message to a dynamically registered log level.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
static ast_mutex_t history_lock
Mutex that protects vector_history.
static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata)
PJSIP callback when a SIP message is transmitted.
int transmitted
Whether or not we transmitted the packet.
static int evaluate_like(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for regex 'like'.
pj_sockaddr dst
Destination address.
Type for a default handler that should do nothing.
void *(*const get_field)(struct pjsip_history_entry *entry)
Function that returns the field from a pjsip_history_entry.
void ast_logger_unregister_level(const char *name)
Unregister a previously registered logger level.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
An operator that we understand in an expression.
static int evaluate_less_than(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining if one operand is less than another.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag...
static int evaluate_less_than_or_equal(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining if one operand is less than or equal to another.
struct timeval timestamp
Time the packet was transmitted/received.
static struct operator allowed_operators[]
Our allowed operations.
static struct operator left_paren
Operator token for a left parenthesis.
The one and only history that we've captured.
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
struct operator* op
An operator that evaluates expressions.
static void * entry_get_sip_msg_request_method(struct pjsip_history_entry *entry)
Callback to retrieve the entry's SIP request method type.
static int evaluate_not(struct operator*op, enum aco_option_type type, void *operand)
Operator callback for determining logical NOT.
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.
static int evaluate_not_equal(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining inequality.
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
int args
This gets set in ast_cli_register()
static int log_level
Log level for history output.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Type for default option handler for character array strings.
static void * entry_get_timestamp(struct pjsip_history_entry *entry)
Callback to retrieve the entry's timestamp.
enum expression_token_type token_type
The type of value stored in the expression token.
A field that we understand and can perform operations on.
pj_sockaddr src
Source address.
int precedence
Precedence of the symbol.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Type for default option handler for unsigned integers.
#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.
int operands
Number of operands the operator takes.
const char * symbol
The representation of the field.
int(*const evaluate_unary)(struct operator*op, enum aco_option_type type, void *operand)
Evaluation function for unary operators.
static struct vector_history_t * filter_history(struct ast_cli_args *a)
Create a filtered history based on a user provided expression.
enum aco_option_type return_type
The type /c get_field returns.
#define ast_malloc(len)
A wrapper for malloc()
#define AST_VECTOR(name, type)
Define a vector structure.
pjsip_msg * msg
The actual SIP message.
aco_option_type
The option types.
int result
The result of an evaluated expression.
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
static struct allowed_field * get_allowed_field(struct expression_token *token)
Determine if the expression token matches a field in allowed_fields.
Type for default option handler for bools (ast_true/ast_false)
static int evaluate_greater_than_or_equal(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining if one operand is greater than or equal to another.
static struct expression_token * expression_token_free(struct expression_token *token)
Free an expression token and all others it references.
void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
Destroy caching pool factory and all cached pools.
#define ast_calloc(num, len)
A wrapper for calloc()
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Type for default option handler for doubles.
static void display_entry_list(struct ast_cli_args *a, struct vector_history_t *vec)
Print a list of the entries to the CLI.
Support for logging to various files, console and syslog Configuration in file logger.conf.
Vector container support.
pj_pool_t * pool
Memory pool used to allocate msg.
static struct pjsip_history_entry * pjsip_history_entry_alloc(pjsip_msg *msg)
Create a pjsip_history_entry AO2 object.
#define AST_VECTOR_PTR_FREE(vec)
Deallocates this vector pointer.
A token in the expression or an evaluated part of the expression.
int(*const evaluate)(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Evaluation function for binary operators.
static void * entry_get_number(struct pjsip_history_entry *entry)
Callback to retrieve the entry index number.
static int evaluate_or(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining logical OR.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
int ast_logger_register_level(const char *name)
Register a new logger level.
static void clear_history_entry_cb(struct pjsip_history_entry *entry)
Vector callback that releases the reference for the entry in a history vector.
Standard Command Line Interface.
static void * entry_get_addr(struct pjsip_history_entry *entry)
Callback to retrieve the entry's destination address.
static int enabled
Whether or not we are storing history.
static int safe_vector_cleanup(void *obj)
Cleanup routine for a history vector, serviced on a registered PJSIP thread.
static void display_single_entry(struct ast_cli_args *a, struct pjsip_history_entry *entry)
Print a detailed view of a single entry in the history to the CLI.
Type for default option handler for stringfields.
const char * symbol
Our operator's symbol.
static struct expression_token * expression_token_alloc(enum expression_token_type token_type, void *value)
Allocate an expression token.
static void pjsip_history_entry_dtor(void *obj)
AO2 destructor for pjsip_history_entry.
static pj_bool_t history_on_rx_msg(pjsip_rx_data *rdata)
PJSIP callback when a SIP message is received.
Type for default option handler for signed integers.
#define ASTERISK_GPL_KEY
The text the key() function should return.
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Asterisk module definitions.
static void * entry_get_sip_msg_call_id(struct pjsip_history_entry *entry)
Callback to retrieve the entry's SIP Call-ID header.
static struct expression_token * build_expression_queue(struct ast_cli_args *a)
Build a reverse polish notation expression queue.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
static int evaluate_equal(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining equality.
struct expression_token * next
The next expression token in the queue.
static pj_caching_pool cachingpool
Pool factory used by pjlib to allocate memory.