LBDING-15

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@14917 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Brian West 2009-09-18 14:37:43 +00:00
parent 2261b687af
commit 305cb9a2db
1 changed files with 268 additions and 1 deletions

View File

@ -128,6 +128,8 @@ struct mdl_profile {
char *odbc_dsn;
char *odbc_user;
char *odbc_pass;
switch_bool_t purge;
switch_thread_rwlock_t *rwlock;
switch_odbc_handle_t *master_odbc;
switch_mutex_t *mutex;
ldl_handle_t *handle;
@ -215,6 +217,8 @@ static ldl_status handle_response(ldl_handle_t *handle, char *id);
static switch_status_t load_config(void);
static int sin_callback(void *pArg, int argc, char **argv, char **columnNames);
static switch_status_t soft_reload(void);
#define is_special(s) (s && (strstr(s, "ext+") || strstr(s, "user+")))
static char *translate_rpid(char *in, char *ext)
@ -1241,6 +1245,15 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session)
if (switch_core_codec_ready(&tech_pvt->write_codec)) {
switch_core_codec_destroy(&tech_pvt->write_codec);
}
switch_thread_rwlock_unlock(tech_pvt->profile->rwlock);
if(tech_pvt->profile->purge) {
mdl_profile_t *profile = tech_pvt->profile;
if(switch_core_hash_delete(globals.profile_hash, profile->name) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Profile %s deleted successfully\n", profile->name);
}
}
}
return SWITCH_STATUS_SUCCESS;
@ -1673,6 +1686,18 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
}
}
if(mdl_profile->purge) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile '%s' is marked for deletion, disallowing outgoing call\n", mdl_profile->name);
terminate_session(new_session, __LINE__, SWITCH_CAUSE_NORMAL_UNSPECIFIED);
return SWITCH_CAUSE_NORMAL_UNSPECIFIED;
}
if(switch_thread_rwlock_tryrdlock(mdl_profile->rwlock) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't do read lock on profile '%s'\n", mdl_profile->name);
terminate_session(new_session, __LINE__, SWITCH_CAUSE_NORMAL_UNSPECIFIED);
return SWITCH_CAUSE_NORMAL_UNSPECIFIED;
}
if (!ldl_handle_ready(mdl_profile->handle)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_DEBUG, "Doh! we are not logged in yet!\n");
terminate_session(new_session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
@ -1845,7 +1870,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dingaling_load)
#define LOGOUT_SYNTAX "dl_logout <profile_name>"
#define LOGIN_SYNTAX "Existing Profile:\ndl_login profile=<profile_name>\nDynamic Profile:\ndl_login var1=val1;var2=val2;varN=valN\n"
#define DEBUG_SYNTAX "dl_debug [true|false]"
#define DINGALING_SYNTAX "dingaling [status]"
#define DINGALING_SYNTAX "dingaling [status|reload]"
SWITCH_ADD_API(api_interface, "dl_debug", "DingaLing Debug", dl_debug, DEBUG_SYNTAX);
SWITCH_ADD_API(api_interface, "dl_pres", "DingaLing Presence", dl_pres, PRES_SYNTAX);
@ -1905,6 +1930,9 @@ static switch_status_t init_profile(mdl_profile_t *profile, uint8_t login)
profile->password,
profile->server,
profile->user_flags, profile->message, handle_loop, handle_signalling, handle_response, profile) == LDL_STATUS_SUCCESS) {
profile->purge = SWITCH_FALSE;
switch_thread_rwlock_create(&profile->rwlock, module_pool);
profile->handle = handle;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Started Thread for %s@%s\n", profile->login, profile->dialplan);
switch_core_hash_insert(globals.profile_hash, profile->name, profile);
@ -2161,6 +2189,9 @@ SWITCH_STANDARD_API(dingaling)
}
stream->write_function(stream, "\n");
}
} else if (argv[0] && !strncasecmp(argv[0], "reload", 6)) {
soft_reload();
stream->write_function(stream, "OK\n");
} else {
stream->write_function(stream, "USAGE: %s\n", DINGALING_SYNTAX);
}
@ -2237,6 +2268,229 @@ SWITCH_STANDARD_API(dl_login)
return status;
}
static switch_bool_t match_profile(mdl_profile_t *profile, mdl_profile_t *new_profile)
{
if(profile == new_profile) {
return SWITCH_TRUE;
}
if(
((!new_profile->name && !profile->name) ||
(new_profile->name && profile->name && !strcasecmp(new_profile->name, profile->name))) &&
((!new_profile->login && !profile->login) ||
(new_profile->login && profile->login && !strcasecmp(new_profile->login, profile->login))) &&
((!new_profile->password && !profile->password) ||
(new_profile->password && profile->password && !strcasecmp(new_profile->password, profile->password))) &&
((!new_profile->message && !profile->message) ||
(new_profile->message && profile->message && !strcasecmp(new_profile->message, profile->message))) &&
((!new_profile->avatar && !profile->avatar) ||
(new_profile->avatar && profile->avatar && !strcasecmp(new_profile->avatar, profile->avatar))) &&
#ifdef AUTO_REPLY
((!new_profile->auto_reply && !profile->auto_reply) ||
(new_profile->auto_reply && profile->auto_reply && !strcasecmp(new_profile->auto_reply, profile->auto_reply))) &&
#endif
((!new_profile->dialplan && !profile->dialplan) ||
(new_profile->dialplan && profile->dialplan && !strcasecmp(new_profile->dialplan, profile->dialplan))) &&
((!new_profile->local_network && !profile->local_network) ||
(new_profile->local_network && profile->local_network && !strcasecmp(new_profile->local_network, profile->local_network))) &&
((!new_profile->ip && !profile->ip) ||
(new_profile->ip && profile->ip && !strcasecmp(new_profile->ip, profile->ip))) &&
((!new_profile->extip && !profile->extip) ||
(new_profile->extip && profile->extip && !strcasecmp(new_profile->extip, profile->extip))) &&
((!new_profile->server && !profile->server) ||
(new_profile->server && profile->server && !strcasecmp(new_profile->server, profile->server))) &&
((!new_profile->timer_name && !profile->timer_name) ||
(new_profile->timer_name && profile->timer_name && !strcasecmp(new_profile->timer_name, profile->timer_name))) &&
((!new_profile->lanaddr && !profile->lanaddr) ||
(new_profile->lanaddr && profile->lanaddr && !strcasecmp(new_profile->lanaddr, profile->lanaddr))) &&
((!new_profile->exten && !profile->exten) ||
(new_profile->exten && profile->exten && !strcasecmp(new_profile->exten, profile->exten))) &&
((!new_profile->context && !profile->context) ||
(new_profile->context && profile->context && !strcasecmp(new_profile->context, profile->context))) &&
(new_profile->user_flags == profile->user_flags) && (new_profile->acl_count == profile->acl_count)
) {
if (switch_odbc_available()) {
if(!(
((!new_profile->odbc_dsn && !profile->odbc_dsn) ||
(new_profile->odbc_dsn && profile->odbc_dsn && !strcasecmp(new_profile->odbc_dsn, profile->odbc_dsn))) &&
((!new_profile->odbc_user && !profile->odbc_user) ||
(new_profile->odbc_user && profile->odbc_user && !strcasecmp(new_profile->odbc_user, profile->odbc_user))) &&
((!new_profile->odbc_pass && !profile->odbc_pass) ||
(new_profile->odbc_pass && profile->odbc_pass && !strcasecmp(new_profile->odbc_pass, profile->odbc_pass)))
)) {
return SWITCH_FALSE;
}
}
for(int i=0; i<new_profile->acl_count; i++) {
if(strcasecmp(new_profile->acl[i], profile->acl[i]) != 0) {
return SWITCH_FALSE;
}
}
}
return SWITCH_TRUE;
}
static switch_status_t destroy_profile(char *name)
{
mdl_profile_t *profile = NULL;
if((profile = switch_core_hash_find(globals.profile_hash, name))) {
if (profile->user_flags & LDL_FLAG_COMPONENT) {
if (switch_odbc_available() && profile->odbc_dsn && profile->master_odbc) {
switch_odbc_handle_disconnect(profile->master_odbc);
switch_odbc_handle_destroy(&profile->master_odbc);
}
switch_mutex_destroy(profile->mutex);
}
if(switch_thread_rwlock_trywrlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Profile %s is busy\n", profile->name);
profile->purge = SWITCH_TRUE;
if(profile->handle) {
ldl_handle_stop(profile->handle);
}
} else {
switch_thread_rwlock_unlock(profile->rwlock);
profile->purge = SWITCH_TRUE;
if(profile->handle) {
ldl_handle_stop(profile->handle);
}
if(switch_core_hash_delete(globals.profile_hash, profile->name) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Profile %s deleted successfully\n", profile->name);
}
}
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t soft_reload(void)
{
char *cf = "dingaling.conf";
mdl_profile_t *profile = NULL, *old_profile = NULL;
switch_xml_t cfg, xml, /*settings,*/ param, xmlint;
void *data = NULL;
switch_hash_t *name_hash;
switch_core_hash_init(&name_hash, module_pool);
if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
return SWITCH_STATUS_TERM;
}
if (!(xmlint = switch_xml_child(cfg, "profile"))) {
if ((xmlint = switch_xml_child(cfg, "interface"))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "!!!!!!! DEPRICATION WARNING 'interface' is now 'profile' !!!!!!!\n");
}
}
for (; xmlint; xmlint = xmlint->next) {
char *type = (char *) switch_xml_attr_soft(xmlint, "type");
for (param = switch_xml_child(xmlint, "param"); param; param = param->next) {
char *var = (char *) switch_xml_attr_soft(param, "name");
char *val = (char *) switch_xml_attr_soft(param, "value");
if (!profile) {
profile = switch_core_alloc(module_pool, sizeof(*profile));
}
set_profile_val(profile, var, val);
}
if (profile && type && !strcasecmp(type, "component")) {
char dbname[256];
switch_core_db_t *db;
if (!profile->login && profile->name) {
profile->login = switch_core_strdup(module_pool, profile->name);
}
switch_set_flag(profile, TFLAG_AUTO);
profile->message = "";
profile->user_flags |= LDL_FLAG_COMPONENT;
switch_mutex_init(&profile->mutex, SWITCH_MUTEX_NESTED, module_pool);
switch_snprintf(dbname, sizeof(dbname), "dingaling_%s", profile->name);
profile->dbname = switch_core_strdup(module_pool, dbname);
if (switch_odbc_available() && profile->odbc_dsn) {
if (!(profile->master_odbc = switch_odbc_handle_new(profile->odbc_dsn, profile->odbc_user, profile->odbc_pass))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open ODBC Database!\n");
continue;
}
if (switch_odbc_handle_connect(profile->master_odbc) != SWITCH_ODBC_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open ODBC Database!\n");
continue;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected ODBC DSN: %s\n", profile->odbc_dsn);
switch_odbc_handle_exec(profile->master_odbc, sub_sql, NULL);
//mdl_execute_sql(profile, sub_sql, NULL);
} else {
if ((db = switch_core_db_open_file(profile->dbname))) {
switch_core_db_test_reactive(db, "select * from jabber_subscriptions", NULL, sub_sql);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n");
continue;
}
switch_core_db_close(db);
}
}
if (profile) {
switch_core_hash_insert(name_hash, profile->name, profile->login);
if((old_profile = switch_core_hash_find(globals.profile_hash, profile->name))) {
if(match_profile(old_profile, profile)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found pre-existing profile %s [%s]\n", profile->name, profile->login);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Overwriting pre-existing profile %s [%s]\n", profile->name, profile->login);
destroy_profile(old_profile->name);
init_profile(profile, switch_test_flag(profile, TFLAG_AUTO) ? 1 : 0);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found new profile %s [%s]\n", profile->name, profile->login);
init_profile(profile, switch_test_flag(profile, TFLAG_AUTO) ? 1 : 0);
}
profile = NULL;
}
}
switch_xml_free(xml);
for (switch_hash_index_t *hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, NULL, NULL, &data);
profile = (mdl_profile_t *) data;
if(switch_core_hash_find(name_hash, profile->name)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "New profile %s [%s] activated\n", profile->name, profile->login);
} else {
switch_core_hash_insert(name_hash, profile->name, profile->name);
}
}
for (switch_hash_index_t *hi = switch_hash_first(NULL, name_hash); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, NULL, NULL, &data);
if((profile = switch_core_hash_find(globals.profile_hash, (char*)data))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleting unused profile %s [%s]\n", profile->name, profile->login);
destroy_profile(profile->name);
}
}
switch_core_hash_destroy(&name_hash);
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t load_config(void)
{
char *cf = "dingaling.conf";
@ -2672,6 +2926,19 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
status = LDL_STATUS_FALSE;
goto done;
}
if(profile->purge) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile '%s' is marked for deletion, disallowing incoming call\n", profile->name);
status = LDL_STATUS_FALSE;
goto done;
}
if(switch_thread_rwlock_tryrdlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't do read lock on profile '%s'\n", profile->name);
status = LDL_STATUS_FALSE;
goto done;
}
if ((session = switch_core_session_request(dingaling_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL)) != 0) {
switch_core_session_add_stream(session, NULL);