Asterisk - The Open Source Telephony Project GIT-master-7e7a603
Data Structures | Macros | Enumerations | Functions | Variables
res_pjsip_history.c File Reference

PJSIP History. More...

#include "asterisk.h"
#include <pjsip.h>
#include <regex.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/cli.h"
#include "asterisk/netsock2.h"
#include "asterisk/vector.h"
#include "asterisk/lock.h"
#include "asterisk/res_pjproject.h"
Include dependency graph for res_pjsip_history.c:

Go to the source code of this file.

Data Structures

struct  allowed_field
 A field that we understand and can perform operations on. More...
 
struct  expression_token
 A token in the expression or an evaluated part of the expression. More...
 
struct  operator
 An operator that we understand in an expression. More...
 
struct  pjsip_history_entry
 An item in the history. More...
 
struct  vector_history_t
 The one and only history that we've captured. More...
 

Macros

#define APPEND_TO_OUTPUT(output, token)
 
#define HISTORY_INITIAL_SIZE   256
 

Enumerations

enum  expression_token_type { TOKEN_TYPE_FIELD , TOKEN_TYPE_OPERATOR , TOKEN_TYPE_RESULT }
 The type of token that has been parsed out of an expression. More...
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static struct expression_tokenbuild_expression_queue (struct ast_cli_args *a)
 Build a reverse polish notation expression queue. More...
 
static int clear_history_entries (void *obj)
 Remove all entries from vector_history. More...
 
static void clear_history_entry_cb (struct pjsip_history_entry *entry)
 Vector callback that releases the reference for the entry in a history vector. More...
 
static void display_entry_list (struct ast_cli_args *a, struct vector_history_t *vec)
 Print a list of the entries to the CLI. More...
 
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. More...
 
static void * entry_get_addr (struct pjsip_history_entry *entry)
 Callback to retrieve the entry's destination address. More...
 
static void * entry_get_number (struct pjsip_history_entry *entry)
 Callback to retrieve the entry index number. More...
 
static void * entry_get_sip_msg_call_id (struct pjsip_history_entry *entry)
 Callback to retrieve the entry's SIP Call-ID header. More...
 
static void * entry_get_sip_msg_request_method (struct pjsip_history_entry *entry)
 Callback to retrieve the entry's SIP request method type. More...
 
static void * entry_get_timestamp (struct pjsip_history_entry *entry)
 Callback to retrieve the entry's timestamp. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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'. More...
 
static int evaluate_not (struct operator*op, enum aco_option_type type, void *operand)
 Operator callback for determining logical NOT. More...
 
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. More...
 
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. More...
 
static struct expression_tokenexpression_token_alloc (enum expression_token_type token_type, void *value)
 Allocate an expression token. More...
 
static struct expression_tokenexpression_token_free (struct expression_token *token)
 Free an expression token and all others it references. More...
 
static struct vector_history_tfilter_history (struct ast_cli_args *a)
 Create a filtered history based on a user provided expression. More...
 
static struct allowed_fieldget_allowed_field (struct expression_token *token)
 Determine if the expression token matches a field in allowed_fields. More...
 
static pj_bool_t history_on_rx_msg (pjsip_rx_data *rdata)
 PJSIP callback when a SIP message is received. More...
 
static pj_status_t history_on_tx_msg (pjsip_tx_data *tdata)
 PJSIP callback when a SIP message is transmitted. More...
 
static int load_module (void)
 
static struct pjsip_history_entrypjsip_history_entry_alloc (pjsip_msg *msg)
 Create a pjsip_history_entry AO2 object. More...
 
static void pjsip_history_entry_dtor (void *obj)
 AO2 destructor for pjsip_history_entry. More...
 
static char * pjsip_set_history (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * pjsip_show_history (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int safe_vector_cleanup (void *obj)
 Cleanup routine for a history vector, serviced on a registered PJSIP thread. More...
 
static void sprint_list_entry (struct pjsip_history_entry *entry, char *line, int len)
 Format single line history entry. More...
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP History" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip", }
 
static struct allowed_field allowed_fields []
 The fields we allow. More...
 
static struct operator allowed_operators []
 Our allowed operations. More...
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static pj_caching_pool cachingpool
 Pool factory used by pjlib to allocate memory. More...
 
static struct ast_cli_entry cli_pjsip []
 
static int enabled
 Whether or not we are storing history. More...
 
static ast_mutex_t history_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 Mutex that protects vector_history. More...
 
static struct operator left_paren
 Operator token for a left parenthesis. More...
 
static int log_level = -1
 Log level for history output. More...
 
static pjsip_module logging_module
 
static int packet_number
 Packet count. More...
 
static struct vector_history_t vector_history
 

Detailed Description

PJSIP History.

Author
Matt Jordan mjord.nosp@m.an@d.nosp@m.igium.nosp@m..com

Definition in file res_pjsip_history.c.

Macro Definition Documentation

◆ APPEND_TO_OUTPUT

#define APPEND_TO_OUTPUT (   output,
  token 
)

◆ HISTORY_INITIAL_SIZE

#define HISTORY_INITIAL_SIZE   256

Definition at line 47 of file res_pjsip_history.c.

Enumeration Type Documentation

◆ expression_token_type

The type of token that has been parsed out of an expression.

Enumerator
TOKEN_TYPE_FIELD 

The expression_token contains a field

TOKEN_TYPE_OPERATOR 

The expression_token contains an operator

TOKEN_TYPE_RESULT 

The expression_token contains a previous result

Definition at line 135 of file res_pjsip_history.c.

135 {
136 /*! The \c expression_token contains a field */
138 /*! The \c expression_token contains an operator */
140 /*! The \c expression_token contains a previous result */
142};
@ TOKEN_TYPE_FIELD
@ TOKEN_TYPE_RESULT
@ TOKEN_TYPE_OPERATOR

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1410 of file res_pjsip_history.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1410 of file res_pjsip_history.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1410 of file res_pjsip_history.c.

◆ build_expression_queue()

static struct expression_token * build_expression_queue ( struct ast_cli_args a)
static

Build a reverse polish notation expression queue.

This function is an implementation of the Shunting-Yard Algorithm. It takes a user provided infix-notation expression and converts it into a reverse polish notation expression, which is a queue of tokens that can be easily parsed.

Parameters
aThe CLI arguments provided by the User, containing the infix expression
Return values
NULLerror
expression_tokenA 'queue' of expression tokens in RPN

Definition at line 804 of file res_pjsip_history.c.

