Asterisk - The Open Source Telephony Project  18.5.0
res_pjsip_history.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2015, Digium, Inc.
5  *
6  * Matt Jordan <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*!
20  * \file
21  * \brief PJSIP History
22  *
23  * \author Matt Jordan <[email protected]>
24  *
25  */
26 
27 /*** MODULEINFO
28  <depend>pjproject</depend>
29  <depend>res_pjsip</depend>
30  <support_level>extended</support_level>
31  ***/
32 
33 #include "asterisk.h"
34 
35 #include <pjsip.h>
36 #include <regex.h>
37 
38 #include "asterisk/res_pjsip.h"
39 #include "asterisk/module.h"
40 #include "asterisk/logger.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/netsock2.h"
43 #include "asterisk/vector.h"
44 #include "asterisk/lock.h"
45 #include "asterisk/res_pjproject.h"
46 
47 #define HISTORY_INITIAL_SIZE 256
48 
49 /*! \brief Pool factory used by pjlib to allocate memory. */
50 static pj_caching_pool cachingpool;
51 
52 /*! \brief Whether or not we are storing history */
53 static int enabled;
54 
55 /*! \brief Packet count */
56 static int packet_number;
57 
58 /*! \brief An item in the history */
60  /*! \brief Packet number */
61  int number;
62  /*! \brief Whether or not we transmitted the packet */
64  /*! \brief Time the packet was transmitted/received */
65  struct timeval timestamp;
66  /*! \brief Source address */
67  pj_sockaddr src;
68  /*! \brief Destination address */
69  pj_sockaddr dst;
70  /*! \brief Memory pool used to allocate \c msg */
71  pj_pool_t *pool;
72  /*! \brief The actual SIP message */
73  pjsip_msg *msg;
74 };
75 
76 /*! \brief Mutex that protects \ref vector_history */
78 
79 /*! \brief The one and only history that we've captured */
80 static AST_VECTOR(vector_history_t, struct pjsip_history_entry *) vector_history;
81 
82 struct expression_token;
83 
84 /*! \brief An operator that we understand in an expression */
85 struct operator {
86  /*! \brief Our operator's symbol */
87  const char *symbol;
88  /*! \brief Precedence of the symbol */
89  int precedence;
90  /*! \brief Non-zero if the operator is evaluated right-to-left */
91  int right_to_left;
92  /*! \brief Number of operands the operator takes */
93  int operands;
94  /*!
95  * \brief Evaluation function for unary operators
96  *
97  * \param op The operator being evaluated
98  * \param type The type of value contained in \c operand
99  * \param operand A pointer to the value to evaluate
100  *
101  * \retval -1 error
102  * \retval 0 evaluation is False
103  * \retval 1 evaluation is True
104  */
105  int (* const evaluate_unary)(struct operator *op, enum aco_option_type type, void *operand);
106  /*!
107  * \brief Evaluation function for binary operators
108  *
109  * \param op The operator being evaluated
110  * \param type The type of value contained in \c op_left
111  * \param op_left A pointer to the value to evaluate (a result or extracted from an entry)
112  * \param op_right The expression token containing the other value (a result or user-provided)
113  *
114  * \retval -1 error
115  * \retval 0 evaluation is False
116  * \retval 1 evaluation is True
117  */
118  int (* const evaluate)(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right);
119 };
120 
121 /*! \brief A field that we understand and can perform operations on */
123  /*! \brief The representation of the field */
124  const char *symbol;
125  /*! \brief The type /c get_field returns */
126  enum aco_option_type return_type;
127  /*!
128  * \brief Function that returns the field from a pjsip_history_entry
129  *
130  * Note that the function must return a pointer to the location in
131  * \c pjsip_history_entry - no memory should be allocated as the caller
132  * will not dispose of any
133  */
134  void *(* const get_field)(struct pjsip_history_entry *entry);
135 };
136 
137 /*! \brief The type of token that has been parsed out of an expression */
139  /*! The \c expression_token contains a field */
141  /*! The \c expression_token contains an operator */
143  /*! The \c expression_token contains a previous result */
145 };
146 
147 /*! \brief A token in the expression or an evaluated part of the expression */
149  /*! \brief The next expression token in the queue */
151  /*! \brief The type of value stored in the expression token */
153  /*! \brief An operator that evaluates expressions */
154  struct operator *op;
155  /*! \brief The result of an evaluated expression */
156  int result;
157  /*! \brief The field in the expression */
158  char field[];
159 };
160 
161 /*! \brief Log level for history output */
162 static int log_level = -1;
163 
164 /*!
165  * \brief Operator callback for determining equality
166  */
167 static int evaluate_equal(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
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:
194  case OPT_STRINGFIELD_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 (sscanf(op_right->field, "%ld", &right.tv_sec) != 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 }
230 
231 /*!
232  * \brief Operator callback for determining inequality
233  */
234 static int evaluate_not_equal(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
235 {
236  return !evaluate_equal(op, type, op_left, op_right);
237 }
238 
239 /*
240  * \brief Operator callback for determining if one operand is less than another
241  */
242 static int evaluate_less_than(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
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 (sscanf(op_right->field, "%ld", &right.tv_sec) != 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 }
287 
288 /*
289  * \brief Operator callback for determining if one operand is greater than another
290  */
291 static int evaluate_greater_than(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
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 (sscanf(op_right->field, "%ld", &right.tv_sec) != 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 }
336 
337 /*
338  * \brief Operator callback for determining if one operand is less than or equal to another
339  */
340 static int evaluate_less_than_or_equal(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
341 {
342  return !evaluate_greater_than(op, type, op_left, op_right);
343 }
344 
345 /*
346  * \brief Operator callback for determining if one operand is greater than or equal to another
347  */
348 static int evaluate_greater_than_or_equal(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
349 {
350  return !evaluate_less_than(op, type, op_left, op_right);
351 }
352 
353 /*
354  * \brief Operator callback for determining logical NOT
355  */
356 static int evaluate_not(struct operator *op, enum aco_option_type type, void *operand)
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 }
370 
371 /*
372  * \brief Operator callback for determining logical AND
373  */
374 static int evaluate_and(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
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 }
388 
389 /*
390  * \brief Operator callback for determining logical OR
391  */
392 static int evaluate_or(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
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 }
406 
407 /*
408  * \brief Operator callback for regex 'like'
409  */
410 static int evaluate_like(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
411 {
412  switch (type) {
413  case OPT_CHAR_ARRAY_T:
414  case OPT_STRINGFIELD_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 }
438 
439 /*!
440  * \brief Operator token for a left parenthesis.
441  *
442  * While this is used by the shunting-yard algorithm implementation,
443  * it should never appear in the resulting RPN queue of expression tokens
444  */
445 static struct operator left_paren = {
446  .symbol = "(",
447  .precedence = 15
448 };
449 
450 /*!
451  * \brief Our allowed operations
452  */
453 static struct operator allowed_operators[] = {
454  { .symbol = "=", .precedence = 7, .operands = 2, .evaluate = evaluate_equal, },
455  { .symbol = "==", .precedence = 7, .operands = 2, .evaluate = evaluate_equal, },
456  { .symbol = "!=", .precedence = 7, .operands = 2, .evaluate = evaluate_not_equal, },
457  { .symbol = "<", .precedence = 6, .operands = 2, .evaluate = evaluate_less_than, },
458  { .symbol = ">", .precedence = 6, .operands = 2, .evaluate = evaluate_greater_than, },
459  { .symbol = "<=", .precedence = 6, .operands = 2, .evaluate = evaluate_less_than_or_equal, },
460  { .symbol = ">=", .precedence = 6, .operands = 2, .evaluate = evaluate_greater_than_or_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, },
468 };
469 
470 /*! \brief Callback to retrieve the entry index number */
472 {
473  return &entry->number;
474 }
475 
476 /*! \brief Callback to retrieve the entry's timestamp */
478 {
479  return &entry->timestamp;
480 }
481 
482 /*! \brief Callback to retrieve the entry's destination address */
484 {
485  if (entry->transmitted) {
486  return &entry->dst;
487  } else {
488  return &entry->src;
489  }
490 }
491 
492 /*! \brief Callback to retrieve the entry's SIP request method type */
494 {
495  if (entry->msg->type != PJSIP_REQUEST_MSG) {
496  return NULL;
497  }
498 
499  return &entry->msg->line.req.method.name;
500 }
501 
502 /*! \brief Callback to retrieve the entry's SIP Call-ID header */
504 {
505  pjsip_cid_hdr *cid_hdr;
506 
507  cid_hdr = PJSIP_MSG_CID_HDR(entry->msg);
508 
509  return &cid_hdr->id;
510 }
511 
512 /*! \brief The fields we allow */
513 static struct allowed_field allowed_fields[] = {
514  { .symbol = "number", .return_type = OPT_INT_T, .get_field = entry_get_number, },
515  /* We co-op the NOOP type here for timeval */
516  { .symbol = "timestamp", .return_type = OPT_NOOP_T, .get_field = entry_get_timestamp, },
517  { .symbol = "addr", .return_type = OPT_SOCKADDR_T, .get_field = entry_get_addr, },
518  { .symbol = "sip.msg.request.method", .return_type = OPT_CHAR_ARRAY_T, .get_field = entry_get_sip_msg_request_method, },
519  { .symbol = "sip.msg.call-id", .return_type = OPT_CHAR_ARRAY_T, .get_field = entry_get_sip_msg_call_id, },
520 };
521 
522 /*! \brief Free an expression token and all others it references */
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 }
537 
538 /*!
539  * \brief Allocate an expression token
540  *
541  * \param token_type The type of token in the expression
542  * \param value The value/operator/result to pack into the token
543  *
544  * \retval NULL on failure
545  * \retval \c expression_token on success
546  */
548 {
549  struct expression_token *token;
550 
551  switch (token_type) {
552  case TOKEN_TYPE_RESULT:
553  case TOKEN_TYPE_OPERATOR:
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) {
570  case TOKEN_TYPE_RESULT:
571  token->result = *(int *)value;
572  break;
573  case TOKEN_TYPE_OPERATOR:
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 }
585 
586 /*! \brief Determine if the expression token matches a field in \c allowed_fields */
587 static struct allowed_field *get_allowed_field(struct expression_token *token)
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 }
603 
604 /*! \brief AO2 destructor for \c pjsip_history_entry */
605 static void pjsip_history_entry_dtor(void *obj)
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 }
619 
620 /*!
621  * \brief Create a \c pjsip_history_entry AO2 object
622  *
623  * \param msg The PJSIP message that this history entry wraps
624  *
625  * \retval An AO2 \c pjsip_history_entry object on success
626  * \retval NULL on failure
627  */
629 {
630  struct pjsip_history_entry *entry;
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 }
655 
656 /*! \brief Format single line history entry */
657 static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int len)
658 {
659  char addr[64];
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  if (entry->msg->type == PJSIP_REQUEST_MSG) {
668  char uri[128];
669 
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",
672  entry->number,
673  entry->timestamp.tv_sec,
674  entry->transmitted ? "* ==>" : "* <==",
675  addr,
676  (int)pj_strlen(&entry->msg->line.req.method.name),
677  pj_strbuf(&entry->msg->line.req.method.name),
678  uri);
679  } else {
680  snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s SIP/2.0 %u %.*s",
681  entry->number,
682  entry->timestamp.tv_sec,
683  entry->transmitted ? "* ==>" : "* <==",
684  addr,
685  entry->msg->line.status.code,
686  (int)pj_strlen(&entry->msg->line.status.reason),
687  pj_strbuf(&entry->msg->line.status.reason));
688  }
689 }
690 
691 /*! \brief PJSIP callback when a SIP message is transmitted */
692 static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata)
693 {
694  struct pjsip_history_entry *entry;
695 
696  if (!enabled) {
697  return PJ_SUCCESS;
698  }
699 
700  entry = pjsip_history_entry_alloc(tdata->msg);
701  if (!entry) {
702  return PJ_SUCCESS;
703  }
704  entry->transmitted = 1;
705  pj_sockaddr_cp(&entry->src, &tdata->tp_info.transport->local_addr);
706  pj_sockaddr_cp(&entry->dst, &tdata->tp_info.dst_addr);
707 
709  if (AST_VECTOR_APPEND(&vector_history, entry)) {
710  ao2_ref(entry, -1);
711  entry = NULL;
712  }
714 
715  if (log_level != -1 && entry) {
716  char line[256];
717 
718  sprint_list_entry(entry, line, sizeof(line));
719  ast_log_dynamic_level(log_level, "%s\n", line);
720  }
721 
722  return PJ_SUCCESS;
723 }
724 
725 /*! \brief PJSIP callback when a SIP message is received */
726 static pj_bool_t history_on_rx_msg(pjsip_rx_data *rdata)
727 {
728  struct pjsip_history_entry *entry;
729 
730  if (!enabled) {
731  return PJ_FALSE;
732  }
733 
734  if (!rdata->msg_info.msg) {
735  return PJ_FALSE;
736  }
737 
738  entry = pjsip_history_entry_alloc(rdata->msg_info.msg);
739  if (!entry) {
740  return PJ_FALSE;
741  }
742 
743  if (rdata->tp_info.transport->addr_len) {
744  pj_sockaddr_cp(&entry->dst, &rdata->tp_info.transport->local_addr);
745  }
746 
747  if (rdata->pkt_info.src_addr_len) {
748  pj_sockaddr_cp(&entry->src, &rdata->pkt_info.src_addr);
749  }
750 
752  if (AST_VECTOR_APPEND(&vector_history, entry)) {
753  ao2_ref(entry, -1);
754  entry = NULL;
755  }
757 
758  if (log_level != -1 && entry) {
759  char line[256];
760 
761  sprint_list_entry(entry, line, sizeof(line));
762  ast_log_dynamic_level(log_level, "%s\n", line);
763  }
764 
765  return PJ_FALSE;
766 }
767 
768 /*! \brief Vector callback that releases the reference for the entry in a history vector */
770 {
771  ao2_ref(entry, -1);
772 }
773 
774 /*!
775  * \brief Remove all entries from \ref vector_history
776  *
777  * This must be called from a registered PJSIP thread
778  */
779 static int clear_history_entries(void *obj)
780 {
782  AST_VECTOR_RESET(&vector_history, clear_history_entry_cb);
783  packet_number = 0;
785 
786  return 0;
787 }
788 
789 /*!
790  * \brief Build a reverse polish notation expression queue
791  *
792  * This function is an implementation of the Shunting-Yard Algorithm. It takes
793  * a user provided infix-notation expression and converts it into a reverse
794  * polish notation expression, which is a queue of tokens that can be easily
795  * parsed.
796  *
797  * \params a The CLI arguments provided by the User, containing the infix expression
798  *
799  * \retval NULL error
800  * \retval expression_token A 'queue' of expression tokens in RPN
801  */
803 {
804  AST_VECTOR(, struct operator *) operators; /* A stack of saved operators */
805  struct expression_token *output = NULL; /* The output queue */
806  struct expression_token *head = NULL; /* Pointer to the head of /c output */
807  int i;
808 
809 #define APPEND_TO_OUTPUT(output, token) do { \
810  if ((output)) { \
811  (output)->next = (token); \
812  (output) = (token); \
813  } else { \
814  (output) = (token); \
815  head = (output); \
816  } \
817 } while (0)
818 
819  if (AST_VECTOR_INIT(&operators, 8)) {
820  return NULL;
821  }
822 
823  for (i = 4; i < a->argc; i++) {
824  struct expression_token *out_token;
825  char *token = ast_strdupa(a->argv[i]);
826  int j;
827 
828  /* Strip off and append any left parentheses */
829  if (token[0] == '(') {
830  AST_VECTOR_APPEND(&operators, &left_paren);
831  if (!token[1]) {
832  continue;
833  }
834  token = &token[1];
835  }
836 
837  /* Handle the case where the token is an operator */
838  for (j = 0; j < ARRAY_LEN(allowed_operators); j++) {
839  int k;
840 
841  if (strcasecmp(token, allowed_operators[j].symbol)) {
842  continue;
843  }
844 
845  for (k = AST_VECTOR_SIZE(&operators) - 1; k >= 0; k--) {
846  struct operator *top = AST_VECTOR_GET(&operators, k);
847 
848  /* Remove and push queued up operators, if they are of
849  * less precedence than this operator
850  */
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)) {
853 
854  if (!(out_token = expression_token_alloc(TOKEN_TYPE_OPERATOR, top))) {
855  goto error;
856  }
857  APPEND_TO_OUTPUT(output, out_token);
858  AST_VECTOR_REMOVE(&operators, k, 1);
859  }
860  }
861 
862  AST_VECTOR_APPEND(&operators, &allowed_operators[j]);
863  token = NULL;
864  break;
865  }
866 
867  /* Token was an operator; continue to next token */
868  if (!token) {
869  continue;
870  }
871 
872  /* Handle a right parentheses either by itself or as part of the token.
873  * If part of the token, push the token onto the output queue first
874  */
875  if (token[0] == ')' || token[strlen(token) - 1] == ')') {
876 
877  if (token[strlen(token) - 1] == ')') {
878  token[strlen(token) - 1] = '\0';
879 
880  if (!(out_token = expression_token_alloc(TOKEN_TYPE_FIELD, token))) {
881  goto error;
882  }
883  APPEND_TO_OUTPUT(output, out_token);
884  token = NULL;
885  }
886 
887  for (j = AST_VECTOR_SIZE(&operators) - 1; j >= 0; j--) {
888  struct operator *top = AST_VECTOR_GET(&operators, j);
889 
890  AST_VECTOR_REMOVE(&operators, j, 1);
891  if (top == &left_paren) {
892  break;
893  }
894 
895  if (!(out_token = expression_token_alloc(TOKEN_TYPE_OPERATOR, top))) {
896  goto error;
897  }
898  APPEND_TO_OUTPUT(output, out_token);
899  }
900  }
901 
902  /* Just a plain token, push to the output queue */
903  if (token) {
904  if (!(out_token = expression_token_alloc(TOKEN_TYPE_FIELD, token))) {
905  goto error;
906  }
907  APPEND_TO_OUTPUT(output, out_token);
908  }
909  }
910 
911  /* Remove any non-applied operators that remain, applying them
912  * to the output queue
913  */
914  for (i = AST_VECTOR_SIZE(&operators) - 1; i >= 0; i--) {
915  struct operator *top = AST_VECTOR_GET(&operators, i);
916  struct expression_token *out_token;
917 
918  AST_VECTOR_REMOVE(&operators, i, 1);
919  if (top == &left_paren) {
920  ast_log(LOG_WARNING, "Unbalanced '(' parentheses in expression!\n");
921  continue;
922  }
923 
924  if (!(out_token = expression_token_alloc(TOKEN_TYPE_OPERATOR, top))) {
925  goto error;
926  }
927  APPEND_TO_OUTPUT(output, out_token);
928  }
929 
930  AST_VECTOR_FREE(&operators);
931  return head;
932 
933 error:
934  AST_VECTOR_FREE(&operators);
935  expression_token_free(output);
936  return NULL;
937 }
938 
939 /*!
940  * \brief Evaluate a single entry in this history using a RPN expression
941  *
942  * \param entry The entry in the history to evaluate
943  * \param queue The RPN expression
944  *
945  * \retval 0 The expression evaluated FALSE on \c entry
946  * \retval 1 The expression evaluated TRUE on \c entry
947  * \retval -1 The expression errored
948  */
950 {
951  AST_VECTOR(, struct expression_token *) stack; /* Our stack of results and operands */
952  struct expression_token *it_queue;
953  struct expression_token *final;
954  int result;
955  int i;
956 
957  if (AST_VECTOR_INIT(&stack, 16)) {
958  return -1;
959  }
960 
961  for (it_queue = queue; it_queue; it_queue = it_queue->next) {
962  struct expression_token *op_one;
963  struct expression_token *op_two = NULL;
964  struct expression_token *result;
965  int res = 0;
966 
967  /* If this is not an operator, push it to the stack */
968  if (!it_queue->op) {
969  if (AST_VECTOR_APPEND(&stack, it_queue)) {
970  goto error;
971  }
972  continue;
973  }
974 
975  if (AST_VECTOR_SIZE(&stack) < it_queue->op->operands) {
976  ast_log(LOG_WARNING, "Unable to evaluate expression operator '%s': not enough operands\n",
977  it_queue->op->symbol);
978  goto error;
979  }
980 
981  if (it_queue->op->operands == 1) {
982  /* Unary operators currently consist only of 'not', which can only act
983  * upon an evaluated condition result.
984  */
985  ast_assert(it_queue->op->evaluate_unary != NULL);
986 
987  op_one = AST_VECTOR_REMOVE(&stack, AST_VECTOR_SIZE(&stack) - 1, 1);
988  if (op_one->token_type != TOKEN_TYPE_RESULT) {
989  ast_log(LOG_WARNING, "Unable to evaluate '%s': operand is not the result of an operation\n",
990  it_queue->op->symbol);
991  goto error;
992  }
993 
994  res = it_queue->op->evaluate_unary(it_queue->op, OPT_INT_T, &op_one->result) == 0 ? 0 : 1;
995  } else if (it_queue->op->operands == 2) {
996  struct allowed_field *field;
997  enum aco_option_type type;
998  void *value;
999 
1000  ast_assert(it_queue->op->evaluate != NULL);
1001 
1002  op_one = AST_VECTOR_REMOVE(&stack, AST_VECTOR_SIZE(&stack) - 1, 1);
1003  op_two = AST_VECTOR_REMOVE(&stack, AST_VECTOR_SIZE(&stack) - 1, 1);
1004 
1005  /* If operand two is a field, then it must be a field we recognize. */
1006  if (op_two->token_type == TOKEN_TYPE_FIELD) {
1007  field = get_allowed_field(op_two);
1008  if (!field) {
1009  ast_log(LOG_WARNING, "Unknown or unrecognized field: %s\n", op_two->field);
1010  goto error;
1011  }
1012 
1013  type = field->return_type;
1014  value = field->get_field(entry);
1015  } else if (op_two->token_type == TOKEN_TYPE_RESULT) {
1016  type = OPT_INT_T;
1017  value = &op_two->result;
1018  } else {
1019  ast_log(LOG_WARNING, "Attempting to evaluate an operator: %s\n", op_two->op->symbol);
1020  goto error;
1021  }
1022 
1023  if (value) {
1024  res = it_queue->op->evaluate(it_queue->op, type, value, op_one) == 0 ? 0 : 1;
1025  } else {
1026  res = 0;
1027  }
1028  } else {
1029  ast_log(LOG_WARNING, "Operator '%s' has an invalid number of operands\n", it_queue->op->symbol);
1030  ast_assert(0);
1031  goto error;
1032  }
1033 
1034  /* Results are temporary; clean used ones up */
1035  if (op_one && op_one->token_type == TOKEN_TYPE_RESULT) {
1036  ast_free(op_one);
1037  }
1038  if (op_two && op_two->token_type == TOKEN_TYPE_RESULT) {
1039  ast_free(op_two);
1040  }
1041 
1042  /* Push the result onto the stack */
1043  result = expression_token_alloc(TOKEN_TYPE_RESULT, &res);
1044  if (!result) {
1045  goto error;
1046  }
1047  if (AST_VECTOR_APPEND(&stack, result)) {
1048  expression_token_free(result);
1049 
1050  goto error;
1051  }
1052  }
1053 
1054  /*
1055  * When the evaluation is complete, we must have:
1056  * - A single result remaining on the stack
1057  * - An actual result
1058  */
1059  if (AST_VECTOR_SIZE(&stack) != 1) {
1060  ast_log(LOG_WARNING, "Expression was unbalanced: %zu results remained after evaluation\n",
1061  AST_VECTOR_SIZE(&stack));
1062  goto error;
1063  }
1064 
1065  final = AST_VECTOR_GET(&stack, 0);
1066  if (final->token_type != TOKEN_TYPE_RESULT) {
1067  ast_log(LOG_WARNING, "Expression did not create a usable result\n");
1068  goto error;
1069  }
1070  result = final->result;
1071  ast_free(final);
1072  AST_VECTOR_FREE(&stack);
1073 
1074  return result;
1075 
1076 error:
1077  /* Clean out any remaining result expression tokens */
1078  for (i = 0; i < AST_VECTOR_SIZE(&stack); i++) {
1079  struct expression_token *failed_token = AST_VECTOR_GET(&stack, i);
1080 
1081  if (failed_token->token_type == TOKEN_TYPE_RESULT) {
1082  ast_free(failed_token);
1083  }
1084  }
1085  AST_VECTOR_FREE(&stack);
1086  return -1;
1087 }
1088 
1089 /*!
1090  * \brief Create a filtered history based on a user provided expression
1091  *
1092  * \param a The CLI arguments containing the expression
1093  *
1094  * \retval NULL on error
1095  * \retval A vector containing the filtered history on success
1096  */
1097 static struct vector_history_t *filter_history(struct ast_cli_args *a)
1098 {
1099  struct vector_history_t *output;
1100  struct expression_token *queue;
1101  int i;
1102 
1103  output = ast_malloc(sizeof(*output));
1104  if (!output) {
1105  return NULL;
1106  }
1107 
1108  if (AST_VECTOR_INIT(output, HISTORY_INITIAL_SIZE / 2)) {
1109  ast_free(output);
1110  return NULL;
1111  }
1112 
1113  queue = build_expression_queue(a);
1114  if (!queue) {
1115  AST_VECTOR_PTR_FREE(output);
1116  return NULL;
1117  }
1118 
1120  for (i = 0; i < AST_VECTOR_SIZE(&vector_history); i++) {
1121  struct pjsip_history_entry *entry = AST_VECTOR_GET(&vector_history, i);
1122  int res;
1123 
1124  res = evaluate_history_entry(entry, queue);
1125  if (res == -1) {
1126  /* Error in expression evaluation; bail */
1129  AST_VECTOR_FREE(output);
1130  ast_free(output);
1131  expression_token_free(queue);
1132  return NULL;
1133  } else if (!res) {
1134  continue;
1135  } else {
1136  ao2_bump(entry);
1137  if (AST_VECTOR_APPEND(output, entry)) {
1138  ao2_cleanup(entry);
1139  }
1140  }
1141  }
1143 
1144  expression_token_free(queue);
1145 
1146  return output;
1147 }
1148 
1149 /*! \brief Print a detailed view of a single entry in the history to the CLI */
1151 {
1152  char addr[64];
1153  char *buf;
1154 
1155  buf = ast_calloc(1, PJSIP_MAX_PKT_LEN * sizeof(char));
1156  if (!buf) {
1157  return;
1158  }
1159 
1160  if (pjsip_msg_print(entry->msg, buf, PJSIP_MAX_PKT_LEN) == -1) {
1161  ast_log(LOG_WARNING, "Unable to print SIP message %d: packet too large!\n", entry->number);
1162  ast_free(buf);
1163  return;
1164  }
1165 
1166  if (entry->transmitted) {
1167  pj_sockaddr_print(&entry->dst, addr, sizeof(addr), 3);
1168  } else {
1169  pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3);
1170  }
1171 
1172  ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10ld --->\n",
1173  entry->number,
1174  entry->transmitted ? "Sent to" : "Received from",
1175  addr,
1176  entry->timestamp.tv_sec);
1177  ast_cli(a->fd, "%s\n", buf);
1178 
1179  ast_free(buf);
1180 }
1181 
1182 /*! \brief Print a list of the entries to the CLI */
1183 static void display_entry_list(struct ast_cli_args *a, struct vector_history_t *vec)
1184 {
1185  int i;
1186 
1187  ast_cli(a->fd, "%-5.5s %-10.10s %-30.30s %-35.35s\n",
1188  "No.",
1189  "Timestamp",
1190  "(Dir) Address",
1191  "SIP Message");
1192  ast_cli(a->fd, "===== ========== ============================== ===================================\n");
1193 
1194  for (i = 0; i < AST_VECTOR_SIZE(vec); i++) {
1195  struct pjsip_history_entry *entry;
1196  char line[256];
1197 
1198  entry = AST_VECTOR_GET(vec, i);
1199  sprint_list_entry(entry, line, sizeof(line));
1200 
1201  ast_cli(a->fd, "%s\n", line);
1202  }
1203 }
1204 
1205 /*! \brief Cleanup routine for a history vector, serviced on a registered PJSIP thread */
1206 static int safe_vector_cleanup(void *obj)
1207 {
1208  struct vector_history_t *vec = obj;
1209 
1211  AST_VECTOR_FREE(vec);
1212  ast_free(vec);
1213 
1214  return 0;
1215 }
1216 
1217 static char *pjsip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1218 {
1219  struct vector_history_t *vec = &vector_history;
1220  struct pjsip_history_entry *entry = NULL;
1221 
1222  if (cmd == CLI_INIT) {
1223  e->command = "pjsip show history";
1224  e->usage =
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"
1240  "\n"
1241  " When filtering, standard Boolean operators can be used,\n"
1242  " as well as 'like' for regexs.\n"
1243  "\n"
1244  " Example:\n"
1245  " 'pjsip show history where number > 5 and (addr = \"192.168.0.3:5060\" or addr = \"192.168.0.5:5060\")'\n";
1246  return NULL;
1247  } else if (cmd == CLI_GENERATE) {
1248  return NULL;
1249  }
1250 
1251  if (a->argc > 3) {
1252  if (!strcasecmp(a->argv[3], "entry") && a->argc == 5) {
1253  int num;
1254 
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]);
1257  return CLI_FAILURE;
1258  }
1259 
1260  /* Get the entry at the provided position */
1262  if (num >= AST_VECTOR_SIZE(&vector_history) || num < 0) {
1263  ast_cli(a->fd, "Entry '%d' does not exist\n", num);
1265  return CLI_FAILURE;
1266  }
1267  entry = ao2_bump(AST_VECTOR_GET(&vector_history, num));
1269  } else if (!strcasecmp(a->argv[3], "where")) {
1270  vec = filter_history(a);
1271  if (!vec) {
1272  return CLI_FAILURE;
1273  }
1274  } else {
1275  return CLI_SHOWUSAGE;
1276  }
1277  }
1278 
1279  if (AST_VECTOR_SIZE(vec) == 1) {
1280  if (vec == &vector_history) {
1282  }
1283  entry = ao2_bump(AST_VECTOR_GET(vec, 0));
1284  if (vec == &vector_history) {
1286  }
1287  }
1288 
1289  if (entry) {
1290  display_single_entry(a, entry);
1291  } else {
1292  if (vec == &vector_history) {
1294  }
1295 
1296  display_entry_list(a, vec);
1297 
1298  if (vec == &vector_history) {
1300  }
1301  }
1302 
1303  if (vec != &vector_history) {
1305  }
1306  ao2_cleanup(entry);
1307 
1308  return CLI_SUCCESS;
1309 }
1310 
1311 static char *pjsip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1312 {
1313  const char *what;
1314 
1315  if (cmd == CLI_INIT) {
1316  e->command = "pjsip set history {on|off|clear}";
1317  e->usage =
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";
1327  return NULL;
1328  } else if (cmd == CLI_GENERATE) {
1329  return NULL;
1330  }
1331 
1332  what = a->argv[e->args - 1]; /* Guaranteed to exist */
1333 
1334  if (a->argc == e->args) {
1335  if (!strcasecmp(what, "on")) {
1336  enabled = 1;
1337  ast_cli(a->fd, "PJSIP History enabled\n");
1338  return CLI_SUCCESS;
1339  } else if (!strcasecmp(what, "off")) {
1340  enabled = 0;
1341  ast_cli(a->fd, "PJSIP History disabled\n");
1342  return CLI_SUCCESS;
1343  } else if (!strcasecmp(what, "clear")) {
1345  ast_cli(a->fd, "PJSIP History cleared\n");
1346  return CLI_SUCCESS;
1347  }
1348  }
1349 
1350  return CLI_SHOWUSAGE;
1351 }
1352 
1353 static pjsip_module logging_module = {
1354  .name = { "History Module", 14 },
1355  .priority = 0,
1356  .on_rx_request = history_on_rx_msg,
1357  .on_rx_response = history_on_rx_msg,
1358  .on_tx_request = history_on_tx_msg,
1359  .on_tx_response = history_on_tx_msg,
1360 };
1361 
1362 static struct ast_cli_entry cli_pjsip[] = {
1363  AST_CLI_DEFINE(pjsip_set_history, "Enable/Disable PJSIP History"),
1364  AST_CLI_DEFINE(pjsip_show_history, "Display PJSIP History"),
1365 };
1366 
1367 static int load_module(void)
1368 {
1369  log_level = ast_logger_register_level("PJSIP_HISTORY");
1370  if (log_level < 0) {
1371  ast_log(LOG_WARNING, "Unable to register history log level\n");
1372  }
1373 
1374  ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
1375 
1376  AST_VECTOR_INIT(&vector_history, HISTORY_INITIAL_SIZE);
1377 
1379  ast_cli_register_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
1380 
1381  return AST_MODULE_LOAD_SUCCESS;
1382 }
1383 
1384 static int unload_module(void)
1385 {
1386  ast_cli_unregister_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
1388 
1390  AST_VECTOR_FREE(&vector_history);
1391 
1393 
1394  if (log_level != -1) {
1395  ast_logger_unregister_level("PJSIP_HISTORY");
1396  }
1397 
1398  return 0;
1399 }
1400 
1402  .support_level = AST_MODULE_SUPPORT_EXTENDED,
1403  .load = load_module,
1404  .unload = unload_module,
1405  .load_pri = AST_MODPRI_APP_DEPEND,
1406  .requires = "res_pjsip",
1407  );
Type for default handler for ast_sockaddrs.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
static const char type[]
Definition: chan_ooh323.c:109
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
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.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
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.
Definition: clicompat.c:30
static int evaluate_greater_than(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static struct allowed_field allowed_fields[]
The fields we allow.
#define APPEND_TO_OUTPUT(output, token)
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
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&#39;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.
Definition: vector.h:256
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.
Definition: cli.h:152
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.
int number
Packet number.
#define ast_log_dynamic_level(level,...)
Send a log message to a dynamically registered log level.
Definition: logger.h:439
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
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().
Definition: time.h:150
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:695
#define ast_mutex_lock(a)
Definition: lock.h:187
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.
Definition: res_pjsip.c:5240
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.
#define NULL
Definition: resample.c:96
static struct operator left_paren
Operator token for a left parenthesis.
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
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:5204
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&#39;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.
Definition: lock.h:755
int args
This gets set in ast_cli_register()
Definition: cli.h:185
static int log_level
Log level for history output.
#define ao2_bump(obj)
Definition: astobj2.h:491
Type for default option handler for character array strings.
static void * entry_get_timestamp(struct pjsip_history_entry *entry)
Callback to retrieve the entry&#39;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.
Definition: logger.c:2536
pj_sockaddr src
Source address.
#define ast_log
Definition: astobj2.c:42
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
Type for default option handler for unsigned integers.
const int fd
Definition: cli.h:159
static pjsip_module logging_module
#define ao2_ref(o, delta)
Definition: astobj2.h:464
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
Definition: astmm.h:300
enum aco_option_type return_type
The type /c get_field returns.
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
pjsip_msg * msg
The actual SIP message.
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:3315
int ast_logger_register_level(const char *name)
Register a new logger level.
Definition: logger.c:2503
Network socket handling.
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.
const char *const * argv
Definition: cli.h:161
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.
Definition: time.h:128
#define CLI_SHOWUSAGE
Definition: cli.h:45
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:5138
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 CLI_FAILURE
Definition: cli.h:46
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:627
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.
Definition: vector.h:189
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",)
const char * usage
Definition: cli.h:177
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)
#define CLI_SUCCESS
Definition: cli.h:44
static struct ast_cli_entry cli_pjsip[]
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
static void clear_history_entry_cb(struct pjsip_history_entry *entry)
Vector callback that releases the reference for the entry in a history vector.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Standard Command Line Interface.
static void * entry_get_addr(struct pjsip_history_entry *entry)
Callback to retrieve the entry&#39;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)
Definition: res_pjsip.c:3331
static PGresult * result
Definition: cel_pgsql.c:88
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.
Definition: search.h:40
int error(const char *format,...)
Definition: utils/frame.c:999
An item in the history.
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.
Definition: module.h:46
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition: vector.h:412
Asterisk module definitions.
static void * entry_get_sip_msg_call_id(struct pjsip_history_entry *entry)
Callback to retrieve the entry&#39;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.
Definition: vector.h:611
#define HISTORY_INITIAL_SIZE
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
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)
Definition: lock.h:188
static struct test_val a