Wed Jan 8 2020 09:49:49

Asterisk developer's documentation


pbx_realtime.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@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 /*! \file
20  *
21  * \brief Realtime PBX Module
22  *
23  * \arg See also: \ref AstARA
24  */
25 
26 /*** MODULEINFO
27  <support_level>extended</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370642 $")
33 
34 #include <signal.h>
35 
36 #include "asterisk/file.h"
37 #include "asterisk/logger.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/config.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/module.h"
42 #include "asterisk/frame.h"
43 #include "asterisk/term.h"
44 #include "asterisk/manager.h"
45 #include "asterisk/cli.h"
46 #include "asterisk/lock.h"
47 #include "asterisk/linkedlists.h"
48 #include "asterisk/chanvars.h"
49 #include "asterisk/sched.h"
50 #include "asterisk/io.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/astdb.h"
53 #include "asterisk/app.h"
54 #include "asterisk/astobj2.h"
55 
56 #define MODE_MATCH 0
57 #define MODE_MATCHMORE 1
58 #define MODE_CANMATCH 2
59 
60 #define EXT_DATA_SIZE 256
61 
64 };
65 
68 });
69 
70 struct cache_entry {
71  struct timeval when;
72  struct ast_variable *var;
73  int priority;
74  char *context;
75  char exten[2];
76 };
77 
79 pthread_t cleanup_thread = 0;
80 
81 static int cache_hash(const void *obj, const int flags)
82 {
83  const struct cache_entry *e = obj;
84  return ast_str_case_hash(e->exten) + e->priority;
85 }
86 
87 static int cache_cmp(void *obj, void *arg, int flags)
88 {
89  struct cache_entry *e = obj, *f = arg;
90  return e->priority != f->priority ? 0 :
91  strcmp(e->exten, f->exten) ? 0 :
92  strcmp(e->context, f->context) ? 0 :
93  CMP_MATCH;
94 }
95 
96 static struct ast_variable *dup_vars(struct ast_variable *v)
97 {
98  struct ast_variable *new, *list = NULL;
99  for (; v; v = v->next) {
100  if (!(new = ast_variable_new(v->name, v->value, v->file))) {
101  ast_variables_destroy(list);
102  return NULL;
103  }
104  /* Reversed list in cache, but when we duplicate out of the cache,
105  * it's back to correct order. */
106  new->next = list;
107  list = new;
108  }
109  return list;
110 }
111 
112 static void free_entry(void *obj)
113 {
114  struct cache_entry *e = obj;
116 }
117 
118 static int purge_old_fn(void *obj, void *arg, int flags)
119 {
120  struct cache_entry *e = obj;
121  struct timeval *now = arg;
122  return ast_tvdiff_ms(*now, e->when) >= 1000 ? CMP_MATCH : 0;
123 }
124 
125 static void *cleanup(void *unused)
126 {
127  struct timespec forever = { 999999999, 0 }, one_second = { 1, 0 };
128  struct timeval now;
129 
130  for (;;) {
131  pthread_testcancel();
132  if (ao2_container_count(cache) == 0) {
133  nanosleep(&forever, NULL);
134  }
135  pthread_testcancel();
136  now = ast_tvnow();
138  pthread_testcancel();
139  nanosleep(&one_second, NULL);
140  }
141 
142  return NULL;
143 }
144 
145 
146 /* Realtime switch looks up extensions in the supplied realtime table.
147 
148  [context@][realtimetable][/options]
149 
150  If the realtimetable is omitted it is assumed to be "extensions". If no context is
151  specified the context is assumed to be whatever is the container.
152 
153  The realtime table should have entries for context,exten,priority,app,args
154 
155  The realtime table currently does not support callerid fields.
156 
157 */
158 
159 
160 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode, struct ast_flags flags)
161 {
162  struct ast_variable *var;
163  struct ast_config *cfg;
164  char pri[20];
165  char *ematch;
166  char rexten[AST_MAX_EXTENSION + 20]="";
167  int match;
168  /* Optimization: since we don't support hints in realtime, it's silly to
169  * query for a hint here, since we won't actually do anything with it.
170  * This just wastes CPU time and resources. */
171  if (priority < 0) {
172  return NULL;
173  }
174  snprintf(pri, sizeof(pri), "%d", priority);
175  switch(mode) {
176  case MODE_MATCHMORE:
177  ematch = "exten LIKE";
178  snprintf(rexten, sizeof(rexten), "%s_%%", exten);
179  break;
180  case MODE_CANMATCH:
181  ematch = "exten LIKE";
182  snprintf(rexten, sizeof(rexten), "%s%%", exten);
183  break;
184  case MODE_MATCH:
185  default:
186  ematch = "exten";
187  ast_copy_string(rexten, exten, sizeof(rexten));
188  }
189  var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, SENTINEL);
190  if (!var && !ast_test_flag(&flags, OPTION_PATTERNS_DISABLED)) {
191  cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, SENTINEL);
192  if (cfg) {
193  char *cat = ast_category_browse(cfg, NULL);
194 
195  while(cat) {
196  switch(mode) {
197  case MODE_MATCHMORE:
198  match = ast_extension_close(cat, exten, 1);
199  break;
200  case MODE_CANMATCH:
201  match = ast_extension_close(cat, exten, 0);
202  break;
203  case MODE_MATCH:
204  default:
205  match = ast_extension_match(cat, exten);
206  }
207  if (match) {
209  break;
210  }
211  cat = ast_category_browse(cfg, cat);
212  }
213  ast_config_destroy(cfg);
214  }
215  }
216  return var;
217 }
218 
219 static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
220 {
221  const char *ctx = NULL;
222  char *table;
223  struct ast_variable *var=NULL;
224  struct ast_flags flags = { 0, };
225  struct cache_entry *ce;
226  struct {
227  struct cache_entry ce;
228  char exten[AST_MAX_EXTENSION];
229  } cache_search = { { .priority = priority, .context = (char *) context }, };
230  char *buf = ast_strdupa(data);
231  /* "Realtime" prefix is stripped off in the parent engine. The
232  * remaining string is: [[context@]table][/opts] */
233  char *opts = strchr(buf, '/');
234  if (opts)
235  *opts++ = '\0';
236  table = strchr(buf, '@');
237  if (table) {
238  *table++ = '\0';
239  ctx = buf;
240  }
241  ctx = S_OR(ctx, context);
242  table = S_OR(table, "extensions");
243  if (!ast_strlen_zero(opts)) {
244  ast_app_parse_options(switch_opts, &flags, NULL, opts);
245  }
246  ast_copy_string(cache_search.exten, exten, sizeof(cache_search.exten));
247  if (mode == MODE_MATCH && (ce = ao2_find(cache, &cache_search, OBJ_POINTER))) {
248  var = dup_vars(ce->var);
249  ao2_ref(ce, -1);
250  } else {
251  var = realtime_switch_common(table, ctx, exten, priority, mode, flags);
252  do {
253  struct ast_variable *new;
254  /* Only cache matches */
255  if (mode != MODE_MATCH) {
256  break;
257  }
258  if (!(new = dup_vars(var))) {
259  break;
260  }
261  if (!(ce = ao2_alloc(sizeof(*ce) + strlen(exten) + strlen(context), free_entry))) {
263  break;
264  }
265  ce->context = ce->exten + strlen(exten) + 1;
266  strcpy(ce->exten, exten); /* SAFE */
267  strcpy(ce->context, context); /* SAFE */
268  ce->priority = priority;
269  ce->var = new;
270  ce->when = ast_tvnow();
271  ao2_link(cache, ce);
272  pthread_kill(cleanup_thread, SIGURG);
273  ao2_ref(ce, -1);
274  } while (0);
275  }
276  return var;
277 }
278 
279 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
280 {
281  struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
282  if (var) {
284  return 1;
285  }
286  return 0;
287 }
288 
289 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
290 {
291  struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
292  if (var) {
294  return 1;
295  }
296  return 0;
297 }
298 
299 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
300 {
301  int res = -1;
302  struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
303 
304  if (var) {
305  char *tmp="";
306  char *app = NULL;
307  struct ast_variable *v;
308 
309  for (v = var; v ; v = v->next) {
310  if (!strcasecmp(v->name, "app"))
311  app = ast_strdupa(v->value);
312  else if (!strcasecmp(v->name, "appdata")) {
314  char *ptr;
315  int in = 0;
316  tmp = ast_alloca(strlen(v->value) * 2 + 1);
317  for (ptr = tmp; *v->value; v->value++) {
318  if (*v->value == ',') {
319  *ptr++ = '\\';
320  *ptr++ = ',';
321  } else if (*v->value == '|' && !in) {
322  *ptr++ = ',';
323  } else {
324  *ptr++ = *v->value;
325  }
326 
327  /* Don't escape '|', meaning 'or', inside expressions ($[ ]) */
328  if (v->value[0] == '[' && v->value[-1] == '$') {
329  in++;
330  } else if (v->value[0] == ']' && in) {
331  in--;
332  }
333  }
334  *ptr = '\0';
335  } else {
336  tmp = ast_strdupa(v->value);
337  }
338  }
339  }
341  if (!ast_strlen_zero(app)) {
342  struct ast_app *a = pbx_findapp(app);
343  if (a) {
344  char appdata[512];
345  char tmp1[80];
346  char tmp2[80];
347  char tmp3[EXT_DATA_SIZE];
348 
349  appdata[0] = 0; /* just in case the substitute var func isn't called */
350  if(!ast_strlen_zero(tmp))
351  pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
352  ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
353  chan->exten, chan->context, chan->priority,
354  term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
355  term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
356  term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
358  "Channel: %s\r\n"
359  "Context: %s\r\n"
360  "Extension: %s\r\n"
361  "Priority: %d\r\n"
362  "Application: %s\r\n"
363  "AppData: %s\r\n"
364  "Uniqueid: %s\r\n",
365  chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid);
366 
367  res = pbx_exec(chan, a, appdata);
368  } else
369  ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
370  } else {
371  ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
372  }
373  }
374  return res;
375 }
376 
377 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
378 {
379  struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
380  if (var) {
382  return 1;
383  }
384  return 0;
385 }
386 
388 {
389  .name = "Realtime",
390  .description = "Realtime Dialplan Switch",
391  .exists = realtime_exists,
392  .canmatch = realtime_canmatch,
393  .exec = realtime_exec,
394  .matchmore = realtime_matchmore,
395 };
396 
397 static int unload_module(void)
398 {
399  ast_unregister_switch(&realtime_switch);
400  pthread_cancel(cleanup_thread);
401  pthread_kill(cleanup_thread, SIGURG);
402  pthread_join(cleanup_thread, NULL);
403  /* Destroy all remaining entries */
404  ao2_ref(cache, -1);
405  return 0;
406 }
407 
408 static int load_module(void)
409 {
410  if (!(cache = ao2_container_alloc(573, cache_hash, cache_cmp))) {
412  }
413 
414  if (ast_pthread_create(&cleanup_thread, NULL, cleanup, NULL)) {
416  }
417 
418  if (ast_register_switch(&realtime_switch))
421 }
422 
static int cache_cmp(void *obj, void *arg, int flags)
Definition: pbx_realtime.c:87
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: pbx.c:4676
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Definition: astobj2.c:470
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
Definition: app.h:712
int priority
Definition: pbx_realtime.c:73
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: pbx.c:1537
int priority
Definition: channel.h:841
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx.c:1497
const ast_string_field uniqueid
Definition: channel.h:787
struct timeval when
Definition: pbx_realtime.c:71
struct ast_variable * ast_category_detach_variables(struct ast_category *cat)
Definition: config.c:856
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
#define ast_test_flag(p, flag)
Definition: utils.h:63
Channel Variables.
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
#define LOG_WARNING
Definition: logger.h:144
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:910
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: app.c:2101
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
static struct ast_variable * dup_vars(struct ast_variable *v)
Definition: pbx_realtime.c:96
static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
Definition: pbx_realtime.c:279
Configuration File Parser.
void ast_unregister_switch(struct ast_switch *sw)
Unregister an alternative switch.
Definition: pbx.c:6457
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: config.c:2548
static struct ast_variable * realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode, struct ast_flags flags)
Definition: pbx_realtime.c:160
Definition: pbx_realtime.c:70
static int cache_hash(const void *obj, const int flags)
Definition: pbx_realtime.c:81
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: config.c:586
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
I/O Management (derived from Cheops-NG)
static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
Definition: pbx_realtime.c:289
#define EVENT_FLAG_DIALPLAN
Definition: manager.h:82
#define ast_verb(level,...)
Definition: logger.h:243
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
pthread_t cleanup_thread
Definition: pbx_realtime.c:79
#define COLOR_BRCYAN
Definition: term.h:60
Utility functions.
static int purge_old_fn(void *obj, void *arg, int flags)
Definition: pbx_realtime.c:118
static int load_module(void)
Definition: pbx_realtime.c:408
static char * table
Definition: cdr_odbc.c:50
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name)
Retrieve a category if it exists.
Definition: config.c:709
#define SENTINEL
Definition: compiler.h:75
const char * name
Definition: pbx.h:130
const char * value
Definition: config.h:79
static int unload_module(void)
Definition: pbx_realtime.c:397
static const char app[]
Definition: app_adsiprog.c:49
General Asterisk PBX channel definitions.
#define MODE_CANMATCH
Definition: pbx_realtime.c:58
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
Asterisk internal frame definitions.
#define AST_MAX_EXTENSION
Definition: channel.h:135
Scheduler Routines (derived from cheops)
#define ao2_ref(o, delta)
Definition: astobj2.h:472
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#define ast_compat_pbx_realtime
Definition: options.h:142
static struct ast_app_option switch_opts[128]
Definition: pbx_realtime.c:68
A set of macros to manage forward-linked lists.
const char * name
Definition: config.h:77
Core PBX routines and definitions.
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Definition: term.c:184
#define COLOR_BRMAGENTA
Definition: term.h:58
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
const char * file
Definition: config.h:85
char exten[2]
Definition: pbx_realtime.c:75
static struct ast_variable * realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
Definition: pbx_realtime.c:219
struct ast_variable * var
Definition: pbx_realtime.c:72
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
#define LOG_NOTICE
Definition: logger.h:133
#define MODE_MATCH
Definition: pbx_realtime.c:56
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:418
int ast_register_switch(struct ast_switch *sw)
Register an alternative dialplan switch.
Definition: pbx.c:6439
static struct ast_format f[]
Definition: format_g726.c:181
int ast_extension_close(const char *pattern, const char *data, int needmore)
Definition: pbx.c:2948
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
Definition: pbx.c:2943
static void free_entry(void *obj)
Definition: pbx_realtime.c:112
static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
Definition: pbx_realtime.c:299
static void * cleanup(void *unused)
Definition: pbx_realtime.c:125
Structure used to handle boolean flags.
Definition: utils.h:200
Support for logging to various files, console and syslog Configuration in file logger.conf.
struct ao2_container * cache
Definition: pbx_realtime.c:78
#define EXT_DATA_SIZE
Definition: pbx_realtime.c:60
#define MODE_MATCHMORE
Definition: pbx_realtime.c:57
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define ao2_container_alloc(arg1, arg2, arg3)
Definition: astobj2.h:734
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
ast_app: A registered application
Definition: pbx.c:971
option_flags
Definition: app_skel.c:78
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
Handy terminal functions for vt* terms.
struct ast_variable * next
Definition: config.h:82
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:219
Asterisk module definitions.
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2069
Persistant data storage (akin to *doze registry)
char exten[AST_MAX_EXTENSION]
Definition: channel.h:869
static struct ast_switch realtime_switch
Definition: pbx_realtime.c:387
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: config.c:278
char * context
Definition: pbx_realtime.c:74
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:989
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
Definition: pbx_realtime.c:377
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: config.c:2650
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
Definition: app.h:721