805{
806 AST_VECTOR(, struct operator *) operators; /* A stack of saved operators */
807 struct expression_token *output = NULL; /* The output queue */
808 struct expression_token *head = NULL; /* Pointer to the head of /c output */
809 int i;
810
811#define APPEND_TO_OUTPUT(output, token) do { \
812 if ((output)) { \
813 (output)->next = (token); \
814 (output) = (token); \
815 } else { \
816 (output) = (token); \
817 head = (output); \
818 } \
819} while (0)
820
821 if (AST_VECTOR_INIT(&operators, 8)) {
822 return NULL;
823 }
824
825 for (i = 4; i < a->argc; i++) {
826 struct expression_token *out_token;
827 char *token = ast_strdupa(a->argv[i]);
828 int j;
829
830 /* Strip off and append any left parentheses */
831 if (token[0] == '(') {
832 AST_VECTOR_APPEND(&operators, &left_paren);
833 if (!token[1]) {
834 continue;
835 }
836 token = &token[1];
837 }
838
839 /* Handle the case where the token is an operator */
840 for (j = 0; j < ARRAY_LEN(allowed_operators); j++) {
841 int k;
842
843 if (strcasecmp(token, allowed_operators[j].symbol)) {
844 continue;
845 }
846
847 for (k = AST_VECTOR_SIZE(&operators) - 1; k >= 0; k--) {
848 struct operator *top = AST_VECTOR_GET(&operators, k);
849
850 /* Remove and push queued up operators, if they are of
851 * less precedence than this operator
852 */
855
856 if (!(out_token = expression_token_alloc(TOKEN_TYPE_OPERATOR, top))) {
857 goto error;
858 }
859 APPEND_TO_OUTPUT(output, out_token);
860 AST_VECTOR_REMOVE(&operators, k, 1);
861 }
862 }
863
864 AST_VECTOR_APPEND(&operators, &allowed_operators[j]);
865 token = NULL;
866 break;
867 }
868
869 /* Token was an operator; continue to next token */
870 if (!token) {
871 continue;
872 }
873
874 /* Handle a right parentheses either by itself or as part of the token.
875 * If part of the token, push the token onto the output queue first
876 */
877 if (token[0] == ')' || token[strlen(token) - 1] == ')') {
878
879 if (token[strlen(token) - 1] == ')') {
880 token[strlen(token) - 1] = '\0';
881
882 if (!(out_token = expression_token_alloc(TOKEN_TYPE_FIELD, token))) {
883 goto error;
884 }
885 APPEND_TO_OUTPUT(output, out_token);
886 token = NULL;
887 }
888
889 for (j = AST_VECTOR_SIZE(&operators) - 1; j >= 0; j--) {
890 struct operator *top = AST_VECTOR_GET(&operators, j);
891
892 AST_VECTOR_REMOVE(&operators, j, 1);
893 if (top == &left_paren) {
894 break;
895 }
896
897 if (!(out_token = expression_token_alloc(TOKEN_TYPE_OPERATOR, top))) {
898 goto error;
899 }
900 APPEND_TO_OUTPUT(output, out_token);
901 }
902 }
903
904 /* Just a plain token, push to the output queue */
905 if (token) {
906 if (!(out_token = expression_token_alloc(TOKEN_TYPE_FIELD, token))) {
907 goto error;
908 }
909 APPEND_TO_OUTPUT(output, out_token);
910 }
911 }
912
913 /* Remove any non-applied operators that remain, applying them
914 * to the output queue
915 */
916 for (i = AST_VECTOR_SIZE(&operators) - 1; i >= 0; i--) {
917 struct operator *top = AST_VECTOR_GET(&operators, i);
918 struct expression_token *out_token;
919
920 AST_VECTOR_REMOVE(&operators, i, 1);
921 if (top == &left_paren) {
922 ast_log(LOG_WARNING, "Unbalanced '(' parentheses in expression!\n");
923 continue;
924 }
925
926 if (!(out_token = expression_token_alloc(TOKEN_TYPE_OPERATOR, top))) {
927 goto error;
928 }
929 APPEND_TO_OUTPUT(output, out_token);
930 }
931
932 AST_VECTOR_FREE(&operators);
933 return head;
934
935error:
936 AST_VECTOR_FREE(&operators);
937 expression_token_free(output);
938 return NULL;
939}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define LOG_WARNING
static struct operator allowed_operators[]
Our allowed operations.
static struct expression_token * expression_token_alloc(enum expression_token_type token_type, void *value)
Allocate an expression token.
#define APPEND_TO_OUTPUT(output, token)
static struct expression_token * expression_token_free(struct expression_token *token)
Free an expression token and all others it references.
static struct operator left_paren
Operator token for a left parenthesis.
#define NULL
Definition: resample.c:96
A token in the expression or an evaluated part of the expression.
An operator that we understand in an expression.
int precedence
Precedence of the symbol.
int right_to_left
Non-zero if the operator is evaluated right-to-left.
static struct test_val a
int error(const char *format,...)
Definition: utils/frame.c:999
#define ARRAY_LEN(a)
Definition: utils.h:666
#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_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition: vector.h:412
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#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

References a, allowed_operators, APPEND_TO_OUTPUT, ARRAY_LEN, ast_log, ast_strdupa, AST_VECTOR, AST_VECTOR_APPEND, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_REMOVE, AST_VECTOR_SIZE, error(), expression_token_alloc(), expression_token_free(), left_paren, LOG_WARNING, NULL, operator::precedence, operator::right_to_left, TOKEN_TYPE_FIELD, and TOKEN_TYPE_OPERATOR.

Referenced by filter_history().

◆ clear_history_entries()

static int clear_history_entries ( void *  obj)
static

Remove all entries from vector_history.

This must be called from a registered PJSIP thread

Definition at line 781 of file res_pjsip_history.c.

782{
785 packet_number = 0;
787
788 return 0;
789}
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
static int packet_number
Packet count.
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 ast_mutex_t history_lock
Mutex that protects vector_history.
static struct vector_history_t vector_history
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625

References ast_mutex_lock, ast_mutex_unlock, AST_VECTOR_RESET, clear_history_entry_cb(), history_lock, packet_number, and vector_history.

Referenced by pjsip_set_history(), and unload_module().

◆ clear_history_entry_cb()

static void clear_history_entry_cb ( struct pjsip_history_entry entry)
static

Vector callback that releases the reference for the entry in a history vector.

Definition at line 771 of file res_pjsip_history.c.

772{
773 ao2_ref(entry, -1);
774}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
Definition: search.h:40

References ao2_ref.

Referenced by clear_history_entries(), filter_history(), and safe_vector_cleanup().

◆ display_entry_list()

static void display_entry_list ( struct ast_cli_args a,
struct vector_history_t vec 
)
static

Print a list of the entries to the CLI.

Definition at line 1186 of file res_pjsip_history.c.

1187{
1188 int i;
1189
1190 ast_cli(a->fd, "%-5.5s %-10.10s %-30.30s %-35.35s\n",
1191 "No.",
1192 "Timestamp",
1193 "(Dir) Address",
1194 "SIP Message");
1195 ast_cli(a->fd, "===== ========== ============================== ===================================\n");
1196
1197 for (i = 0; i < AST_VECTOR_SIZE(vec); i++) {
1198 struct pjsip_history_entry *entry;
1199 char line[256];
1200
1201 entry = AST_VECTOR_GET(vec, i);
1202 sprint_list_entry(entry, line, sizeof(line));
1203
1204 ast_cli(a->fd, "%s\n", line);
1205 }
1206}
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int len)
Format single line history entry.
An item in the history.

