47 #define HISTORY_INITIAL_SIZE 256 105 int (*
const evaluate_unary)(
struct operator *op,
enum aco_option_type type,
void *operand);
177 if (sscanf(op_right->
field,
"%30d", &right) != 1) {
181 return (*(
int *)op_left) == right;
187 if (sscanf(op_right->
field,
"%lf", &right) != 1) {
191 return (*(
double *)op_left) == right;
196 return pj_strcmp2(op_left, op_right->
field) == 0;
200 struct timeval right = { 0, };
202 if (sscanf(op_right->
field,
"%ld", &right.tv_sec) != 1) {
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) {
221 return pj_sockaddr_cmp(op_left, &right) == 0;
225 op_right->
field, op->symbol);
252 if (sscanf(op_right->
field,
"%30d", &right) != 1) {
256 return (*(
int *)op_left) < right;
262 if (sscanf(op_right->
field,
"%lf", &right) != 1) {
266 return (*(
double *)op_left) < right;
271 struct timeval right = { 0, };
273 if (sscanf(op_right->
field,
"%ld", &right.tv_sec) != 1) {
278 return ast_tvcmp(*(
struct timeval *)op_left, right) == -1;
282 op_right->
field, op->symbol);
301 if (sscanf(op_right->
field,
"%30d", &right) != 1) {
305 return (*(
int *)op_left) > right;
311 if (sscanf(op_right->
field,
"%lf", &right) != 1) {
315 return (*(
double *)op_left) > right;
320 struct timeval right = { 0, };
322 if (sscanf(op_right->
field,
"%ld", &right.tv_sec) != 1) {
327 return ast_tvcmp(*(
struct timeval *)op_left, right) == 1;
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];
422 if (regcomp(®exbuf, op_right->
field, REG_EXTENDED | REG_NOSUB)) {
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);
454 { .symbol =
"=", .precedence = 7, .operands = 2, .evaluate =
evaluate_equal, },
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);
641 PJSIP_POOL_RDATA_INC,
NULL);
647 entry->
msg = pjsip_msg_clone(entry->
pool, msg);
662 pj_sockaddr_print(&entry->
dst, addr,
sizeof(addr), 3);
664 pj_sockaddr_print(&entry->
src, addr,
sizeof(addr), 3);
667 if (entry->
msg->type == PJSIP_REQUEST_MSG) {
670 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->
msg->line.req.uri, uri,
sizeof(uri));
671 snprintf(line, len,
"%-5.5d %-10.10ld %-5.5s %-24.24s %.*s %s SIP/2.0",
676 (
int)pj_strlen(&entry->
msg->line.req.method.name),
677 pj_strbuf(&entry->
msg->line.req.method.name),
680 snprintf(line, len,
"%-5.5d %-10.10ld %-5.5s %-24.24s SIP/2.0 %u %.*s",
685 entry->
msg->line.status.code,
686 (
int)pj_strlen(&entry->
msg->line.status.reason),
687 pj_strbuf(&entry->
msg->line.status.reason));
705 pj_sockaddr_cp(&entry->
src, &tdata->tp_info.transport->local_addr);
706 pj_sockaddr_cp(&entry->
dst, &tdata->tp_info.dst_addr);
734 if (!rdata->msg_info.msg) {
743 if (rdata->tp_info.transport->addr_len) {
744 pj_sockaddr_cp(&entry->
dst, &rdata->tp_info.transport->local_addr);
747 if (rdata->pkt_info.src_addr_len) {
748 pj_sockaddr_cp(&entry->
src, &rdata->pkt_info.src_addr);
809 #define APPEND_TO_OUTPUT(output, token) do { \ 811 (output)->next = (token); \ 812 (output) = (token); \ 814 (output) = (token); \ 823 for (i = 4; i < a->
argc; i++) {
829 if (token[0] ==
'(') {
838 for (j = 0; j <
ARRAY_LEN(allowed_operators); j++) {
841 if (strcasecmp(token, allowed_operators[j].symbol)) {
851 if ((allowed_operators[j].right_to_left && allowed_operators[j].precedence >= top->precedence)
852 || (!allowed_operators[j].right_to_left && allowed_operators[j].precedence > top->precedence)) {
875 if (token[0] ==
')' || token[strlen(token) - 1] ==
')') {
877 if (token[strlen(token) - 1] ==
')') {
878 token[strlen(token) - 1] =
'\0';
891 if (top == &left_paren) {
919 if (top == &left_paren) {
961 for (it_queue = queue; it_queue; it_queue = it_queue->
next) {
976 ast_log(
LOG_WARNING,
"Unable to evaluate expression operator '%s': not enough operands\n",
977 it_queue->
op->symbol);
981 if (it_queue->
op->operands == 1) {
989 ast_log(
LOG_WARNING,
"Unable to evaluate '%s': operand is not the result of an operation\n",
990 it_queue->
op->symbol);
995 }
else if (it_queue->
op->operands == 2) {
1024 res = it_queue->
op->evaluate(it_queue->
op, type, value, op_one) == 0 ? 0 : 1;
1029 ast_log(
LOG_WARNING,
"Operator '%s' has an invalid number of operands\n", it_queue->
op->symbol);
1060 ast_log(
LOG_WARNING,
"Expression was unbalanced: %zu results remained after evaluation\n",
1070 result =
final->result;
1099 struct vector_history_t *output;
1155 buf =
ast_calloc(1, PJSIP_MAX_PKT_LEN *
sizeof(
char));
1160 if (pjsip_msg_print(entry->
msg, buf, PJSIP_MAX_PKT_LEN) == -1) {
1167 pj_sockaddr_print(&entry->
dst, addr,
sizeof(addr), 3);
1169 pj_sockaddr_print(&entry->
src, addr,
sizeof(addr), 3);
1172 ast_cli(a->
fd,
"<--- History Entry %d %s %s at %-10.10ld --->\n",
1187 ast_cli(a->
fd,
"%-5.5s %-10.10s %-30.30s %-35.35s\n",
1192 ast_cli(a->
fd,
"===== ========== ============================== ===================================\n");
1208 struct vector_history_t *vec = obj;
1219 struct vector_history_t *vec = &vector_history;
1223 e->
command =
"pjsip show history";
1225 "Usage: pjsip show history [entry <num>|where [...]]\n" 1226 " Displays the currently collected history or an\n" 1227 " entry within the history.\n\n" 1228 " * Running the command with no options will display\n" 1229 " the entire history.\n" 1230 " * Providing 'entry <num>' will display the full\n" 1231 " detail of a particular entry in this history.\n" 1232 " * Providing 'where ...' will allow for filtering\n" 1233 " the history. The history can be filtered using\n" 1234 " any of the following fields:\n" 1235 " - number: The history entry number\n" 1236 " - timestamp: The time associated with the history entry\n" 1237 " - addr: The source/destination address of the SIP message\n" 1238 " - sip.msg.request.method: The request method type\n" 1239 " - sip.msg.call-id: The Call-ID header of the SIP message\n" 1241 " When filtering, standard Boolean operators can be used,\n" 1242 " as well as 'like' for regexs.\n" 1245 " 'pjsip show history where number > 5 and (addr = \"192.168.0.3:5060\" or addr = \"192.168.0.5:5060\")'\n";
1252 if (!strcasecmp(a->
argv[3],
"entry") && a->
argc == 5) {
1255 if (sscanf(a->
argv[4],
"%30d", &num) != 1) {
1256 ast_cli(a->
fd,
"'%s' is not a valid entry number\n", a->
argv[4]);
1263 ast_cli(a->
fd,
"Entry '%d' does not exist\n", num);
1269 }
else if (!strcasecmp(a->
argv[3],
"where")) {
1280 if (vec == &vector_history) {
1284 if (vec == &vector_history) {
1292 if (vec == &vector_history) {
1298 if (vec == &vector_history) {
1303 if (vec != &vector_history) {
1316 e->
command =
"pjsip set history {on|off|clear}";
1318 "Usage: pjsip set history {on|off|clear}\n" 1319 " Enables/disables/clears the PJSIP history.\n\n" 1320 " Enabling the history will start recording transmitted/received\n" 1321 " packets. Disabling the history will stop recording, but keep\n" 1322 " the already received packets. Clearing the history will wipe\n" 1323 " the received packets from memory.\n\n" 1324 " As the PJSIP history is maintained in memory, and includes\n" 1325 " all received/transmitted requests and responses, it should\n" 1326 " only be enabled for debugging purposes, and cleared when done.\n";
1335 if (!strcasecmp(what,
"on")) {
1337 ast_cli(a->
fd,
"PJSIP History enabled\n");
1339 }
else if (!strcasecmp(what,
"off")) {
1341 ast_cli(a->
fd,
"PJSIP History disabled\n");
1343 }
else if (!strcasecmp(what,
"clear")) {
1345 ast_cli(a->
fd,
"PJSIP History cleared\n");
1354 .name = {
"History Module", 14 },
1406 .requires =
"res_pjsip",
Type for default handler for ast_sockaddrs.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_CLI_DEFINE(fn, txt,...)
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.
void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
Destroy caching pool factory and all cached pools.
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)
static int packet_number
Packet count.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
static int evaluate_greater_than(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
static struct allowed_field allowed_fields[]
The fields we allow.
#define APPEND_TO_OUTPUT(output, token)
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.
static AST_VECTOR(vector_history_t, struct pjsip_history_entry *)
The one and only history that we've captured.
expression_token_type
The type of token that has been parsed out of an expression.
#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)
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.
#define ast_log_dynamic_level(level,...)
Send a log message to a dynamically registered log level.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
static int evaluate_less_than(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define ao2_alloc_options(data_size, destructor_fn, options)
#define ast_mutex_lock(a)
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag...
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
static int evaluate_less_than_or_equal(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
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.
void ast_cli(int fd, const char *fmt,...)
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 int load_module(void)
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)
static char * pjsip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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.
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.
void ast_logger_unregister_level(const char *name)
Unregister a previously registered logger level.
pj_sockaddr src
Source address.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Type for default option handler for unsigned integers.
static pjsip_module logging_module
#define ao2_ref(o, delta)
const char * symbol
The representation of the field.
static struct vector_history_t * filter_history(struct ast_cli_args *a)
Create a filtered history based on a user provided expression.
#define ast_strdupa(s)
duplicate a string in memory from the stack
enum aco_option_type return_type
The type /c get_field returns.
#define ast_malloc(len)
A wrapper for malloc()
pjsip_msg * msg
The actual SIP message.
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
int ast_logger_register_level(const char *name)
Register a new logger level.
aco_option_type
The option types.
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 result
The result of an evaluated expression.
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compres 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)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static struct expression_token * expression_token_free(struct expression_token *token)
Free an expression token and all others it references.
#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.
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.
Support for logging to various files, console and syslog Configuration in file logger.conf.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
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)
static struct ast_cli_entry cli_pjsip[]
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
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.
void ast_sip_unregister_service(pjsip_module *module)
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.
int error(const char *format,...)
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.
static int unload_module(void)
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 char * pjsip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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.
#define HISTORY_INITIAL_SIZE
#define AST_MUTEX_DEFINE_STATIC(mutex)
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.
#define ast_mutex_unlock(a)