Asterisk - The Open Source Telephony Project GIT-master-a358458
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#include <signal.h>
33
34#include "asterisk/file.h"
35#include "asterisk/logger.h"
36#include "asterisk/channel.h"
37#include "asterisk/config.h"
38#include "asterisk/pbx.h"
39#include "asterisk/module.h"
40#include "asterisk/frame.h"
41#include "asterisk/term.h"
42#include "asterisk/manager.h"
43#include "asterisk/cli.h"
44#include "asterisk/lock.h"
46#include "asterisk/chanvars.h"
47#include "asterisk/sched.h"
48#include "asterisk/io.h"
49#include "asterisk/utils.h"
50#include "asterisk/astdb.h"
51#include "asterisk/app.h"
52#include "asterisk/astobj2.h"
54
55#define MODE_MATCH 0
56#define MODE_MATCHMORE 1
57#define MODE_CANMATCH 2
58
59#define EXT_DATA_SIZE 256
60
63};
64
67});
68
70 struct timeval when;
73 char *context;
74 char exten[2];
75};
76
78pthread_t cleanup_thread = 0;
79
80static int cache_hash(const void *obj, const int flags)
81{
82 const struct cache_entry *e = obj;
83 return ast_str_case_hash(e->exten) + e->priority;
84}
85
86static int cache_cmp(void *obj, void *arg, int flags)
87{
88 struct cache_entry *e = obj, *f = arg;
89 return e->priority != f->priority ? 0 :
90 strcmp(e->exten, f->exten) ? 0 :
91 strcmp(e->context, f->context) ? 0 :
93}
94
95static struct ast_variable *dup_vars(struct ast_variable *v)
96{
97 struct ast_variable *new, *list = NULL;
98 for (; v; v = v->next) {
99 if (!(new = ast_variable_new(v->name, v->value, v->file))) {
101 return NULL;
102 }
103 /* Reversed list in cache, but when we duplicate out of the cache,
104 * it's back to correct order. */
105 new->next = list;
106 list = new;
107 }
108 return list;
109}
110
111static void free_entry(void *obj)
112{
113 struct cache_entry *e = obj;
115}
116
117static int purge_old_fn(void *obj, void *arg, int flags)
118{
119 struct cache_entry *e = obj;
120 struct timeval *now = arg;
121 return ast_tvdiff_ms(*now, e->when) >= 1000 ? CMP_MATCH : 0;
122}
123
124static void *cleanup(void *unused)
125{
126 struct timespec forever = { 999999999, 0 }, one_second = { 1, 0 };
127 struct timeval now;
128
129 for (;;) {
130 pthread_testcancel();
131 if (ao2_container_count(cache) == 0) {
132 nanosleep(&forever, NULL);
133 }
134 pthread_testcancel();
135 now = ast_tvnow();
137 pthread_testcancel();
138 nanosleep(&one_second, NULL);
139 }
140
141 return NULL;
142}
143
145{
146 const char *extenp = S_OR(ast_variable_find(p, "exten"), "");
147 const char *extenq = S_OR(ast_variable_find(q, "exten"), "");
148
149 return strlen(extenp) - strlen(extenq);
150}
151
152/* Realtime switch looks up extensions in the supplied realtime table.
153
154 [context@][realtimetable][/options]
155
156 If the realtimetable is omitted it is assumed to be "extensions". If no context is
157 specified the context is assumed to be whatever is the container.
158
159 The realtime table should have entries for context,exten,priority,app,args
160
161 The realtime table currently does not support callerid fields.
162
163*/
164
165
166static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode, struct ast_flags flags)
167{
168 struct ast_variable *var;
169 struct ast_config *cfg;
170 char pri[20];
171 char *ematch;
172 char rexten[AST_MAX_EXTENSION + 20]="";
173 int match;
174 /* Optimization: since we don't support hints in realtime, it's silly to
175 * query for a hint here, since we won't actually do anything with it.
176 * This just wastes CPU time and resources. */
177 if (priority < 0) {
178 return NULL;
179 }
180 snprintf(pri, sizeof(pri), "%d", priority);
181 switch(mode) {
182 case MODE_MATCHMORE:
183 ematch = "exten LIKE";
184 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
185 break;
186 case MODE_CANMATCH:
187 ematch = "exten LIKE";
188 snprintf(rexten, sizeof(rexten), "%s%%", exten);
189 break;
190 case MODE_MATCH:
191 default:
192 ematch = "exten";
193 ast_copy_string(rexten, exten, sizeof(rexten));
194 }
195 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, SENTINEL);
196 if (!var && !ast_test_flag(&flags, OPTION_PATTERNS_DISABLED)) {
197 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, SENTINEL);
198 if (cfg) {
199 char *cat = NULL;
200
201 /* Sort so that longer patterns are checked first */
203
204 while ((cat = ast_category_browse(cfg, cat))) {
205 const char *realtime_exten = ast_variable_retrieve(cfg, cat, "exten");
206
207 switch(mode) {
208 case MODE_MATCHMORE:
209 match = ast_extension_close(realtime_exten, exten, 1);
210 break;
211 case MODE_CANMATCH:
212 match = ast_extension_close(realtime_exten, exten, 0);
213 break;
214 case MODE_MATCH:
215 default:
216 match = ast_extension_match(realtime_exten, exten);
217 }
218 if (match) {
220 break;
221 }
222 }
224 }
225 }
226 return var;
227}
228
229static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
230{
231 const char *ctx = NULL;
232 char *table;
233 struct ast_variable *var=NULL;
234 struct ast_flags flags = { 0, };
235 struct cache_entry *ce;
236 struct {
237 struct cache_entry ce;
239 } cache_search = { { .priority = priority, .context = (char *) context }, };
240 char *buf = ast_strdupa(data);
241 /* "Realtime" prefix is stripped off in the parent engine. The
242 * remaining string is: [[context@]table][/opts] */
243 char *opts = strchr(buf, '/');
244 if (opts)
245 *opts++ = '\0';
246 table = strchr(buf, '@');
247 if (table) {
248 *table++ = '\0';
249 ctx = buf;
250 }
251 ctx = S_OR(ctx, context);
252 table = S_OR(table, "extensions");
253 if (!ast_strlen_zero(opts)) {
254 ast_app_parse_options(switch_opts, &flags, NULL, opts);
255 }
256 ast_copy_string(cache_search.exten, exten, sizeof(cache_search.exten));
257 if (mode == MODE_MATCH && (ce = ao2_find(cache, &cache_search, OBJ_POINTER))) {
258 var = dup_vars(ce->var);
259 ao2_ref(ce, -1);
260 } else {
261 var = realtime_switch_common(table, ctx, exten, priority, mode, flags);
262 do {
263 struct ast_variable *new;
264 /* Only cache matches */
265 if (mode != MODE_MATCH) {
266 break;
267 }
268 if (!(new = dup_vars(var))) {
269 break;
270 }
271 if (!(ce = ao2_alloc(sizeof(*ce) + strlen(exten) + strlen(context), free_entry))) {
273 break;
274 }
275 ce->context = ce->exten + strlen(exten) + 1;
276 strcpy(ce->exten, exten); /* SAFE */
277 strcpy(ce->context, context); /* SAFE */
278 ce->priority = priority;
279 ce->var = new;
280 ce->when = ast_tvnow();
281 ao2_link(cache, ce);
282 pthread_kill(cleanup_thread, SIGURG);
283 ao2_ref(ce, -1);
284 } while (0);
285 }
286 return var;
287}
288
289static int realtime_exists(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_MATCH);
292 if (var) {
294 return 1;
295 }
296 return 0;
297}
298
299static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
300{
302 if (var) {
304 return 1;
305 }
306 return 0;
307}
308
309static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
310{
311 int res = -1;
312 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
313
314 if (var) {
315 char *appdata_tmp = "";
316 char *app = NULL;
317 struct ast_variable *v;
318
319 for (v = var; v ; v = v->next) {
320 if (!strcasecmp(v->name, "app"))
321 app = ast_strdupa(v->value);
322 else if (!strcasecmp(v->name, "appdata")) {
323 appdata_tmp = ast_strdupa(v->value);
324 }
325 }
327 if (!ast_strlen_zero(app)) {
328 struct ast_app *a = pbx_findapp(app);
329 if (a) {
330 char appdata[512];
331 char tmp1[80];
332 char tmp2[80];
333 char tmp3[EXT_DATA_SIZE];
334
335 appdata[0] = 0; /* just in case the substitute var func isn't called */
336 if(!ast_strlen_zero(appdata_tmp))
337 pbx_substitute_variables_helper(chan, appdata_tmp, appdata, sizeof(appdata) - 1);
338 ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
340 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
341 term_color(tmp2, ast_channel_name(chan), COLOR_BRMAGENTA, 0, sizeof(tmp2)),
342 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
344 char *tmp_appl;
345 char *tmp_data;
346
347 ast_channel_lock(chan);
348 /* Force a new dialplan segment that will be unique to use so we can update it with the
349 * information we want. In the future when a channel snapshot is published this will
350 * occur again and unset this flag.
351 */
353
354 /* pbx_exec sets application name and data, but we don't want to log
355 * every exec. Just update the snapshot here instead. Publishing the
356 * snapshot retrieves data from the channel object directly, so save
357 * current values prior to publishing so they can be restored after.
358 */
359 tmp_appl = ast_channel_appl(chan) ? ast_strdupa(ast_channel_appl(chan)) : NULL;
360 tmp_data = ast_channel_data(chan) ? ast_strdupa(ast_channel_data(chan)) : NULL;
361
363 ast_channel_data_set(chan, !ast_strlen_zero(appdata) ? appdata : "(NULL)");
364
366
367 ast_channel_appl_set(chan, tmp_appl);
368 ast_channel_data_set(chan, tmp_data);
369
370 ast_channel_unlock(chan);
371 }
372 res = pbx_exec(chan, a, appdata);
373 } else
374 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
375 } else {
376 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
377 }
378 }
379 return res;
380}
381
382static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
383{
385 if (var) {
387 return 1;
388 }
389 return 0;
390}
391
393{
394 .name = "Realtime",
395 .description = "Realtime Dialplan Switch",
396 .exists = realtime_exists,
397 .canmatch = realtime_canmatch,
398 .exec = realtime_exec,
399 .matchmore = realtime_matchmore,
400};
401
402static int unload_module(void)
403{
405 pthread_cancel(cleanup_thread);
406 pthread_kill(cleanup_thread, SIGURG);
407 pthread_join(cleanup_thread, NULL);
408 /* Destroy all remaining entries */
409 ao2_ref(cache, -1);
410 return 0;
411}
412
413static int load_module(void)
414{
417 if (!cache) {
419 }
420
423 }
424
428}
429
static const char app[]
Definition: app_adsiprog.c:56
option_flags
Definition: app_skel.c:136
#define var
Definition: ast_expr2f.c:605
Persistent data storage (akin to *doze registry)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
static int priority
static char * table
Definition: cdr_odbc.c:55
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2362
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void ast_channel_appl_set(struct ast_channel *chan, const char *value)
const char * ast_channel_data(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2922
void ast_channel_data_set(struct ast_channel *chan, const char *value)
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
const char * ast_channel_appl(const struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
#define AST_MAX_EXTENSION
Definition: channel.h:134
Channel Variables.
Standard Command Line Interface.
#define SENTINEL
Definition: compiler.h:87
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Generic File Format Support. Should be included by clients of the file handling routines....
void ast_channel_snapshot_invalidate_segment(struct ast_channel *chan, enum ast_channel_snapshot_segment_invalidation segment)
Invalidate a channel snapshot segment from being reused.
struct stasis_message_type * ast_channel_snapshot_type(void)
Message type for ast_channel_snapshot_update.
void ast_channel_publish_snapshot(struct ast_channel *chan)
Publish a ast_channel_snapshot for a channel.
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
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: main/app.c:3056
Configuration File Parser.
struct ast_variable * ast_category_detach_variables(struct ast_category *cat)
Definition: main/config.c:1440
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
void ast_config_sort_categories(struct ast_config *config, int descending, int(*comparator)(struct ast_category *p, struct ast_category *q))
Sorts categories in a config in the order of a numerical value contained within them.
Definition: main/config.c:1260
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3622
#define ast_variable_new(name, value, filename)
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3506
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
const char * ast_variable_find(const struct ast_category *category, const char *variable)
Gets a variable value from a specific category structure by name.
Definition: main/config.c:824
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
Definition: main/config.c:1111
Asterisk internal frame definitions.
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
I/O Management (derived from Cheops-NG)
A set of macros to manage forward-linked lists.
Asterisk locking-related definitions:
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
Asterisk module definitions.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_FAILURE
Module could not be loaded properly.
Definition: module.h:102
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
Core PBX routines and definitions.
void ast_unregister_switch(struct ast_switch *sw)
Unregister an alternative switch.
Definition: pbx_switch.c:76
int ast_register_switch(struct ast_switch *sw)
Register an alternative dialplan switch.
Definition: pbx_switch.c:58
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
int ast_extension_close(const char *pattern, const char *data, int needmore)
Definition: pbx.c:2432
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
Definition: extconf.c:4295
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
pthread_t cleanup_thread
Definition: pbx_realtime.c:78
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
static struct ast_variable * realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
Definition: pbx_realtime.c:229
static int cache_hash(const void *obj, const int flags)
Definition: pbx_realtime.c:80
@ OPTION_PATTERNS_DISABLED
Definition: pbx_realtime.c:62
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:309
static const struct ast_app_option switch_opts[128]
Definition: pbx_realtime.c:67
static struct ast_switch realtime_switch
Definition: pbx_realtime.c:392
static int cache_cmp(void *obj, void *arg, int flags)
Definition: pbx_realtime.c:86
static int extension_length_comparator(struct ast_category *p, struct ast_category *q)
Definition: pbx_realtime.c:144
#define MODE_CANMATCH
Definition: pbx_realtime.c:57
#define MODE_MATCHMORE
Definition: pbx_realtime.c:56
static struct ast_variable * dup_vars(struct ast_variable *v)
Definition: pbx_realtime.c:95
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:166
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:299
#define EXT_DATA_SIZE
Definition: pbx_realtime.c:59
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:289
static int load_module(void)
Definition: pbx_realtime.c:413
static void free_entry(void *obj)
Definition: pbx_realtime.c:111
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:382
static int unload_module(void)
Definition: pbx_realtime.c:402
#define MODE_MATCH
Definition: pbx_realtime.c:55
struct ao2_container * cache
Definition: pbx_realtime.c:77
static int purge_old_fn(void *obj, void *arg, int flags)
Definition: pbx_realtime.c:117
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Realtime Switch")
#define NULL
Definition: resample.c:96
Scheduler Routines (derived from cheops)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
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:1303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Generic container type.
ast_app: A registered application
Definition: pbx_app.c:45
Main Channel structure associated with a channel.
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
const char * name
Definition: pbx.h:162
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Definition: pbx_realtime.c:69
char exten[2]
Definition: pbx_realtime.c:74
char * context
Definition: pbx_realtime.c:73
struct timeval when
Definition: pbx_realtime.c:70
struct ast_variable * var
Definition: pbx_realtime.c:71
int priority
Definition: pbx_realtime.c:72
Handy terminal functions for vt* terms.
#define COLOR_BRCYAN
Definition: term.h:63
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition: term.c:235
#define COLOR_BRMAGENTA
Definition: term.h:61
static struct test_val a
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:584