References a, ast_cli(), AST_VECTOR_GET, AST_VECTOR_SIZE, and sprint_list_entry().

Referenced by pjsip_show_history().

◆ display_single_entry()

static void display_single_entry ( struct ast_cli_args a,
struct pjsip_history_entry entry 
)
static

Print a detailed view of a single entry in the history to the CLI.

Definition at line 1152 of file res_pjsip_history.c.

1153{
1154 char addr[64], secs[AST_TIME_T_LEN];
1155 char *buf;
1156
1157 buf = ast_calloc(1, PJSIP_MAX_PKT_LEN * sizeof(char));
1158 if (!buf) {
1159 return;
1160 }
1161
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);
1164 ast_free(buf);
1165 return;
1166 }
1167
1168 if (entry->transmitted) {
1169 pj_sockaddr_print(&entry->dst, addr, sizeof(addr), 3);
1170 } else {
1171 pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3);
1172 }
1173
1174 ast_time_t_to_string(entry->timestamp.tv_sec, secs, sizeof(secs));
1175 ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10s --->\n",
1176 entry->number,
1177 entry->transmitted ? "Sent to" : "Received from",
1178 addr,
1179 secs);
1180 ast_cli(a->fd, "%s\n", buf);
1181
1182 ast_free(buf);
1183}
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
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....
Definition: time.c:152
#define AST_TIME_T_LEN
Definition: time.h:45

References a, ast_calloc, ast_cli(), ast_free, ast_log, AST_TIME_T_LEN, ast_time_t_to_string(), buf, and LOG_WARNING.

Referenced by pjsip_show_history().

◆ entry_get_addr()

static void * entry_get_addr ( struct pjsip_history_entry entry)
static

Callback to retrieve the entry's destination address.

Definition at line 483 of file res_pjsip_history.c.

484{
485 if (entry->transmitted) {
486 return &entry->dst;
487 } else {
488 return &entry->src;
489 }
490}

◆ entry_get_number()

static void * entry_get_number ( struct pjsip_history_entry entry)
static

Callback to retrieve the entry index number.

Definition at line 471 of file res_pjsip_history.c.

472{
473 return &entry->number;
474}

◆ entry_get_sip_msg_call_id()

static void * entry_get_sip_msg_call_id ( struct pjsip_history_entry entry)
static

Callback to retrieve the entry's SIP Call-ID header.

Definition at line 503 of file res_pjsip_history.c.

504{
505 pjsip_cid_hdr *cid_hdr;
506
507 cid_hdr = PJSIP_MSG_CID_HDR(entry->msg);
508
509 return &cid_hdr->id;
510}

◆ entry_get_sip_msg_request_method()

static void * entry_get_sip_msg_request_method ( struct pjsip_history_entry entry)
static

Callback to retrieve the entry's SIP request method type.

Definition at line 493 of file res_pjsip_history.c.

494{
495 if (entry->msg->type != PJSIP_REQUEST_MSG) {
496 return NULL;
497 }
498
499 return &entry->msg->line.req.method.name;
500}

References NULL.

◆ entry_get_timestamp()

static void * entry_get_timestamp ( struct pjsip_history_entry entry)
static

Callback to retrieve the entry's timestamp.

Definition at line 477 of file res_pjsip_history.c.

478{
479 return &entry->timestamp;
480}

◆ evaluate_and()

static int evaluate_and ( struct operator op,
enum aco_option_type  type,
void *  op_left,
struct expression_token op_right 
)
static

Operator callback for determining logical AND.

Definition at line 374 of file res_pjsip_history.c.

375{
376 switch (type) {
377 case OPT_BOOL_T:
378 case OPT_BOOLFLAG_T:
379 case OPT_INT_T:
380 case OPT_UINT_T:
381 return (*(int *)op_left && op_right->result);
382 default:
383 ast_log(LOG_WARNING, "Cannot evaluate: invalid operand type for operator '%s'\n", op->symbol);
384 }
385
386 return -1;
387}
static const char type[]
Definition: chan_ooh323.c:109
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ 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_INT_T
Type for default option handler for signed integers.
int result
The result of an evaluated expression.
const char * symbol
Our operator's symbol.

References ast_log, LOG_WARNING, OPT_BOOL_T, OPT_BOOLFLAG_T, OPT_INT_T, OPT_UINT_T, expression_token::result, and type.

◆ evaluate_equal()

static int evaluate_equal ( struct operator op,
enum aco_option_type  type,
void *  op_left,
struct expression_token op_right 
)
static

Operator callback for determining equality.

Definition at line 167 of file res_pjsip_history.c.

168{
169 switch (type) {
170 case OPT_BOOL_T:
171 case OPT_BOOLFLAG_T:
172 case OPT_INT_T:
173 case OPT_UINT_T:
174 {
175 int right;
176
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);
179 return -1;
180 }
181 return (*(int *)op_left) == right;
182 }
183 case OPT_DOUBLE_T:
184 {
185 double right;
186
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);
189 return -1;
190 }
191 return (*(double *)op_left) == right;
192 }
193 case OPT_CHAR_ARRAY_T:
195 /* In our case, we operate on pj_str_t */
196 return pj_strcmp2(op_left, op_right->field) == 0;
197 case OPT_NOOP_T:
198 /* Used for timeval */
199 {
200 struct timeval right = { 0, };
201
202 if ((right.tv_sec = ast_string_to_time_t(op_right->field)) == -1) {
203 ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field);
204 return -1;
205 }
206
207 return ast_tvcmp(*(struct timeval *)op_left, right) == 0;
208 }
209 case OPT_SOCKADDR_T:
210 /* In our case, we operate only on pj_sockaddr_t */
211 {
212 pj_sockaddr right;
213 pj_str_t str_right;
214
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);
218 return -1;
219 }
220
221 return pj_sockaddr_cmp(op_left, &right) == 0;
222 }
223 default:
224 ast_log(LOG_WARNING, "Cannot evaluate field '%s': invalid type for operator '%s'\n",
225 op_right->field, op->symbol);
226 }
227
228 return -1;
229}
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_CHAR_ARRAY_T
Type for default option handler for character array strings.
@ OPT_SOCKADDR_T
Type for default handler for ast_sockaddrs.
@ OPT_DOUBLE_T
Type for default option handler for doubles.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
char field[]
The field in the expression.
time_t ast_string_to_time_t(const char *str)
Returns a time_t from a string containing seconds since the epoch.
Definition: time.c:163
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller,...
Definition: time.h:137

References ast_log, ast_string_to_time_t(), ast_tvcmp(), expression_token::field, LOG_WARNING, OPT_BOOL_T, OPT_BOOLFLAG_T, OPT_CHAR_ARRAY_T, OPT_DOUBLE_T, OPT_INT_T, OPT_NOOP_T, OPT_SOCKADDR_T, OPT_STRINGFIELD_T, OPT_UINT_T, and type.

Referenced by evaluate_not_equal().

◆ evaluate_greater_than()

static int evaluate_greater_than ( struct operator op,
enum aco_option_type  type,
void *  op_left,
struct expression_token op_right 
)
static

