47#define HISTORY_INITIAL_SIZE 256
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, };
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, };
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, };
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)) {
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, },
473 return &
entry->number;
479 return &
entry->timestamp;
485 if (
entry->transmitted) {
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;
557 token =
ast_calloc(1,
sizeof(*token) + strlen((
const char *)
value) + 1);
613 pj_pool_t *temp_pool =
entry->pool;
616 pj_pool_release(temp_pool);
638 entry->timestamp.tv_usec = 0;
641 PJSIP_POOL_RDATA_INC,
NULL);
661 if (
entry->transmitted) {
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",
676 entry->transmitted ?
"* ==>" :
"* <==",
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",
685 entry->transmitted ?
"* ==>" :
"* <==",
687 entry->msg->line.status.code,
688 (
int)pj_strlen(&
entry->msg->line.status.reason),
689 pj_strbuf(&
entry->msg->line.status.reason));
706 entry->transmitted = 1;
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] ==
'(') {
877 if (token[0] ==
')' || token[strlen(token) - 1] ==
')') {
879 if (token[strlen(token) - 1] ==
')') {
880 token[strlen(token) - 1] =
'\0';
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",
1062 ast_log(
LOG_WARNING,
"Expression was unbalanced: %zu results remained after evaluation\n",
1162 if (pjsip_msg_print(
entry->msg,
buf, PJSIP_MAX_PKT_LEN) == -1) {
1168 if (
entry->transmitted) {
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",
1177 entry->transmitted ?
"Sent to" :
"Received from",
1190 ast_cli(
a->fd,
"%-5.5s %-10.10s %-30.30s %-35.35s\n",
1195 ast_cli(
a->fd,
"===== ========== ============================== ===================================\n");
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";
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")) {
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";
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");
1357 .name = {
"History Module", 14 },
1409 .
requires =
"res_pjsip",
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_malloc(len)
A wrapper for malloc()
@ AO2_ALLOC_OPT_LOCK_NOLOCK
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_alloc_options(data_size, destructor_fn, options)
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Standard Command Line Interface.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define AST_CLI_DEFINE(fn, txt,...)
void ast_cli(int fd, const char *fmt,...)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
aco_option_type
The option types.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_BOOLFLAG_T
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag.
@ OPT_CHAR_ARRAY_T
Type for default option handler for character array strings.
@ OPT_SOCKADDR_T
Type for default handler for ast_sockaddrs.
@ OPT_INT_T
Type for default option handler for signed integers.
@ OPT_DOUBLE_T
Type for default option handler for doubles.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
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.
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_log_dynamic_level(level,...)
Send a log message to a dynamically registered log level.
int ast_logger_register_level(const char *name)
Register a new logger level.
void ast_logger_unregister_level(const char *name)
Unregister a previously registered logger level.
Asterisk locking-related definitions:
#define ast_mutex_unlock(a)
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
#define ast_mutex_lock(a)
#define AST_MUTEX_DEFINE_STATIC(mutex)
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_EXTENDED
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
Destroy caching pool factory and all cached pools.
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.
void ast_sip_unregister_service(pjsip_module *module)
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
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 struct operator allowed_operators[]
Our allowed operations.
static int enabled
Whether or not we are storing history.
static struct allowed_field * get_allowed_field(struct expression_token *token)
Determine if the expression token matches a field in allowed_fields.
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.
static void * entry_get_addr(struct pjsip_history_entry *entry)
Callback to retrieve the entry's destination address.
static pj_caching_pool cachingpool
Pool factory used by pjlib to allocate memory.
#define HISTORY_INITIAL_SIZE
static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int len)
Format single line history entry.
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.
static int packet_number
Packet count.
static void * entry_get_sip_msg_request_method(struct pjsip_history_entry *entry)
Callback to retrieve the entry's SIP request method type.
static struct expression_token * expression_token_alloc(enum expression_token_type token_type, void *value)
Allocate an expression token.
static struct ast_cli_entry cli_pjsip[]
static void clear_history_entry_cb(struct pjsip_history_entry *entry)
Vector callback that releases the reference for the entry in a history vector.
static char * pjsip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct pjsip_history_entry * pjsip_history_entry_alloc(pjsip_msg *msg)
Create a pjsip_history_entry AO2 object.
static int safe_vector_cleanup(void *obj)
Cleanup routine for a history vector, serviced on a registered PJSIP thread.
static pj_bool_t history_on_rx_msg(pjsip_rx_data *rdata)
PJSIP callback when a SIP message is received.
static pjsip_module logging_module
static struct vector_history_t * filter_history(struct ast_cli_args *a)
Create a filtered history based on a user provided expression.
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.
static void pjsip_history_entry_dtor(void *obj)
AO2 destructor for pjsip_history_entry.
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.
#define APPEND_TO_OUTPUT(output, token)
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 evaluate_not_equal(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining inequality.
static ast_mutex_t history_lock
Mutex that protects vector_history.
static struct expression_token * expression_token_free(struct expression_token *token)
Free an expression token and all others it references.
static void * entry_get_sip_msg_call_id(struct pjsip_history_entry *entry)
Callback to retrieve the entry's SIP Call-ID header.
expression_token_type
The type of token that has been parsed out of an expression.
static struct expression_token * build_expression_queue(struct ast_cli_args *a)
Build a reverse polish notation expression queue.
static char * pjsip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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.
static int log_level
Log level for history output.
static int evaluate_not(struct operator*op, enum aco_option_type type, void *operand)
Operator callback for determining logical NOT.
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.
static void * entry_get_timestamp(struct pjsip_history_entry *entry)
Callback to retrieve the entry's timestamp.
static int load_module(void)
static void display_entry_list(struct ast_cli_args *a, struct vector_history_t *vec)
Print a list of the entries to the CLI.
static struct allowed_field allowed_fields[]
The fields we allow.
static int unload_module(void)
static struct vector_history_t vector_history
static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata)
PJSIP callback when a SIP message is transmitted.
static int clear_history_entries(void *obj)
Remove all entries from vector_history.
static struct operator left_paren
Operator token for a left parenthesis.
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'.
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.
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.
A field that we understand and can perform operations on.
enum aco_option_type return_type
The type /c get_field returns.
const char * symbol
The representation of the field.
void *(*const get_field)(struct pjsip_history_entry *entry)
Function that returns the field from a pjsip_history_entry.
descriptor for a cli entry.
int args
This gets set in ast_cli_register()
A token in the expression or an evaluated part of the expression.
struct expression_token * next
The next expression token in the queue.
char field[]
The field in the expression.
enum expression_token_type token_type
The type of value stored in the expression token.
int result
The result of an evaluated expression.
struct operator* op
An operator that evaluates expressions.
An operator that we understand in an 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.
int precedence
Precedence of the symbol.
int(*const evaluate_unary)(struct operator*op, enum aco_option_type type, void *operand)
Evaluation function for unary operators.
int operands
Number of operands the operator takes.
const char * symbol
Our operator's symbol.
int right_to_left
Non-zero if the operator is evaluated right-to-left.
pjsip_msg * msg
The actual SIP message.
struct timeval timestamp
Time the packet was transmitted/received.
pj_pool_t * pool
Memory pool used to allocate msg.
pj_sockaddr src
Source address.
int transmitted
Whether or not we transmitted the packet.
pj_sockaddr dst
Destination address.
The one and only history that we've captured.
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....
time_t ast_string_to_time_t(const char *str)
Returns a time_t from a string containing seconds since the epoch.
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller,...
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
int error(const char *format,...)
Vector container support.
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
#define AST_VECTOR_PTR_FREE(vec)
Deallocates this vector pointer.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
#define AST_VECTOR(name, type)
Define a vector structure.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.