Realtime PBX Module. More...
#include "asterisk.h"
#include <signal.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/frame.h"
#include "asterisk/term.h"
#include "asterisk/manager.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/chanvars.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/utils.h"
#include "asterisk/astdb.h"
#include "asterisk/app.h"
#include "asterisk/astobj2.h"
Go to the source code of this file.
Data Structures | |
struct | cache_entry |
Defines | |
#define | EXT_DATA_SIZE 256 |
#define | MODE_CANMATCH 2 |
#define | MODE_MATCH 0 |
#define | MODE_MATCHMORE 1 |
Enumerations | |
enum | option_flags { OPTION_A = (1 << 0), OPTION_B = (1 << 1), OPTION_C = (1 << 2), OPTION_WAIT = (1 << 0), OPTION_PATTERNS_DISABLED = (1 << 0) } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | cache_cmp (void *obj, void *arg, int flags) |
static int | cache_hash (const void *obj, const int flags) |
static void * | cleanup (void *unused) |
static struct ast_variable * | dup_vars (struct ast_variable *v) |
static void | free_entry (void *obj) |
static int | load_module (void) |
static int | purge_old_fn (void *obj, void *arg, int flags) |
static int | realtime_canmatch (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) |
static struct ast_variable * | realtime_common (const char *context, const char *exten, int priority, const char *data, int mode) |
static int | realtime_exec (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) |
static int | realtime_exists (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) |
static int | realtime_matchmore (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) |
static struct ast_variable * | realtime_switch_common (const char *table, const char *context, const char *exten, int priority, int mode, struct ast_flags flags) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Realtime Switch" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
struct ao2_container * | cache |
pthread_t | cleanup_thread = 0 |
static struct ast_switch | realtime_switch |
static struct ast_app_option | switch_opts [128] = { [ 'p' ] = { .flag = OPTION_PATTERNS_DISABLED },} |
Realtime PBX Module.
Definition in file pbx_realtime.c.
#define EXT_DATA_SIZE 256 |
Definition at line 60 of file pbx_realtime.c.
#define MODE_CANMATCH 2 |
Definition at line 58 of file pbx_realtime.c.
Referenced by realtime_canmatch(), and realtime_switch_common().
#define MODE_MATCH 0 |
Definition at line 56 of file pbx_realtime.c.
Referenced by realtime_common(), realtime_exec(), realtime_exists(), and realtime_switch_common().
#define MODE_MATCHMORE 1 |
Definition at line 57 of file pbx_realtime.c.
Referenced by realtime_matchmore(), and realtime_switch_common().
enum option_flags |
Definition at line 62 of file pbx_realtime.c.
00062 { 00063 OPTION_PATTERNS_DISABLED = (1 << 0), 00064 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 423 of file pbx_realtime.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 423 of file pbx_realtime.c.
static int cache_cmp | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 87 of file pbx_realtime.c.
References CMP_MATCH, cache_entry::context, cache_entry::exten, f, and cache_entry::priority.
Referenced by load_module().
static int cache_hash | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 81 of file pbx_realtime.c.
References ast_str_case_hash(), cache_entry::exten, and cache_entry::priority.
Referenced by load_module().
00082 { 00083 const struct cache_entry *e = obj; 00084 return ast_str_case_hash(e->exten) + e->priority; 00085 }
static void* cleanup | ( | void * | unused | ) | [static] |
Definition at line 125 of file pbx_realtime.c.
References ao2_callback, ao2_container_count(), ast_tvnow(), OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, and purge_old_fn().
Referenced by _sip_tcp_helper_thread(), ast_rtp_dtmf_end_with_duration(), ast_sockaddr_resolve(), build_user(), handle_uri(), load_module(), and realtime_peer().
00126 { 00127 struct timespec forever = { 999999999, 0 }, one_second = { 1, 0 }; 00128 struct timeval now; 00129 00130 for (;;) { 00131 pthread_testcancel(); 00132 if (ao2_container_count(cache) == 0) { 00133 nanosleep(&forever, NULL); 00134 } 00135 pthread_testcancel(); 00136 now = ast_tvnow(); 00137 ao2_callback(cache, OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA, purge_old_fn, &now); 00138 pthread_testcancel(); 00139 nanosleep(&one_second, NULL); 00140 } 00141 00142 return NULL; 00143 }
static struct ast_variable* dup_vars | ( | struct ast_variable * | v | ) | [static, read] |
Definition at line 96 of file pbx_realtime.c.
References ast_variable_new(), ast_variables_destroy(), ast_variable::file, ast_variable::name, ast_variable::next, and ast_variable::value.
Referenced by realtime_common().
00097 { 00098 struct ast_variable *new, *list = NULL; 00099 for (; v; v = v->next) { 00100 if (!(new = ast_variable_new(v->name, v->value, v->file))) { 00101 ast_variables_destroy(list); 00102 return NULL; 00103 } 00104 /* Reversed list in cache, but when we duplicate out of the cache, 00105 * it's back to correct order. */ 00106 new->next = list; 00107 list = new; 00108 } 00109 return list; 00110 }
static void free_entry | ( | void * | obj | ) | [static] |
Definition at line 112 of file pbx_realtime.c.
References ast_variables_destroy(), and cache_entry::var.
Referenced by realtime_common().
00113 { 00114 struct cache_entry *e = obj; 00115 ast_variables_destroy(e->var); 00116 }
static int load_module | ( | void | ) | [static] |
Definition at line 408 of file pbx_realtime.c.
References ao2_container_alloc, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_pthread_create, ast_register_switch(), cache_cmp(), cache_hash(), and cleanup().
00409 { 00410 if (!(cache = ao2_container_alloc(573, cache_hash, cache_cmp))) { 00411 return AST_MODULE_LOAD_FAILURE; 00412 } 00413 00414 if (ast_pthread_create(&cleanup_thread, NULL, cleanup, NULL)) { 00415 return AST_MODULE_LOAD_FAILURE; 00416 } 00417 00418 if (ast_register_switch(&realtime_switch)) 00419 return AST_MODULE_LOAD_FAILURE; 00420 return AST_MODULE_LOAD_SUCCESS; 00421 }
static int purge_old_fn | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 118 of file pbx_realtime.c.
References ast_tvdiff_ms(), CMP_MATCH, and cache_entry::when.
Referenced by cleanup().
00119 { 00120 struct cache_entry *e = obj; 00121 struct timeval *now = arg; 00122 return ast_tvdiff_ms(*now, e->when) >= 1000 ? CMP_MATCH : 0; 00123 }
static int realtime_canmatch | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | exten, | |||
int | priority, | |||
const char * | callerid, | |||
const char * | data | |||
) | [static] |
Definition at line 289 of file pbx_realtime.c.
References ast_variables_destroy(), MODE_CANMATCH, and realtime_common().
00290 { 00291 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH); 00292 if (var) { 00293 ast_variables_destroy(var); 00294 return 1; 00295 } 00296 return 0; 00297 }
static struct ast_variable* realtime_common | ( | const char * | context, | |
const char * | exten, | |||
int | priority, | |||
const char * | data, | |||
int | mode | |||
) | [static, read] |
Definition at line 219 of file pbx_realtime.c.
References ao2_alloc, ao2_find, ao2_link, ao2_ref, ast_app_parse_options(), ast_copy_string(), AST_MAX_EXTENSION, ast_strdupa, ast_strlen_zero(), ast_tvnow(), ast_variables_destroy(), cache_entry::context, dup_vars(), cache_entry::exten, free_entry(), MODE_MATCH, OBJ_POINTER, cache_entry::priority, realtime_switch_common(), S_OR, switch_opts, table, cache_entry::var, var, and cache_entry::when.
Referenced by realtime_canmatch(), realtime_exec(), realtime_exists(), and realtime_matchmore().
00220 { 00221 const char *ctx = NULL; 00222 char *table; 00223 struct ast_variable *var=NULL; 00224 struct ast_flags flags = { 0, }; 00225 struct cache_entry *ce; 00226 struct { 00227 struct cache_entry ce; 00228 char exten[AST_MAX_EXTENSION]; 00229 } cache_search = { { .priority = priority, .context = (char *) context }, }; 00230 char *buf = ast_strdupa(data); 00231 /* "Realtime" prefix is stripped off in the parent engine. The 00232 * remaining string is: [[context@]table][/opts] */ 00233 char *opts = strchr(buf, '/'); 00234 if (opts) 00235 *opts++ = '\0'; 00236 table = strchr(buf, '@'); 00237 if (table) { 00238 *table++ = '\0'; 00239 ctx = buf; 00240 } 00241 ctx = S_OR(ctx, context); 00242 table = S_OR(table, "extensions"); 00243 if (!ast_strlen_zero(opts)) { 00244 ast_app_parse_options(switch_opts, &flags, NULL, opts); 00245 } 00246 ast_copy_string(cache_search.exten, exten, sizeof(cache_search.exten)); 00247 if (mode == MODE_MATCH && (ce = ao2_find(cache, &cache_search, OBJ_POINTER))) { 00248 var = dup_vars(ce->var); 00249 ao2_ref(ce, -1); 00250 } else { 00251 var = realtime_switch_common(table, ctx, exten, priority, mode, flags); 00252 do { 00253 struct ast_variable *new; 00254 /* Only cache matches */ 00255 if (mode != MODE_MATCH) { 00256 break; 00257 } 00258 if (!(new = dup_vars(var))) { 00259 break; 00260 } 00261 if (!(ce = ao2_alloc(sizeof(*ce) + strlen(exten) + strlen(context), free_entry))) { 00262 ast_variables_destroy(new); 00263 break; 00264 } 00265 ce->context = ce->exten + strlen(exten) + 1; 00266 strcpy(ce->exten, exten); /* SAFE */ 00267 strcpy(ce->context, context); /* SAFE */ 00268 ce->priority = priority; 00269 ce->var = new; 00270 ce->when = ast_tvnow(); 00271 ao2_link(cache, ce); 00272 pthread_kill(cleanup_thread, SIGURG); 00273 ao2_ref(ce, -1); 00274 } while (0); 00275 } 00276 return var; 00277 }
static int realtime_exec | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | exten, | |||
int | priority, | |||
const char * | callerid, | |||
const char * | data | |||
) | [static] |
Definition at line 299 of file pbx_realtime.c.
References app, ast_alloca, ast_compat_pbx_realtime, ast_log(), ast_strdupa, ast_strlen_zero(), ast_variables_destroy(), ast_verb, COLOR_BRCYAN, COLOR_BRMAGENTA, ast_channel::context, EVENT_FLAG_DIALPLAN, EXT_DATA_SIZE, ast_channel::exten, LOG_NOTICE, LOG_WARNING, manager_event, MODE_MATCH, ast_variable::name, ast_variable::next, pbx_exec(), pbx_findapp(), pbx_substitute_variables_helper(), ast_channel::priority, realtime_common(), S_OR, term_color(), and ast_variable::value.
00300 { 00301 int res = -1; 00302 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH); 00303 00304 if (var) { 00305 char *tmp=""; 00306 char *app = NULL; 00307 struct ast_variable *v; 00308 00309 for (v = var; v ; v = v->next) { 00310 if (!strcasecmp(v->name, "app")) 00311 app = ast_strdupa(v->value); 00312 else if (!strcasecmp(v->name, "appdata")) { 00313 if (ast_compat_pbx_realtime) { 00314 char *ptr; 00315 int in = 0; 00316 tmp = ast_alloca(strlen(v->value) * 2 + 1); 00317 for (ptr = tmp; *v->value; v->value++) { 00318 if (*v->value == ',') { 00319 *ptr++ = '\\'; 00320 *ptr++ = ','; 00321 } else if (*v->value == '|' && !in) { 00322 *ptr++ = ','; 00323 } else { 00324 *ptr++ = *v->value; 00325 } 00326 00327 /* Don't escape '|', meaning 'or', inside expressions ($[ ]) */ 00328 if (v->value[0] == '[' && v->value[-1] == '$') { 00329 in++; 00330 } else if (v->value[0] == ']' && in) { 00331 in--; 00332 } 00333 } 00334 *ptr = '\0'; 00335 } else { 00336 tmp = ast_strdupa(v->value); 00337 } 00338 } 00339 } 00340 ast_variables_destroy(var); 00341 if (!ast_strlen_zero(app)) { 00342 struct ast_app *a = pbx_findapp(app); 00343 if (a) { 00344 char appdata[512]; 00345 char tmp1[80]; 00346 char tmp2[80]; 00347 char tmp3[EXT_DATA_SIZE]; 00348 00349 appdata[0] = 0; /* just in case the substitute var func isn't called */ 00350 if(!ast_strlen_zero(tmp)) 00351 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1); 00352 ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n", 00353 chan->exten, chan->context, chan->priority, 00354 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)), 00355 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)), 00356 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3))); 00357 manager_event(EVENT_FLAG_DIALPLAN, "Newexten", 00358 "Channel: %s\r\n" 00359 "Context: %s\r\n" 00360 "Extension: %s\r\n" 00361 "Priority: %d\r\n" 00362 "Application: %s\r\n" 00363 "AppData: %s\r\n" 00364 "Uniqueid: %s\r\n", 00365 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid); 00366 00367 res = pbx_exec(chan, a, appdata); 00368 } else 00369 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context); 00370 } else { 00371 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context); 00372 } 00373 } 00374 return res; 00375 }
static int realtime_exists | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | exten, | |||
int | priority, | |||
const char * | callerid, | |||
const char * | data | |||
) | [static] |
Definition at line 279 of file pbx_realtime.c.
References ast_variables_destroy(), MODE_MATCH, and realtime_common().
00280 { 00281 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH); 00282 if (var) { 00283 ast_variables_destroy(var); 00284 return 1; 00285 } 00286 return 0; 00287 }
static int realtime_matchmore | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | exten, | |||
int | priority, | |||
const char * | callerid, | |||
const char * | data | |||
) | [static] |
Definition at line 377 of file pbx_realtime.c.
References ast_variables_destroy(), MODE_MATCHMORE, and realtime_common().
00378 { 00379 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE); 00380 if (var) { 00381 ast_variables_destroy(var); 00382 return 1; 00383 } 00384 return 0; 00385 }
static struct ast_variable* realtime_switch_common | ( | const char * | table, | |
const char * | context, | |||
const char * | exten, | |||
int | priority, | |||
int | mode, | |||
struct ast_flags | flags | |||
) | [static, read] |
Definition at line 160 of file pbx_realtime.c.
References ast_category_browse(), ast_category_detach_variables(), ast_category_get(), ast_config_destroy(), ast_copy_string(), ast_extension_close(), ast_extension_match(), ast_load_realtime(), ast_load_realtime_multientry(), AST_MAX_EXTENSION, ast_test_flag, match(), MODE_CANMATCH, MODE_MATCH, MODE_MATCHMORE, OPTION_PATTERNS_DISABLED, SENTINEL, and var.
Referenced by realtime_common().
00161 { 00162 struct ast_variable *var; 00163 struct ast_config *cfg; 00164 char pri[20]; 00165 char *ematch; 00166 char rexten[AST_MAX_EXTENSION + 20]=""; 00167 int match; 00168 /* Optimization: since we don't support hints in realtime, it's silly to 00169 * query for a hint here, since we won't actually do anything with it. 00170 * This just wastes CPU time and resources. */ 00171 if (priority < 0) { 00172 return NULL; 00173 } 00174 snprintf(pri, sizeof(pri), "%d", priority); 00175 switch(mode) { 00176 case MODE_MATCHMORE: 00177 ematch = "exten LIKE"; 00178 snprintf(rexten, sizeof(rexten), "%s_%%", exten); 00179 break; 00180 case MODE_CANMATCH: 00181 ematch = "exten LIKE"; 00182 snprintf(rexten, sizeof(rexten), "%s%%", exten); 00183 break; 00184 case MODE_MATCH: 00185 default: 00186 ematch = "exten"; 00187 ast_copy_string(rexten, exten, sizeof(rexten)); 00188 } 00189 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, SENTINEL); 00190 if (!var && !ast_test_flag(&flags, OPTION_PATTERNS_DISABLED)) { 00191 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, SENTINEL); 00192 if (cfg) { 00193 char *cat = ast_category_browse(cfg, NULL); 00194 00195 while(cat) { 00196 switch(mode) { 00197 case MODE_MATCHMORE: 00198 match = ast_extension_close(cat, exten, 1); 00199 break; 00200 case MODE_CANMATCH: 00201 match = ast_extension_close(cat, exten, 0); 00202 break; 00203 case MODE_MATCH: 00204 default: 00205 match = ast_extension_match(cat, exten); 00206 } 00207 if (match) { 00208 var = ast_category_detach_variables(ast_category_get(cfg, cat)); 00209 break; 00210 } 00211 cat = ast_category_browse(cfg, cat); 00212 } 00213 ast_config_destroy(cfg); 00214 } 00215 } 00216 return var; 00217 }
static int unload_module | ( | void | ) | [static] |
Definition at line 397 of file pbx_realtime.c.
References ao2_ref, and ast_unregister_switch().
00398 { 00399 ast_unregister_switch(&realtime_switch); 00400 pthread_cancel(cleanup_thread); 00401 pthread_kill(cleanup_thread, SIGURG); 00402 pthread_join(cleanup_thread, NULL); 00403 /* Destroy all remaining entries */ 00404 ao2_ref(cache, -1); 00405 return 0; 00406 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Realtime Switch" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 423 of file pbx_realtime.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 423 of file pbx_realtime.c.
struct ao2_container* cache |
Definition at line 78 of file pbx_realtime.c.
pthread_t cleanup_thread = 0 |
Definition at line 79 of file pbx_realtime.c.
struct ast_switch realtime_switch [static] |
Definition at line 387 of file pbx_realtime.c.
struct ast_app_option switch_opts[128] = { [ 'p' ] = { .flag = OPTION_PATTERNS_DISABLED },} [static] |
Definition at line 68 of file pbx_realtime.c.
Referenced by realtime_common().