Operator callback for determining if one operand is greater than another.

Definition at line 291 of file res_pjsip_history.c.

292{
293 switch (type) {
294 case OPT_BOOL_T:
295 case OPT_BOOLFLAG_T:
296 case OPT_INT_T:
297 case OPT_UINT_T:
298 {
299 int right;
300
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);
303 return -1;
304 }
305 return (*(int *)op_left) > right;
306 }
307 case OPT_DOUBLE_T:
308 {
309 double right;
310
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);
313 return -1;
314 }
315 return (*(double *)op_left) > right;
316 }
317 case OPT_NOOP_T:
318 /* Used for timeval */
319 {
320 struct timeval right = { 0, };
321
322 if ((right.tv_sec = ast_string_to_time_t(op_right->field)) == -1) {
323 ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field);
324 return -1;
325 }
326
327 return ast_tvcmp(*(struct timeval *)op_left, right) == 1;
328 }
329 default:
330 ast_log(LOG_WARNING, "Cannot evaluate field '%s': invalid type for operator '%s'\n",
331 op_right->field, op->symbol);
332 }
333
334 return -1;
335}

References ast_log, ast_string_to_time_t(), ast_tvcmp(), expression_token::field, LOG_WARNING, OPT_BOOL_T, OPT_BOOLFLAG_T, OPT_DOUBLE_T, OPT_INT_T, OPT_NOOP_T, OPT_UINT_T, and type.

Referenced by evaluate_less_than_or_equal().

◆ evaluate_greater_than_or_equal()

static int evaluate_greater_than_or_equal ( struct operator op,
enum aco_option_type  type,
void *  op_left,
struct expression_token op_right 
)
static

Operator callback for determining if one operand is greater than or equal to another.

Definition at line 348 of file res_pjsip_history.c.

349{
350 return !evaluate_less_than(op, type, op_left, op_right);
351}
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.

References evaluate_less_than(), and type.

◆ evaluate_history_entry()

static int evaluate_history_entry ( struct pjsip_history_entry entry,
struct expression_token queue 
)
static

Evaluate a single entry in this history using a RPN expression.

Parameters
entryThe entry in the history to evaluate
queueThe RPN expression
Return values
0The expression evaluated FALSE on entry
1The expression evaluated TRUE on entry
-1The expression errored

Definition at line 951 of file res_pjsip_history.c.

952{
953 AST_VECTOR(, struct expression_token *) stack; /* Our stack of results and operands */
954 struct expression_token *it_queue;
955 struct expression_token *final;
956 int result;
957 int i;
958
959 if (AST_VECTOR_INIT(&stack, 16)) {
960 return -1;
961 }
962
963 for (it_queue = queue; it_queue; it_queue = it_queue->next) {
964 struct expression_token *op_one;
965 struct expression_token *op_two = NULL;
966 struct expression_token *result;
967 int res = 0;
968
969 /* If this is not an operator, push it to the stack */
970 if (!it_queue->op) {
971 if (AST_VECTOR_APPEND(&stack, it_queue)) {
972 goto error;
973 }
974 continue;
975 }
976
977 if (AST_VECTOR_SIZE(&stack) < it_queue->op->operands) {
978 ast_log(LOG_WARNING, "Unable to evaluate expression operator '%s': not enough operands\n",
979 it_queue->op->symbol);
980 goto error;
981 }
982
983 if (it_queue->op->operands == 1) {
984 /* Unary operators currently consist only of 'not', which can only act
985 * upon an evaluated condition result.
986 */
987 ast_assert(it_queue->op->evaluate_unary != NULL);
988
989 op_one = AST_VECTOR_REMOVE(&stack, AST_VECTOR_SIZE(&stack) - 1, 1);
990 if (op_one->token_type != TOKEN_TYPE_RESULT) {
991 ast_log(LOG_WARNING, "Unable to evaluate '%s': operand is not the result of an operation\n",
992 it_queue->op->symbol);
993 goto error;
994 }
995
996 res = it_queue->op->evaluate_unary(it_queue->op, OPT_INT_T, &op_one->result) == 0 ? 0 : 1;
997 } else if (it_queue->op->operands == 2) {
998 struct allowed_field *field;
1000 void *value;
1001
1002 ast_assert(it_queue->op->evaluate != NULL);
1003
1004 op_one = AST_VECTOR_REMOVE(&stack, AST_VECTOR_SIZE(&stack) - 1, 1);
1005 op_two = AST_VECTOR_REMOVE(&stack, AST_VECTOR_SIZE(&stack) - 1, 1);
1006
1007 /* If operand two is a field, then it must be a field we recognize. */
1008 if (op_two->token_type == TOKEN_TYPE_FIELD) {
1009 field = get_allowed_field(op_two);
1010 if (!field) {
1011 ast_log(LOG_WARNING, "Unknown or unrecognized field: %s\n", op_two->field);
1012 goto error;
1013 }
1014
1015 type = field->return_type;
1016 value = field->get_field(entry);
1017 } else if (op_two->token_type == TOKEN_TYPE_RESULT) {
1018 type = OPT_INT_T;
1019 value = &op_two->result;
1020 } else {
1021 ast_log(LOG_WARNING, "Attempting to evaluate an operator: %s\n", op_two->op->symbol);
1022 goto error;
1023 }
1024
1025 if (value) {
1026 res = it_queue->op->evaluate(it_queue->op, type, value, op_one) == 0 ? 0 : 1;
1027 } else {
1028 res = 0;
1029 }
1030 } else {
1031 ast_log(LOG_WARNING, "Operator '%s' has an invalid number of operands\n", it_queue->op->symbol);
1032 ast_assert(0);
1033 goto error;
1034 }
1035
1036 /* Results are temporary; clean used ones up */
1037 if (op_one && op_one->token_type == TOKEN_TYPE_RESULT) {
1038 ast_free(op_one);
1039 }
1040 if (op_two && op_two->token_type == TOKEN_TYPE_RESULT) {
1041 ast_free(op_two);
1042 }
1043
1044 /* Push the result onto the stack */
1046 if (!result) {
1047 goto error;
1048 }
1049 if (AST_VECTOR_APPEND(&stack, result)) {
1051
1052 goto error;
1053 }
1054 }
1055
1056 /*
1057 * When the evaluation is complete, we must have:
1058 * - A single result remaining on the stack
1059 * - An actual result
1060 */
1061 if (AST_VECTOR_SIZE(&stack) != 1) {
1062 ast_log(LOG_WARNING, "Expression was unbalanced: %zu results remained after evaluation\n",
1063 AST_VECTOR_SIZE(&stack));
1064 goto error;
1065 }
1066
1067 final = AST_VECTOR_GET(&stack, 0);
1068 if (final->token_type != TOKEN_TYPE_RESULT) {
1069 ast_log(LOG_WARNING, "Expression did not create a usable result\n");
1070 goto error;
1071 }
1072 result = final->result;
1073 ast_free(final);
1074 AST_VECTOR_FREE(&stack);
1075
1076 return result;
1077
1078error:
1079 /* Clean out any remaining result expression tokens */
1080 for (i = 0; i < AST_VECTOR_SIZE(&stack); i++) {
1081 struct expression_token *failed_token = AST_VECTOR_GET(&stack, i);
1082
1083 if (failed_token->token_type == TOKEN_TYPE_RESULT) {
1084 ast_free(failed_token);
1085 }
1086 }
1087 AST_VECTOR_FREE(&stack);
1088 return -1;
1089}
static PGresult * result
Definition: cel_pgsql.c:84
aco_option_type
The option types.
static struct allowed_field * get_allowed_field(struct expression_token *token)
Determine if the expression token matches a field in allowed_fields.
A field that we understand and can perform operations on.
enum aco_option_type return_type
The type /c get_field returns.
void *(*const get_field)(struct pjsip_history_entry *entry)
Function that returns the field from a pjsip_history_entry.
struct expression_token * next
The next expression token in the queue.
enum expression_token_type token_type
The type of value stored in the expression token.
struct operator* op
An operator that evaluates expressions.
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(*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.
int value
Definition: syslog.c:37
#define ast_assert(a)
Definition: utils.h:739

References ast_assert, ast_free, ast_log, AST_VECTOR, AST_VECTOR_APPEND, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_REMOVE, AST_VECTOR_SIZE, error(), operator::evaluate, operator::evaluate_unary, expression_token_alloc(), expression_token_free(), expression_token::field, get_allowed_field(), allowed_field::get_field, LOG_WARNING, expression_token::next, NULL, expression_token::op, operator::operands, OPT_INT_T, result, expression_token::result, allowed_field::return_type, operator::symbol, expression_token::token_type, TOKEN_TYPE_FIELD, TOKEN_TYPE_RESULT, type, and value.

Referenced by filter_history().

◆ evaluate_less_than()

static int evaluate_less_than ( struct operator op,
enum aco_option_type  type,
void *  op_left,
struct expression_token op_right 
)
static

Operator callback for determining if one operand is less than another.

Definition at line 242 of file res_pjsip_history.c.

243{
244 switch (type) {
245 case OPT_BOOL_T:
246 case OPT_BOOLFLAG_T:
247 case OPT_INT_T:
248 case OPT_UINT_T:
249 {
250 int right;
251
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);
254 return -1;
255 }
256 return (*(int *)op_left) < right;
257 }
258 case OPT_DOUBLE_T:
259 {
260 double right;
261
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);
264 return -1;
265 }
266 return (*(double *)op_left) < right;
267 }
268 case OPT_NOOP_T:
269 /* Used for timeval */
270 {
271 struct timeval right = { 0, };
272
273 if ((right.tv_sec = ast_string_to_time_t(op_right->field)) == -1) {
274 ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field);
275 return -1;
276 }
277
278 return ast_tvcmp(*(struct timeval *)op_left, right) == -1;
279 }
280 default:
281 ast_log(LOG_WARNING, "Cannot evaluate field '%s': invalid type for operator '%s'\n",
282 op_right->field, op->symbol);
283 }
284
285 return -1;
286}

