#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_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 |
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 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 425 of file pbx_realtime.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 425 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().
00088 { 00089 struct cache_entry *e = obj, *f = arg; 00090 return e->priority != f->priority ? 0 : 00091 strcmp(e->exten, f->exten) ? 0 : 00092 strcmp(e->context, f->context) ? 0 : 00093 CMP_MATCH; 00094 }
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(), cache, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, and purge_old_fn().
Referenced by _sip_tcp_helper_thread(), 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] |
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 410 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.
00411 { 00412 if (!(cache = ao2_container_alloc(573, cache_hash, cache_cmp))) { 00413 return AST_MODULE_LOAD_FAILURE; 00414 } 00415 00416 if (ast_pthread_create(&cleanup_thread, NULL, cleanup, NULL)) { 00417 return AST_MODULE_LOAD_FAILURE; 00418 } 00419 00420 if (ast_register_switch(&realtime_switch)) 00421 return AST_MODULE_LOAD_FAILURE; 00422 return AST_MODULE_LOAD_SUCCESS; 00423 }
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 291 of file pbx_realtime.c.
References ast_variables_destroy(), MODE_CANMATCH, realtime_common(), and var.
00292 { 00293 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH); 00294 if (var) { 00295 ast_variables_destroy(var); 00296 return 1; 00297 } 00298 return 0; 00299 }
static struct ast_variable* realtime_common | ( | const char * | context, | |
const char * | exten, | |||
int | priority, | |||
const char * | data, | |||
int | mode | |||
) | [static] |
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, 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().
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 if (buf) { 00232 /* "Realtime" prefix is stripped off in the parent engine. The 00233 * remaining string is: [[context@]table][/opts] */ 00234 char *opts = strchr(buf, '/'); 00235 if (opts) 00236 *opts++ = '\0'; 00237 table = strchr(buf, '@'); 00238 if (table) { 00239 *table++ = '\0'; 00240 ctx = buf; 00241 } 00242 ctx = S_OR(ctx, context); 00243 table = S_OR(table, "extensions"); 00244 if (!ast_strlen_zero(opts)) { 00245 ast_app_parse_options(switch_opts, &flags, NULL, opts); 00246 } 00247 ast_copy_string(cache_search.exten, exten, sizeof(cache_search.exten)); 00248 if (mode == MODE_MATCH && (ce = ao2_find(cache, &cache_search, OBJ_POINTER))) { 00249 var = dup_vars(ce->var); 00250 ao2_ref(ce, -1); 00251 } else { 00252 var = realtime_switch_common(table, ctx, exten, priority, mode, flags); 00253 do { 00254 struct ast_variable *new; 00255 /* Only cache matches */ 00256 if (mode != MODE_MATCH) { 00257 break; 00258 } 00259 if (!(new = dup_vars(var))) { 00260 break; 00261 } 00262 if (!(ce = ao2_alloc(sizeof(*ce) + strlen(exten) + strlen(context), free_entry))) { 00263 ast_variables_destroy(new); 00264 break; 00265 } 00266 ce->context = ce->exten + strlen(exten) + 1; 00267 strcpy(ce->exten, exten); /* SAFE */ 00268 strcpy(ce->context, context); /* SAFE */ 00269 ce->priority = priority; 00270 ce->var = new; 00271 ce->when = ast_tvnow(); 00272 ao2_link(cache, ce); 00273 pthread_kill(cleanup_thread, SIGURG); 00274 ao2_ref(ce, -1); 00275 } while (0); 00276 } 00277 } 00278 return var; 00279 }
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 301 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.
00302 { 00303 int res = -1; 00304 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH); 00305 00306 if (var) { 00307 char *tmp=""; 00308 char *app = NULL; 00309 struct ast_variable *v; 00310 00311 for (v = var; v ; v = v->next) { 00312 if (!strcasecmp(v->name, "app")) 00313 app = ast_strdupa(v->value); 00314 else if (!strcasecmp(v->name, "appdata")) { 00315 if (ast_compat_pbx_realtime) { 00316 char *ptr; 00317 int in = 0; 00318 tmp = alloca(strlen(v->value) * 2 + 1); 00319 for (ptr = tmp; *v->value; v->value++) { 00320 if (*v->value == ',') { 00321 *ptr++ = '\\'; 00322 *ptr++ = ','; 00323 } else if (*v->value == '|' && !in) { 00324 *ptr++ = ','; 00325 } else { 00326 *ptr++ = *v->value; 00327 } 00328 00329 /* Don't escape '|', meaning 'or', inside expressions ($[ ]) */ 00330 if (v->value[0] == '[' && v->value[-1] == '$') { 00331 in++; 00332 } else if (v->value[0] == ']' && in) { 00333 in--; 00334 } 00335 } 00336 *ptr = '\0'; 00337 } else { 00338 tmp = ast_strdupa(v->value); 00339 } 00340 } 00341 } 00342 ast_variables_destroy(var); 00343 if (!ast_strlen_zero(app)) { 00344 struct ast_app *a = pbx_findapp(app); 00345 if (a) { 00346 char appdata[512]; 00347 char tmp1[80]; 00348 char tmp2[80]; 00349 char tmp3[EXT_DATA_SIZE]; 00350 00351 appdata[0] = 0; /* just in case the substitute var func isn't called */ 00352 if(!ast_strlen_zero(tmp)) 00353 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1); 00354 ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n", 00355 chan->exten, chan->context, chan->priority, 00356 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)), 00357 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)), 00358 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3))); 00359 manager_event(EVENT_FLAG_DIALPLAN, "Newexten", 00360 "Channel: %s\r\n" 00361 "Context: %s\r\n" 00362 "Extension: %s\r\n" 00363 "Priority: %d\r\n" 00364 "Application: %s\r\n" 00365 "AppData: %s\r\n" 00366 "Uniqueid: %s\r\n", 00367 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid); 00368 00369 res = pbx_exec(chan, a, appdata); 00370 } else 00371 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context); 00372 } else { 00373 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context); 00374 } 00375 } 00376 return res; 00377 }
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 281 of file pbx_realtime.c.
References ast_variables_destroy(), MODE_MATCH, realtime_common(), and var.
00282 { 00283 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH); 00284 if (var) { 00285 ast_variables_destroy(var); 00286 return 1; 00287 } 00288 return 0; 00289 }
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 379 of file pbx_realtime.c.
References ast_variables_destroy(), MODE_MATCHMORE, realtime_common(), and var.
00380 { 00381 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE); 00382 if (var) { 00383 ast_variables_destroy(var); 00384 return 1; 00385 } 00386 return 0; 00387 }
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 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 399 of file pbx_realtime.c.
References ao2_ref, ast_unregister_switch(), cache, cleanup_thread, and realtime_switch.
00400 { 00401 ast_unregister_switch(&realtime_switch); 00402 pthread_cancel(cleanup_thread); 00403 pthread_kill(cleanup_thread, SIGURG); 00404 pthread_join(cleanup_thread, NULL); 00405 /* Destroy all remaining entries */ 00406 ao2_ref(cache, -1); 00407 return 0; 00408 }
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 425 of file pbx_realtime.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 425 of file pbx_realtime.c.
struct ao2_container* cache |
Definition at line 78 of file pbx_realtime.c.
Referenced by cleanup(), event_update_cache(), load_module(), realtime_common(), and unload_module().
pthread_t cleanup_thread = 0 |
Definition at line 79 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] |