Asterisk - The Open Source Telephony Project  21.4.1
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 <mjordan@digium.com>
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 <mjordan@digium.com>
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 \c vector_history */
77 AST_MUTEX_DEFINE_STATIC(history_lock);
78 
79 struct expression_token;
80 
81 /*! \brief An operator that we understand in an expression */
82 struct operator {
83  /*! \brief Our operator's symbol */
84  const char *symbol;
85  /*! \brief Precedence of the symbol */
87  /*! \brief Non-zero if the operator is evaluated right-to-left */
89  /*! \brief Number of operands the operator takes */
90  int operands;
91  /*!
92  * \brief Evaluation function for unary operators
93  *
94  * \param op The operator being evaluated
95  * \param type The type of value contained in \c operand
96  * \param operand A pointer to the value to evaluate
97  *
98  * \retval -1 error
99  * \retval 0 evaluation is False
100  * \retval 1 evaluation is True
101  */
102  int (* const evaluate_unary)(struct operator *op, enum aco_option_type type, void *operand);
103  /*!
104  * \brief Evaluation function for binary operators
105  *
106  * \param op The operator being evaluated
107  * \param type The type of value contained in \c op_left
108  * \param op_left A pointer to the value to evaluate (a result or extracted from an entry)
109  * \param op_right The expression token containing the other value (a result or user-provided)
110  *
111  * \retval -1 error
112  * \retval 0 evaluation is False
113  * \retval 1 evaluation is True
114  */
115  int (* const evaluate)(struct operator *op, enum aco_option_type type, void *op_left, struct expression_token *op_right);
116 };
117 
118 /*! \brief A field that we understand and can perform operations on */
120  /*! \brief The representation of the field */
121  const char *symbol;
122  /*! \brief The type /c get_field returns */
124  /*!
125  * \brief Function that returns the field from a pjsip_history_entry
126  *
127  * Note that the function must return a pointer to the location in
128  * \c pjsip_history_entry - no memory should be allocated as the caller
129  * will not dispose of any
130  */
131  void *(* const get_field)(struct pjsip_history_entry *entry);
132 };
133 
134 /*! \brief The type of token that has been parsed out of an expression */
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 };
143 
144 /*! \brief A token in the expression or an evaluated part of the expression */
146  /*! \brief The next expression token in the queue */
148  /*! \brief The type of value stored in the expression token */
150  /*! \brief An operator that evaluates expressions */
151  struct operator *op;
152  /*! \brief The result of an evaluated expression */
153  int result;
154  /*! \brief The field in the expression */
155  char field[];
156 };
157 
158 /*! \brief Log level for history output */
159 static int log_level = -1;
160 
161 /*! \brief The one and only history that we've captured */
162 static AST_VECTOR(vector_history_t, struct pjsip_history_entry *) vector_history;
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 ((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 }
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 ((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 }
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 ((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 }
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 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 
591  ast_assert(token->token_type == TOKEN_TYPE_FIELD);
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 
632  entry = ao2_alloc_options(sizeof(*entry), pjsip_history_entry_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
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], 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 }
692 
693 /*! \brief PJSIP callback when a SIP message is transmitted */
694 static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata)
695 {
696  struct pjsip_history_entry *entry;
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 
710  ast_mutex_lock(&history_lock);
711  if (AST_VECTOR_APPEND(&vector_history, entry)) {
712  ao2_ref(entry, -1);
713  entry = NULL;
714  }
715  ast_mutex_unlock(&history_lock);
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 }
726 
727 /*! \brief PJSIP callback when a SIP message is received */
728 static pj_bool_t history_on_rx_msg(pjsip_rx_data *rdata)
729 {
730  struct pjsip_history_entry *entry;
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 
753  ast_mutex_lock(&history_lock);
754  if (AST_VECTOR_APPEND(&vector_history, entry)) {
755  ao2_ref(entry, -1);
756  entry = NULL;
757  }
758  ast_mutex_unlock(&history_lock);
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 }
769 
770 /*! \brief Vector callback that releases the reference for the entry in a history vector */
772 {
773  ao2_ref(entry, -1);
774 }
775 
776 /*!
777  * \brief Remove all entries from \c vector_history
778  *
779  * This must be called from a registered PJSIP thread
780  */
781 static int clear_history_entries(void *obj)
782 {
783  ast_mutex_lock(&history_lock);
784  AST_VECTOR_RESET(&vector_history, clear_history_entry_cb);
785  packet_number = 0;
786  ast_mutex_unlock(&history_lock);
787 
788  return 0;
789 }
790 
791 /*!
792  * \brief Build a reverse polish notation expression queue
793  *
794  * This function is an implementation of the Shunting-Yard Algorithm. It takes
795  * a user provided infix-notation expression and converts it into a reverse
796  * polish notation expression, which is a queue of tokens that can be easily
797  * parsed.
798  *
799  * \param a The CLI arguments provided by the User, containing the infix expression
800  *
801  * \retval NULL error
802  * \retval expression_token A 'queue' of expression tokens in RPN
803  */
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  */
853  if ((allowed_operators[j].right_to_left && allowed_operators[j].precedence >= top->precedence)
854  || (!allowed_operators[j].right_to_left && allowed_operators[j].precedence > top->precedence)) {
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 
935 error:
936  AST_VECTOR_FREE(&operators);
937  expression_token_free(output);
938  return NULL;
939 }
940 
941 /*!
942  * \brief Evaluate a single entry in this history using a RPN expression
943  *
944  * \param entry The entry in the history to evaluate
945  * \param queue The RPN expression
946  *
947  * \retval 0 The expression evaluated FALSE on \c entry
948  * \retval 1 The expression evaluated TRUE on \c entry
949  * \retval -1 The expression errored
950  */
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;
999  enum aco_option_type type;
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 */
1045  result = expression_token_alloc(TOKEN_TYPE_RESULT, &res);
1046  if (!result) {
1047  goto error;
1048  }
1049  if (AST_VECTOR_APPEND(&stack, result)) {
1050  expression_token_free(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 
1078 error:
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 }
1090 
1091 /*!
1092  * \brief Create a filtered history based on a user provided expression
1093  *
1094  * \param a The CLI arguments containing the expression
1095  *
1096  * \retval NULL on error
1097  * \retval A vector containing the filtered history on success
1098  */
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 
1121  ast_mutex_lock(&history_lock);
1122  for (i = 0; i < AST_VECTOR_SIZE(&vector_history); i++) {
1123  struct pjsip_history_entry *entry = AST_VECTOR_GET(&vector_history, i);
1124  int res;
1125 
1126  res = evaluate_history_entry(entry, queue);
1127  if (res == -1) {
1128  /* Error in expression evaluation; bail */
1129  ast_mutex_unlock(&history_lock);
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)) {
1140  ao2_cleanup(entry);
1141  }
1142  }
1143  }
1144  ast_mutex_unlock(&history_lock);
1145 
1146  expression_token_free(queue);
1147 
1148  return output;
1149 }
1150 
1151 /*! \brief Print a detailed view of a single entry in the history to the CLI */
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 }
1184 
1185 /*! \brief Print a list of the entries to the CLI */
1186 static void display_entry_list(struct ast_cli_args *a, struct vector_history_t *vec)
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 }
1207 
1208 /*! \brief Cleanup routine for a history vector, serviced on a registered PJSIP thread */
1209 static int safe_vector_cleanup(void *obj)
1210 {
1211  struct vector_history_t *vec = obj;
1212 
1214  AST_VECTOR_FREE(vec);
1215  ast_free(vec);
1216 
1217  return 0;
1218 }
1219 
1220 static char *pjsip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 */
1264  ast_mutex_lock(&history_lock);
1265  if (num >= AST_VECTOR_SIZE(&vector_history) || num < 0) {
1266  ast_cli(a->fd, "Entry '%d' does not exist\n", num);
1267  ast_mutex_unlock(&history_lock);
1268  return CLI_FAILURE;
1269  }
1270  entry = ao2_bump(AST_VECTOR_GET(&vector_history, num));
1271  ast_mutex_unlock(&history_lock);
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) {
1284  ast_mutex_lock(&history_lock);
1285  }
1286  entry = ao2_bump(AST_VECTOR_GET(vec, 0));
1287  if (vec == &vector_history) {
1288  ast_mutex_unlock(&history_lock);
1289  }
1290  }
1291 
1292  if (entry) {
1293  display_single_entry(a, entry);
1294  } else {
1295  if (vec == &vector_history) {
1296  ast_mutex_lock(&history_lock);
1297  }
1298 
1299  display_entry_list(a, vec);
1300 
1301  if (vec == &vector_history) {
1302  ast_mutex_unlock(&history_lock);
1303  }
1304  }
1305 
1306  if (vec != &vector_history) {
1308  }
1309  ao2_cleanup(entry);
1310 
1311  return CLI_SUCCESS;
1312 }
1313 
1314 static char *pjsip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 }
1355 
1356 static pjsip_module logging_module = {
1357  .name = { "History Module", 14 },
1358  .priority = 0,
1359  .on_rx_request = history_on_rx_msg,
1360  .on_rx_response = history_on_rx_msg,
1361  .on_tx_request = history_on_tx_msg,
1362  .on_tx_response = history_on_tx_msg,
1363 };
1364 
1365 static struct ast_cli_entry cli_pjsip[] = {
1366  AST_CLI_DEFINE(pjsip_set_history, "Enable/Disable PJSIP History"),
1367  AST_CLI_DEFINE(pjsip_show_history, "Display PJSIP History"),
1368 };
1369 
1370 static int load_module(void)
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 
1379  AST_VECTOR_INIT(&vector_history, HISTORY_INITIAL_SIZE);
1380 
1381  ast_sip_register_service(&logging_module);
1382  ast_cli_register_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
1383 
1384  return AST_MODULE_LOAD_SUCCESS;
1385 }
1386 
1387 static int unload_module(void)
1388 {
1389  ast_cli_unregister_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
1390  ast_sip_unregister_service(&logging_module);
1391 
1393  AST_VECTOR_FREE(&vector_history);
1394 
1396 
1397  if (log_level != -1) {
1398  ast_logger_unregister_level("PJSIP_HISTORY");
1399  }
1400 
1401  return 0;
1402 }
1403 
1404 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP History",
1405  .support_level = AST_MODULE_SUPPORT_EXTENDED,
1406  .load = load_module,
1407  .unload = unload_module,
1408  .load_pri = AST_MODPRI_APP_DEPEND,
1409  .requires = "res_pjsip",
1410  );
Type for default handler for ast_sockaddrs.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
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
static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expression_token *queue)
Evaluate a single entry in this history using a RPN expression.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int right_to_left
Non-zero if the operator is evaluated right-to-left.
static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int len)
Format single line history entry.
static int evaluate_and(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining logical AND.
static int packet_number
Packet count.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch. Returns -1 on failure, zero otherwise.
Definition: time.c:152
static int evaluate_greater_than(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining if one operand is greater than another.
static struct allowed_field allowed_fields[]
The fields we allow.
descriptor for a cli entry.
Definition: cli.h:171
char field[]
The field in the expression.
static int clear_history_entries(void *obj)
Remove all entries from vector_history.
expression_token_type
The type of token that has been parsed out of an expression.
#define ast_log_dynamic_level(level,...)
Send a log message to a dynamically registered log level.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
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)
Operator callback for regex 'like'.
pj_sockaddr dst
Destination address.
Type for a default handler that should do nothing.
void *(*const get_field)(struct pjsip_history_entry *entry)
Function that returns the field from a pjsip_history_entry.
int number
Packet number.
void ast_logger_unregister_level(const char *name)
Unregister a previously registered logger level.
Definition: logger.c:2909
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
An operator that we understand in an expression.
static int evaluate_less_than(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining if one operand is less than another.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag...
static int evaluate_less_than_or_equal(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining if one operand is less than or equal to another.
struct timeval timestamp
Time the packet was transmitted/received.
static struct operator allowed_operators[]
Our allowed operations.
static struct operator left_paren
Operator token for a left parenthesis.
The one and only history that we've captured.
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:2165
struct operator* op
An operator that evaluates expressions.
static void * entry_get_sip_msg_request_method(struct pjsip_history_entry *entry)
Callback to retrieve the entry's SIP request method type.
static int evaluate_not(struct operator*op, enum aco_option_type type, void *operand)
Operator callback for determining logical NOT.
void ast_pjproject_caching_pool_init(pj_caching_pool *cp, const pj_pool_factory_policy *policy, pj_size_t max_capacity)
Initialize the caching pool factory.
static int evaluate_not_equal(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining inequality.
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
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)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
Type for default option handler for character array strings.
static void * entry_get_timestamp(struct pjsip_history_entry *entry)
Callback to retrieve the entry's timestamp.
enum expression_token_type token_type
The type of value stored in the expression token.
A field that we understand and can perform operations on.
pj_sockaddr src
Source address.
int precedence
Precedence of the symbol.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
Type for default option handler for unsigned integers.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
int operands
Number of operands the operator takes.
const char * symbol
The representation of the field.
int(*const evaluate_unary)(struct operator*op, enum aco_option_type type, void *operand)
Evaluation function for unary operators.
static struct vector_history_t * filter_history(struct ast_cli_args *a)
Create a filtered history based on a user provided expression.
enum aco_option_type return_type
The type /c get_field returns.
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
pjsip_msg * msg
The actual SIP message.
Network socket handling.
aco_option_type
The option types.
int result
The result of an evaluated expression.
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
Definition: time.h:137
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 struct allowed_field * get_allowed_field(struct expression_token *token)
Determine if the expression token matches a field in allowed_fields.
Type for default option handler for bools (ast_true/ast_false)
static int evaluate_greater_than_or_equal(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Operator callback for determining if one operand is greater than or equal to another.
static struct expression_token * expression_token_free(struct expression_token *token)
Free an expression token and all others it references.
void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
Destroy caching pool factory and all cached pools.
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625
Type for default option handler for doubles.
static void display_entry_list(struct ast_cli_args *a, struct vector_history_t *vec)
Print a list of the entries to the CLI.
Support for logging to various files, console and syslog Configuration in file logger.conf.
Vector container support.
pj_pool_t * pool
Memory pool used to allocate msg.
static struct pjsip_history_entry * pjsip_history_entry_alloc(pjsip_msg *msg)
Create a pjsip_history_entry AO2 object.
#define AST_VECTOR_PTR_FREE(vec)
Deallocates this vector pointer.
Definition: vector.h:189
A token in the expression or an evaluated part of the expression.
int(*const evaluate)(struct operator*op, enum aco_option_type type, void *op_left, struct expression_token *op_right)
Evaluation function for binary operators.
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)
Operator callback for determining logical OR.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
int ast_logger_register_level(const char *name)
Register a new logger level.
Definition: logger.c:2851
static void clear_history_entry_cb(struct pjsip_history_entry *entry)
Vector callback that releases the reference for the entry in a history vector.
Standard Command Line Interface.
static void * entry_get_addr(struct pjsip_history_entry *entry)
Callback to retrieve the entry's destination address.
static int enabled
Whether or not we are storing history.
static int safe_vector_cleanup(void *obj)
Cleanup routine for a history vector, serviced on a registered PJSIP thread.
static void display_single_entry(struct ast_cli_args *a, struct pjsip_history_entry *entry)
Print a detailed view of a single entry in the history to the CLI.
Type for default option handler for stringfields.
const char * symbol
Our operator's symbol.
Definition: search.h:40
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.
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's SIP Call-ID header.
static struct expression_token * build_expression_queue(struct ast_cli_args *a)
Build a reverse polish notation expression queue.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
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.