References ast_log, ast_string_to_time_t(), ast_tvcmp(), expression_token::field, LOG_WARNING, OPT_BOOL_T, OPT_BOOLFLAG_T, OPT_DOUBLE_T, OPT_INT_T, OPT_NOOP_T, OPT_UINT_T, and type.

Referenced by evaluate_greater_than_or_equal().

◆ evaluate_less_than_or_equal()

static int evaluate_less_than_or_equal ( struct operator op,
enum aco_option_type  type,
void *  op_left,
struct expression_token op_right 
)
static

Operator callback for determining if one operand is less than or equal to another.

Definition at line 340 of file res_pjsip_history.c.

341{
342 return !evaluate_greater_than(op, type, op_left, op_right);
343}
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.

References evaluate_greater_than(), and type.

◆ evaluate_like()

static int evaluate_like ( struct operator op,
enum aco_option_type  type,
void *  op_left,
struct expression_token op_right 
)
static

Operator callback for regex 'like'.

Definition at line 410 of file res_pjsip_history.c.

411{
412 switch (type) {
413 case OPT_CHAR_ARRAY_T:
415 /* In our case, we operate on pj_str_t */
416 {
417 int result;
418 regex_t regexbuf;
419 char buf[pj_strlen(op_left) + 1];
420
421 ast_copy_pj_str(buf, op_left, pj_strlen(op_left));
422 if (regcomp(&regexbuf, op_right->field, REG_EXTENDED | REG_NOSUB)) {
423 ast_log(LOG_WARNING, "Failed to compile '%s' into a regular expression\n", op_right->field);
424 return -1;
425 }
426
427 result = (regexec(&regexbuf, buf, 0, NULL, 0) == 0);
428 regfree(&regexbuf);
429
430 return result;
431 }
432 default:
433 ast_log(LOG_WARNING, "Cannot evaluate: invalid operand type for operator '%s'\n", op->symbol);
434 }
435
436 return -1;
437}
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.
Definition: res_pjsip.c:2201

References ast_copy_pj_str(), ast_log, buf, expression_token::field, LOG_WARNING, NULL, OPT_CHAR_ARRAY_T, OPT_STRINGFIELD_T, result, and type.

◆ evaluate_not()

static int evaluate_not ( struct operator op,
enum aco_option_type  type,
void *  operand 
)
static

Operator callback for determining logical NOT.

Definition at line 356 of file res_pjsip_history.c.

357{
358 switch (type) {
359 case OPT_BOOL_T:
360 case OPT_BOOLFLAG_T:
361 case OPT_INT_T:
362 case OPT_UINT_T:
363 return !(*(int *)operand);
364 default:
365 ast_log(LOG_WARNING, "Cannot evaluate: invalid operand type for operator '%s'\n", op->symbol);
366 }
367
368 return -1;
369}

References ast_log, LOG_WARNING, OPT_BOOL_T, OPT_BOOLFLAG_T, OPT_INT_T, OPT_UINT_T, and type.

◆ evaluate_not_equal()

static int evaluate_not_equal ( struct operator op,
enum aco_option_type  type,
void *  op_left,
struct expression_token op_right 
)
static

Operator callback for determining inequality.

Definition at line 234 of file res_pjsip_history.c.

235{
236 return !evaluate_equal(op, type, op_left, op_right);
237}
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.

References evaluate_equal(), and type.

◆ evaluate_or()

static int evaluate_or ( struct operator op,
enum aco_option_type  type,
void *  op_left,
struct expression_token op_right 
)
static

Operator callback for determining logical OR.

Definition at line 392 of file res_pjsip_history.c.

393{
394 switch (type) {
395 case OPT_BOOL_T:
396 case OPT_BOOLFLAG_T:
397 case OPT_INT_T:
398 case OPT_UINT_T:
399 return (*(int *)op_left || op_right->result);
400 default:
401 ast_log(LOG_WARNING, "Cannot evaluate: invalid operand type for operator '%s'\n", op->symbol);
402 }
403
404 return -1;
405}

