#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/md5.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_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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
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 },} |
Definition in file pbx_realtime.c.
#define EXT_DATA_SIZE 256 |
Definition at line 57 of file pbx_realtime.c.
#define MODE_CANMATCH 2 |
Definition at line 55 of file pbx_realtime.c.
Referenced by realtime_canmatch(), and realtime_switch_common().
#define MODE_MATCH 0 |
Definition at line 53 of file pbx_realtime.c.
Referenced by realtime_common(), realtime_exec(), realtime_exists(), and realtime_switch_common().
#define MODE_MATCHMORE 1 |
Definition at line 54 of file pbx_realtime.c.
Referenced by realtime_matchmore(), and realtime_switch_common().
enum option_flags |
Definition at line 59 of file pbx_realtime.c.
00059 { 00060 OPTION_PATTERNS_DISABLED = (1 << 0), 00061 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 422 of file pbx_realtime.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 422 of file pbx_realtime.c.
static int cache_cmp | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 84 of file pbx_realtime.c.
References CMP_MATCH, cache_entry::context, cache_entry::exten, f, and cache_entry::priority.
Referenced by load_module().
00085 { 00086 struct cache_entry *e = obj, *f = arg; 00087 return e->priority != f->priority ? 0 : 00088 strcmp(e->exten, f->exten) ? 0 : 00089 strcmp(e->context, f->context) ? 0 : 00090 CMP_MATCH; 00091 }
static int cache_hash | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 78 of file pbx_realtime.c.
References ast_str_case_hash(), cache_entry::exten, and cache_entry::priority.
Referenced by load_module().
00079 { 00080 const struct cache_entry *e = obj; 00081 return ast_str_case_hash(e->exten) + e->priority; 00082 }
static void* cleanup | ( | void * | unused | ) | [static] |
Definition at line 122 of file pbx_realtime.c.
References ao2_callback, ao2_container_count(), ast_tvnow(), cache, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, and purge_old_fn().
Referenced by _sip_tcp_helper_thread(), ast_sockaddr_resolve(), build_user(), handle_uri(), and load_module().
00123 { 00124 struct timespec forever = { 999999999, 0 }, one_second = { 1, 0 }; 00125 struct timeval now; 00126 00127 for (;;) { 00128 pthread_testcancel(); 00129 if (ao2_container_count(cache) == 0) { 00130 nanosleep(&forever, NULL); 00131 } 00132 pthread_testcancel(); 00133 now = ast_tvnow(); 00134 ao2_callback(cache, OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA, purge_old_fn, &now); 00135 pthread_testcancel(); 00136 nanosleep(&one_second, NULL); 00137 } 00138 00139 return NULL; 00140 }
static struct ast_variable* dup_vars | ( | struct ast_variable * | v | ) | [static] |
Definition at line 93 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().
00094 { 00095 struct ast_variable *new, *list = NULL; 00096 for (; v; v = v->next) { 00097 if (!(new = ast_variable_new(v->name, v->value, v->file))) { 00098 ast_variables_destroy(list); 00099 return NULL; 00100 } 00101 /* Reversed list in cache, but when we duplicate out of the cache, 00102 * it's back to correct order. */ 00103 new->next = list; 00104 list = new; 00105 } 00106 return list; 00107 }
static void free_entry | ( | void * | obj | ) | [static] |
Definition at line 109 of file pbx_realtime.c.
References ast_variables_destroy(), and cache_entry::var.
Referenced by realtime_common().
00110 { 00111 struct cache_entry *e = obj; 00112 ast_variables_destroy(e->var); 00113 }
static int load_module | ( | void | ) | [static] |
Definition at line 407 of file pbx_realtime.c.
References ao2_container_alloc, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_pthread_create, ast_register_switch(), cache, cache_cmp(), cache_hash(), cleanup(), cleanup_thread, and realtime_switch.
00408 { 00409 if (!(cache = ao2_container_alloc(573, cache_hash, cache_cmp))) { 00410 return AST_MODULE_LOAD_FAILURE; 00411 } 00412 00413 if (ast_pthread_create(&cleanup_thread, NULL, cleanup, NULL)) { 00414 return AST_MODULE_LOAD_FAILURE; 00415 } 00416 00417 if (ast_register_switch(&realtime_switch)) 00418 return AST_MODULE_LOAD_FAILURE; 00419 return AST_MODULE_LOAD_SUCCESS; 00420 }
static int purge_old_fn | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 115 of file pbx_realtime.c.
References ast_tvdiff_ms(), CMP_MATCH, and cache_entry::when.
Referenced by cleanup().
00116 { 00117 struct cache_entry *e = obj; 00118 struct timeval *now = arg; 00119 return ast_tvdiff_ms(*now, e->when) >= 1000 ? CMP_MATCH : 0; 00120 }
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 288 of file pbx_realtime.c.
References ast_variables_destroy(), MODE_CANMATCH, realtime_common(), and var.
00289 { 00290 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH); 00291 if (var) { 00292 ast_variables_destroy(var); 00293 return 1; 00294 } 00295 return 0; 00296 }
static struct ast_variable* realtime_common | ( | const char * | context, | |
const char * | exten, | |||
int | priority, | |||
const char * | data, | |||
int | mode | |||
) | [static] |
Definition at line 216 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, cleanup_thread, dup_vars(), ast_flags::flags, free_entry(), MODE_MATCH, OBJ_POINTER, cache_entry::priority, realtime_switch_common(), S_OR, switch_opts, table, cache_entry::var, and var.
Referenced by realtime_canmatch(), realtime_exec(), realtime_exists(), and realtime_matchmore().
00217 { 00218 const char *ctx = NULL; 00219 char *table; 00220 struct ast_variable *var=NULL; 00221 struct ast_flags flags = { 0, }; 00222 struct cache_entry *ce; 00223 struct { 00224 struct cache_entry ce; 00225 char exten[AST_MAX_EXTENSION]; 00226 } cache_search = { { .priority = priority, .context = (char *) context }, }; 00227 char *buf = ast_strdupa(data); 00228 if (buf) { 00229 /* "Realtime" prefix is stripped off in the parent engine. The 00230 * remaining string is: [[context@]table][/opts] */ 00231 char *opts = strchr(buf, '/'); 00232 if (opts) 00233 *opts++ = '\0'; 00234 table = strchr(buf, '@'); 00235 if (table) { 00236 *table++ = '\0'; 00237 ctx = buf; 00238 } 00239 ctx = S_OR(ctx, context); 00240 table = S_OR(table, "extensions"); 00241 if (!ast_strlen_zero(opts)) { 00242 ast_app_parse_options(switch_opts, &flags, NULL, opts); 00243 } 00244 ast_copy_string(cache_search.exten, exten, sizeof(cache_search.exten)); 00245 if (mode == MODE_MATCH && (ce = ao2_find(cache, &cache_search, OBJ_POINTER))) { 00246 var = dup_vars(ce->var); 00247 ao2_ref(ce, -1); 00248 } else { 00249 var = realtime_switch_common(table, ctx, exten, priority, mode, flags); 00250 do { 00251 struct ast_variable *new; 00252 /* Only cache matches */ 00253 if (mode != MODE_MATCH) { 00254 break; 00255 } 00256 if (!(new = dup_vars(var))) { 00257 break; 00258 } 00259 if (!(ce = ao2_alloc(sizeof(*ce) + strlen(exten) + strlen(context), free_entry))) { 00260 ast_variables_destroy(new); 00261 break; 00262 } 00263 ce->context = ce->exten + strlen(exten) + 1; 00264 strcpy(ce->exten, exten); /* SAFE */ 00265 strcpy(ce->context, context); /* SAFE */ 00266 ce->priority = priority; 00267 ce->var = new; 00268 ce->when = ast_tvnow(); 00269 ao2_link(cache, ce); 00270 pthread_kill(cleanup_thread, SIGURG); 00271 ao2_ref(ce, -1); 00272 } while (0); 00273 } 00274 } 00275 return var; 00276 }
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 298 of file pbx_realtime.c.
References app, ast_compat_pbx_realtime, ast_strdupa, MODE_MATCH, ast_variable::name, ast_variable::next, realtime_common(), ast_variable::value, and var.
00299 { 00300 int res = -1; 00301 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH); 00302 00303 if (var) { 00304 char *tmp=""; 00305 char *app = NULL; 00306 struct ast_variable *v; 00307 00308 for (v = var; v ; v = v->next) { 00309 if (!strcasecmp(v->name, "app")) 00310 app = ast_strdupa(v->value); 00311 else if (!strcasecmp(v->name, "appdata")) { 00312 if (ast_compat_pbx_realtime) { 00313 char *ptr; 00314 int in = 0; 00315 tmp = alloca(strlen(v->value) * 2 + 1); 00316 for (ptr = tmp; *v->value; v->value++) { 00317 if (*v->value == ',') { 00318 *ptr++ = '\\'; 00319 *ptr++ = ','; 00320 } else if (*v->value == '|' && !in) { 00321 *ptr++ = ','; 00322 } else { 00323 *ptr++ = *v->value; 00324 } 00325 00326 /* Don't escape '|', meaning 'or', inside expressions ($[ ]) */ 00327 if (v->value[0] == '[' && v->value[-1] == '$') { 00328 in++; 00329 } else if (v->value[0] == ']' && in) { 00330 in--; 00331 } 00332 } 00333 *ptr = '\0'; 00334 } else { 00335 tmp = ast_strdupa(v->value); 00336 } 00337 } 00338 } 00339 ast_variables_destroy(var); 00340 if (!ast_strlen_zero(app)) { 00341 struct ast_app *a = pbx_findapp(app); 00342 if (a) { 00343 char appdata[512]; 00344 char tmp1[80]; 00345 char tmp2[80]; 00346 char tmp3[EXT_DATA_SIZE]; 00347 00348 appdata[0] = 0; /* just in case the substitute var func isn't called */ 00349 if(!ast_strlen_zero(tmp)) 00350 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1); 00351 ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n", 00352 chan->exten, chan->context, chan->priority, 00353 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)), 00354 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)), 00355 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3))); 00356 manager_event(EVENT_FLAG_DIALPLAN, "Newexten", 00357 "Channel: %s\r\n" 00358 "Context: %s\r\n" 00359 "Extension: %s\r\n" 00360 "Priority: %d\r\n" 00361 "Application: %s\r\n" 00362 "AppData: %s\r\n" 00363 "Uniqueid: %s\r\n", 00364 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid); 00365 00366 res = pbx_exec(chan, a, appdata); 00367 } else 00368 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context); 00369 } else { 00370 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context); 00371 } 00372 } 00373 return res; 00374 }
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 278 of file pbx_realtime.c.
References ast_variables_destroy(), MODE_MATCH, realtime_common(), and var.
00279 { 00280 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH); 00281 if (var) { 00282 ast_variables_destroy(var); 00283 return 1; 00284 } 00285 return 0; 00286 }
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 376 of file pbx_realtime.c.
References ast_variables_destroy(), MODE_MATCHMORE, realtime_common(), and var.
00377 { 00378 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE); 00379 if (var) { 00380 ast_variables_destroy(var); 00381 return 1; 00382 } 00383 return 0; 00384 }
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] |
Definition at line 157 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().
00158 { 00159 struct ast_variable *var; 00160 struct ast_config *cfg; 00161 char pri[20]; 00162 char *ematch; 00163 char rexten[AST_MAX_EXTENSION + 20]=""; 00164 int match; 00165 /* Optimization: since we don't support hints in realtime, it's silly to 00166 * query for a hint here, since we won't actually do anything with it. 00167 * This just wastes CPU time and resources. */ 00168 if (priority < 0) { 00169 return NULL; 00170 } 00171 snprintf(pri, sizeof(pri), "%d", priority); 00172 switch(mode) { 00173 case MODE_MATCHMORE: 00174 ematch = "exten LIKE"; 00175 snprintf(rexten, sizeof(rexten), "%s_%%", exten); 00176 break; 00177 case MODE_CANMATCH: 00178 ematch = "exten LIKE"; 00179 snprintf(rexten, sizeof(rexten), "%s%%", exten); 00180 break; 00181 case MODE_MATCH: 00182 default: 00183 ematch = "exten"; 00184 ast_copy_string(rexten, exten, sizeof(rexten)); 00185 } 00186 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, SENTINEL); 00187 if (!var && !ast_test_flag(&flags, OPTION_PATTERNS_DISABLED)) { 00188 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, SENTINEL); 00189 if (cfg) { 00190 char *cat = ast_category_browse(cfg, NULL); 00191 00192 while(cat) { 00193 switch(mode) { 00194 case MODE_MATCHMORE: 00195 match = ast_extension_close(cat, exten, 1); 00196 break; 00197 case MODE_CANMATCH: 00198 match = ast_extension_close(cat, exten, 0); 00199 break; 00200 case MODE_MATCH: 00201 default: 00202 match = ast_extension_match(cat, exten); 00203 } 00204 if (match) { 00205 var = ast_category_detach_variables(ast_category_get(cfg, cat)); 00206 break; 00207 } 00208 cat = ast_category_browse(cfg, cat); 00209 } 00210 ast_config_destroy(cfg); 00211 } 00212 } 00213 return var; 00214 }
static int unload_module | ( | void | ) | [static] |
Definition at line 396 of file pbx_realtime.c.
References ao2_ref, ast_unregister_switch(), cache, cleanup_thread, and realtime_switch.
00397 { 00398 ast_unregister_switch(&realtime_switch); 00399 pthread_cancel(cleanup_thread); 00400 pthread_kill(cleanup_thread, SIGURG); 00401 pthread_join(cleanup_thread, NULL); 00402 /* Destroy all remaining entries */ 00403 ao2_ref(cache, -1); 00404 return 0; 00405 }
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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 422 of file pbx_realtime.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 422 of file pbx_realtime.c.
struct ao2_container* cache |
Definition at line 75 of file pbx_realtime.c.
Referenced by cleanup(), load_module(), realtime_common(), and unload_module().
pthread_t cleanup_thread = 0 |
Definition at line 76 of file pbx_realtime.c.
Referenced by load_module(), realtime_common(), and unload_module().
struct ast_switch realtime_switch [static] |
struct ast_app_option switch_opts[128] = { [ 'p' ] = { .flag = OPTION_PATTERNS_DISABLED },} [static] |