References ast_log, LOG_WARNING, OPT_BOOL_T, OPT_BOOLFLAG_T, OPT_INT_T, OPT_UINT_T, expression_token::result, and type.

◆ expression_token_alloc()

static struct expression_token * expression_token_alloc ( enum expression_token_type  token_type,
void *  value 
)
static

Allocate an expression token.

Parameters
token_typeThe type of token in the expression
valueThe value/operator/result to pack into the token
Return values
NULLon failure
expression_tokenon success

Definition at line 547 of file res_pjsip_history.c.

548{
549 struct expression_token *token;
550
551 switch (token_type) {
554 token = ast_calloc(1, sizeof(*token));
555 break;
556 case TOKEN_TYPE_FIELD:
557 token = ast_calloc(1, sizeof(*token) + strlen((const char *)value) + 1);
558 break;
559 default:
560 ast_assert(0);
561 return NULL;
562 }
563
564 if (!token) {
565 return NULL;
566 }
567 token->token_type = token_type;
568
569 switch (token_type) {
571 token->result = *(int *)value;
572 break;
574 token->op = value;
575 break;
576 case TOKEN_TYPE_FIELD:
577 strcpy(token->field, value); /* safe */
578 break;
579 default:
580 ast_assert(0);
581 }
582
583 return token;
584}

References ast_assert, ast_calloc, expression_token::field, NULL, expression_token::op, expression_token::result, expression_token::token_type, TOKEN_TYPE_FIELD, TOKEN_TYPE_OPERATOR, TOKEN_TYPE_RESULT, and value.

Referenced by build_expression_queue(), and evaluate_history_entry().

◆ expression_token_free()

static struct expression_token * expression_token_free ( struct expression_token token)
static

Free an expression token and all others it references.

Definition at line 523 of file res_pjsip_history.c.

524{
525 struct expression_token *it_token;
526
527 it_token = token;
528 while (it_token) {
529 struct expression_token *prev = it_token;
530
531 it_token = it_token->next;
532 ast_free(prev);
533 }
534
535 return NULL;
536}

References ast_free, expression_token::next, and NULL.

Referenced by build_expression_queue(), evaluate_history_entry(), and filter_history().

◆ filter_history()

static struct vector_history_t * filter_history ( struct ast_cli_args a)
static

Create a filtered history based on a user provided expression.

Parameters
aThe CLI arguments containing the expression
Return values
NULLon error
Avector containing the filtered history on success

Definition at line 1099 of file res_pjsip_history.c.

1100{
1101 struct vector_history_t *output;
1102 struct expression_token *queue;
1103 int i;
1104
1105 output = ast_malloc(sizeof(*output));
1106 if (!output) {
1107 return NULL;
1108 }
1109
1110 if (AST_VECTOR_INIT(output, HISTORY_INITIAL_SIZE / 2)) {
1111 ast_free(output);
1112 return NULL;
1113 }
1114
1115 queue = build_expression_queue(a);
1116 if (!queue) {
1117 AST_VECTOR_PTR_FREE(output);
1118 return NULL;
1119 }
1120
1122 for (i = 0; i < AST_VECTOR_SIZE(&vector_history); i++) {
1124 int res;
1125
1126 res = evaluate_history_entry(entry, queue);
1127 if (res == -1) {
1128 /* Error in expression evaluation; bail */
1131 AST_VECTOR_FREE(output);
1132 ast_free(output);
1133 expression_token_free(queue);
1134 return NULL;
1135 } else if (!res) {
1136 continue;
1137 } else {
1138 ao2_bump(entry);
1139 if (AST_VECTOR_APPEND(output, entry)) {
1141 }
1142 }
1143 }
1145
1146 expression_token_free(queue);
1147
1148 return output;
1149}
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
#define HISTORY_INITIAL_SIZE
static struct expression_token * build_expression_queue(struct ast_cli_args *a)
Build a reverse polish notation expression queue.
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.
The one and only history that we've captured.
#define AST_VECTOR_PTR_FREE(vec)
Deallocates this vector pointer.
Definition: vector.h:189

References a, ao2_bump, ao2_cleanup, ast_free, ast_malloc, ast_mutex_lock, ast_mutex_unlock, AST_VECTOR_APPEND, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_PTR_FREE, AST_VECTOR_RESET, AST_VECTOR_SIZE, build_expression_queue(), clear_history_entry_cb(), evaluate_history_entry(), expression_token_free(), HISTORY_INITIAL_SIZE, history_lock, NULL, and vector_history.

Referenced by pjsip_show_history().

◆ get_allowed_field()

static struct allowed_field * get_allowed_field ( struct expression_token token)
static

Determine if the expression token matches a field in allowed_fields.

Definition at line 587 of file res_pjsip_history.c.

588{
589 int i;
590
592
593 for (i = 0; i < ARRAY_LEN(allowed_fields); i++) {
594 if (strcasecmp(allowed_fields[i].symbol, token->field)) {
595 continue;
596 }
597
598 return &allowed_fields[i];
599 }
600
601 return NULL;
602}
static struct allowed_field allowed_fields[]
The fields we allow.

References allowed_fields, ARRAY_LEN, ast_assert, expression_token::field, NULL, allowed_field::symbol, expression_token::token_type, and TOKEN_TYPE_FIELD.

Referenced by evaluate_history_entry().

◆ history_on_rx_msg()

static pj_bool_t history_on_rx_msg ( pjsip_rx_data *  rdata)
static

PJSIP callback when a SIP message is received.

Definition at line 728 of file res_pjsip_history.c.

729{
731
732 if (!enabled) {
733 return PJ_FALSE;
734 }
735
736 if (!rdata->msg_info.msg) {
737 return PJ_FALSE;
738 }
739
740 entry = pjsip_history_entry_alloc(rdata->msg_info.msg);
741 if (!entry) {
742 return PJ_FALSE;
743 }
744
745 if (rdata->tp_info.transport->addr_len) {
746 pj_sockaddr_cp(&entry->dst, &rdata->tp_info.transport->local_addr);
747 }
748
749 if (rdata->pkt_info.src_addr_len) {
750 pj_sockaddr_cp(&entry->src, &rdata->pkt_info.src_addr);
751 }
752
755 ao2_ref(entry, -1);
756 entry = NULL;
757 }
759
760 if (log_level != -1 && entry) {
761 char line[256];
762
763 sprint_list_entry(entry, line, sizeof(line));
764 ast_log_dynamic_level(log_level, "%s\n", line);
765 }
766
767 return PJ_FALSE;
768}
#define ast_log_dynamic_level(level,...)
Send a log message to a dynamically registered log level.
static int enabled
Whether or not we are storing history.
static struct pjsip_history_entry * pjsip_history_entry_alloc(pjsip_msg *msg)
Create a pjsip_history_entry AO2 object.
static int log_level
Log level for history output.

References ao2_ref, ast_log_dynamic_level, ast_mutex_lock, ast_mutex_unlock, AST_VECTOR_APPEND, enabled, history_lock, log_level, NULL, pjsip_history_entry_alloc(), sprint_list_entry(), and vector_history.

◆ history_on_tx_msg()

static pj_status_t history_on_tx_msg ( pjsip_tx_data *  tdata)
static

PJSIP callback when a SIP message is transmitted.

Definition at line 694 of file res_pjsip_history.c.

695{
697
698 if (!enabled) {
699 return PJ_SUCCESS;
700 }
701
702 entry = pjsip_history_entry_alloc(tdata->msg);
703 if (!entry) {
704 return PJ_SUCCESS;
705 }
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);
709
712 ao2_ref(entry, -1);
713 entry = NULL;
714 }
716
717 if (log_level != -1 && entry) {
718 char line[256];
719
720 sprint_list_entry(entry, line, sizeof(line));
721 ast_log_dynamic_level(log_level, "%s\n", line);
722 }
723
724 return PJ_SUCCESS;
725}

References ao2_ref, ast_log_dynamic_level, ast_mutex_lock, ast_mutex_unlock, AST_VECTOR_APPEND, enabled, history_lock, log_level, NULL, pjsip_history_entry_alloc(), sprint_list_entry(), and vector_history.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1370 of file res_pjsip_history.c.

1371{
1372 log_level = ast_logger_register_level("PJSIP_HISTORY");
1373 if (log_level < 0) {
1374 ast_log(LOG_WARNING, "Unable to register history log level\n");
1375 }
1376
1377 ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
1378
1380
1383
1385}
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
int ast_logger_register_level(const char *name)
Register a new logger level.
Definition: logger.c:2839
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
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_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:117
static pj_caching_pool cachingpool
Pool factory used by pjlib to allocate memory.
static struct ast_cli_entry cli_pjsip[]
static pjsip_module logging_module

References ARRAY_LEN, ast_cli_register_multiple, ast_log, ast_logger_register_level(), AST_MODULE_LOAD_SUCCESS, ast_pjproject_caching_pool_init(), ast_sip_register_service(), AST_VECTOR_INIT, cachingpool, cli_pjsip, HISTORY_INITIAL_SIZE, log_level, LOG_WARNING, logging_module, and vector_history.

◆ pjsip_history_entry_alloc()

static struct pjsip_history_entry * pjsip_history_entry_alloc ( pjsip_msg *  msg)
static

Create a pjsip_history_entry AO2 object.

Parameters
msgThe PJSIP message that this history entry wraps
Return values
AnAO2 pjsip_history_entry object on success
NULLon failure

Definition at line 628 of file res_pjsip_history.c.

629{
631
633 if (!entry) {
634 return NULL;
635 }
637 entry->timestamp = ast_tvnow();
638 entry->timestamp.tv_usec = 0;
639
640 entry->pool = pj_pool_create(&cachingpool.factory, NULL, PJSIP_POOL_RDATA_LEN,
641 PJSIP_POOL_RDATA_INC, NULL);
642 if (!entry->pool) {
643 ao2_ref(entry, -1);
644 return NULL;
645 }
646
647 entry->msg = pjsip_msg_clone(entry->pool, msg);
648 if (!entry->msg) {
649 ao2_ref(entry, -1);
650 return NULL;
651 }
652
653 return entry;
654}
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
static void pjsip_history_entry_dtor(void *obj)
AO2 destructor for pjsip_history_entry.
pjsip_msg * msg
The actual SIP message.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_ref, ast_atomic_fetchadd_int(), ast_tvnow(), cachingpool, pjsip_history_entry::msg, NULL, packet_number, and pjsip_history_entry_dtor().

Referenced by history_on_rx_msg(), and history_on_tx_msg().

◆ pjsip_history_entry_dtor()

static void pjsip_history_entry_dtor ( void *  obj)
static

AO2 destructor for pjsip_history_entry.

Definition at line 605 of file res_pjsip_history.c.

606{
607 struct pjsip_history_entry *entry = obj;
608
609 if (entry->pool) {
610 /* This mimics the behavior of pj_pool_safe_release
611 * which was introduced in pjproject 2.6.
612 */
613 pj_pool_t *temp_pool = entry->pool;
614
615 entry->pool = NULL;
616 pj_pool_release(temp_pool);
617 }
618}

References NULL.

Referenced by pjsip_history_entry_alloc().

◆ pjsip_set_history()

static char * pjsip_set_history ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1314 of file res_pjsip_history.c.

1315{
1316 const char *what;
1317
1318 if (cmd == CLI_INIT) {
1319 e->command = "pjsip set history {on|off|clear}";
1320 e->usage =
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";
1330 return NULL;
1331 } else if (cmd == CLI_GENERATE) {
1332 return NULL;
1333 }
1334
1335 what = a->argv[e->args - 1]; /* Guaranteed to exist */
1336
1337 if (a->argc == e->args) {
1338 if (!strcasecmp(what, "on")) {
1339 enabled = 1;
1340 ast_cli(a->fd, "PJSIP History enabled\n");
1341 return CLI_SUCCESS;
1342 } else if (!strcasecmp(what, "off")) {
1343 enabled = 0;
1344 ast_cli(a->fd, "PJSIP History disabled\n");
1345 return CLI_SUCCESS;
1346 } else if (!strcasecmp(what, "clear")) {
1348 ast_cli(a->fd, "PJSIP History cleared\n");
1349 return CLI_SUCCESS;
1350 }
1351 }
1352
1353 return CLI_SHOWUSAGE;
1354}
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
static int clear_history_entries(void *obj)
Remove all entries from vector_history.
int args
This gets set in ast_cli_register()
Definition: cli.h:185
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177

References a, ast_cli_entry::args, ast_cli(), ast_sip_push_task(), clear_history_entries(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, enabled, NULL, and ast_cli_entry::usage.

◆ pjsip_show_history()

static char * pjsip_show_history ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1220 of file res_pjsip_history.c.

1221{
1222 struct vector_history_t *vec = &vector_history;
1223 struct pjsip_history_entry *entry = NULL;
1224
1225 if (cmd == CLI_INIT) {
1226 e->command = "pjsip show history";
1227 e->usage =
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"
1243 "\n"
1244 " When filtering, standard Boolean operators can be used,\n"
1245 " as well as 'like' for regexs.\n"
1246 "\n"
1247 " Example:\n"
1248 " 'pjsip show history where number > 5 and (addr = \"192.168.0.3:5060\" or addr = \"192.168.0.5:5060\")'\n";
1249 return NULL;
1250 } else if (cmd == CLI_GENERATE) {
1251 return NULL;
1252 }
1253
1254 if (a->argc > 3) {
1255 if (!strcasecmp(a->argv[3], "entry") && a->argc == 5) {
1256 int num;
1257
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]);
1260 return CLI_FAILURE;
1261 }
1262
1263 /* Get the entry at the provided position */
1265 if (num >= AST_VECTOR_SIZE(&vector_history) || num < 0) {
1266 ast_cli(a->fd, "Entry '%d' does not exist\n", num);
1268 return CLI_FAILURE;
1269 }
1272 } else if (!strcasecmp(a->argv[3], "where")) {
1273 vec = filter_history(a);
1274 if (!vec) {
1275 return CLI_FAILURE;
1276 }
1277 } else {
1278 return CLI_SHOWUSAGE;
1279 }
1280 }
1281
1282 if (AST_VECTOR_SIZE(vec) == 1) {
1283 if (vec == &vector_history) {
1285 }
1286 entry = ao2_bump(AST_VECTOR_GET(vec, 0));
1287 if (vec == &vector_history) {
1289 }
1290 }
1291
1292 if (entry) {
1294 } else {
1295 if (vec == &vector_history) {
1297 }
1298
1299 display_entry_list(a, vec);
1300
1301 if (vec == &vector_history) {
1303 }
1304 }
1305
1306 if (vec != &vector_history) {
1308 }
1310
1311 return CLI_SUCCESS;
1312}
#define CLI_FAILURE
Definition: cli.h:46
static int safe_vector_cleanup(void *obj)
Cleanup routine for a history vector, serviced on a registered PJSIP thread.
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 display_entry_list(struct ast_cli_args *a, struct vector_history_t *vec)
Print a list of the entries to the CLI.

References a, ao2_bump, ao2_cleanup, ast_cli(), ast_mutex_lock, ast_mutex_unlock, ast_sip_push_task(), AST_VECTOR_GET, AST_VECTOR_SIZE, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, display_entry_list(), display_single_entry(), filter_history(), history_lock, NULL, safe_vector_cleanup(), ast_cli_entry::usage, and vector_history.

◆ safe_vector_cleanup()

static int safe_vector_cleanup ( void *  obj)
static

Cleanup routine for a history vector, serviced on a registered PJSIP thread.

Definition at line 1209 of file res_pjsip_history.c.

1210{
1211 struct vector_history_t *vec = obj;
1212
1214 AST_VECTOR_FREE(vec);
1215 ast_free(vec);
1216
1217 return 0;
1218}

References ast_free, AST_VECTOR_FREE, AST_VECTOR_RESET, and clear_history_entry_cb().

Referenced by pjsip_show_history().

◆ sprint_list_entry()

static void sprint_list_entry ( struct pjsip_history_entry entry,
char *  line,
int  len 
)
static

Format single line history entry.

Definition at line 657 of file res_pjsip_history.c.

658{
659 char addr[64], secs[AST_TIME_T_LEN];
660
661 if (entry->transmitted) {
662 pj_sockaddr_print(&entry->dst, addr, sizeof(addr), 3);
663 } else {
664 pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3);
665 }
666
667 ast_time_t_to_string(entry->timestamp.tv_sec, secs, sizeof(secs));
668
669 if (entry->msg->type == PJSIP_REQUEST_MSG) {
670 char uri[128];
671
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",
674 entry->number,
675 secs,
676 entry->transmitted ? "* ==>" : "* <==",
677 addr,
678 (int)pj_strlen(&entry->msg->line.req.method.name),
679 pj_strbuf(&entry->msg->line.req.method.name),
680 uri);
681 } else {
682 snprintf(line, len, "%-5.5d %-10.10s %-5.5s %-24.24s SIP/2.0 %u %.*s",
683 entry->number,
684 secs,
685 entry->transmitted ? "* ==>" : "* <==",
686 addr,
687 entry->msg->line.status.code,
688 (int)pj_strlen(&entry->msg->line.status.reason),
689 pj_strbuf(&entry->msg->line.status.reason));
690 }
691}
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

References AST_TIME_T_LEN, ast_time_t_to_string(), and len().

Referenced by display_entry_list(), history_on_rx_msg(), and history_on_tx_msg().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1387 of file res_pjsip_history.c.

1388{
1391
1394
1396
1397 if (log_level != -1) {
1398 ast_logger_unregister_level("PJSIP_HISTORY");
1399 }
1400
1401 return 0;
1402}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
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.
Definition: res_pjsip.c:2165
void ast_logger_unregister_level(const char *name)
Unregister a previously registered logger level.
Definition: logger.c:2897
void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
Destroy caching pool factory and all cached pools.
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:133

References ARRAY_LEN, ast_cli_unregister_multiple(), ast_logger_unregister_level(), ast_pjproject_caching_pool_destroy(), ast_sip_push_task_wait_servant(), ast_sip_unregister_service(), AST_VECTOR_FREE, cachingpool, clear_history_entries(), cli_pjsip, log_level, logging_module, NULL, and vector_history.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP History" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip", }
static

Definition at line 1410 of file res_pjsip_history.c.

◆ allowed_fields

struct allowed_field allowed_fields[]
static

The fields we allow.

Definition at line 513 of file res_pjsip_history.c.

Referenced by get_allowed_field().

◆ allowed_operators

struct operator allowed_operators[]
static

Our allowed operations.

Definition at line 453 of file res_pjsip_history.c.

Referenced by build_expression_queue().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1410 of file res_pjsip_history.c.

◆ cachingpool

pj_caching_pool cachingpool
static

Pool factory used by pjlib to allocate memory.

Definition at line 50 of file res_pjsip_history.c.

Referenced by load_module(), pjsip_history_entry_alloc(), and unload_module().

◆ cli_pjsip

struct ast_cli_entry cli_pjsip[]
static
Initial value:
= {
{ .handler = pjsip_set_history , .summary = "Enable/Disable PJSIP History" ,},
{ .handler = pjsip_show_history , .summary = "Display PJSIP History" ,},
}
static char * pjsip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * pjsip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 1365 of file res_pjsip_history.c.

Referenced by load_module(), and unload_module().

◆ enabled

int enabled
static

Whether or not we are storing history.

Definition at line 53 of file res_pjsip_history.c.

Referenced by history_on_rx_msg(), history_on_tx_msg(), and pjsip_set_history().

◆ history_lock

ast_mutex_t history_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Mutex that protects vector_history.

Definition at line 77 of file res_pjsip_history.c.

Referenced by clear_history_entries(), filter_history(), history_on_rx_msg(), history_on_tx_msg(), and pjsip_show_history().

◆ left_paren

struct operator left_paren
static
Initial value:
= {
.symbol = "(",
.precedence = 15
}

Operator token for a left parenthesis.

While this is used by the shunting-yard algorithm implementation, it should never appear in the resulting RPN queue of expression tokens

Definition at line 445 of file res_pjsip_history.c.

Referenced by build_expression_queue().

◆ log_level

int log_level = -1
static

Log level for history output.

Definition at line 159 of file res_pjsip_history.c.

Referenced by history_on_rx_msg(), history_on_tx_msg(), load_module(), unload_module(), and verify_log_result().

◆ logging_module

pjsip_module logging_module
static

Definition at line 1356 of file res_pjsip_history.c.

Referenced by load_module(), and unload_module().

◆ packet_number

int packet_number
static

Packet count.

Definition at line 56 of file res_pjsip_history.c.

Referenced by clear_history_entries(), and pjsip_history_entry_alloc().

◆ vector_history

struct vector_history_t vector_history
static