* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
* Emmanuel Schmidbauer <eschmidbauer@gmail.com>
+ * Andrey Volk <andywolk@gmail.com>
*
*
* switch_core_sqldb.c -- Main Core Library (statistics tracker)
static void switch_core_sqldb_start_thread(void);
static void switch_core_sqldb_stop_thread(void);
+#define database_interface_handle_callback_exec(database_interface, dih, sql, callback, pdata, err) database_interface->callback_exec_detailed(__FILE__, (char *)__SWITCH_FUNC__, __LINE__, dih, sql, callback, pdata, err)
+#define database_interface_handle_exec(database_interface, dih, sql, err) database_interface->exec_detailed(__FILE__, (char *)__SWITCH_FUNC__, __LINE__, dih, sql, err)
+
static switch_cache_db_handle_t *create_handle(switch_cache_db_handle_type_t type)
{
switch_cache_db_handle_t *new_dbh = NULL;
switch_mutex_unlock(sql_manager.dbh_mutex);
}
+SWITCH_DECLARE(void) switch_cache_db_database_interface_flush_handles(switch_database_interface_t *database_interface)
+{
+ switch_cache_db_handle_t *dbh_ptr = NULL;
+
+ switch_mutex_lock(sql_manager.dbh_mutex);
+
+ for (dbh_ptr = sql_manager.handle_pool; dbh_ptr; dbh_ptr = dbh_ptr->next) {
+ if (switch_mutex_trylock(dbh_ptr->mutex) == SWITCH_STATUS_SUCCESS) {
+ if (dbh_ptr->type != SCDB_TYPE_DATABASE_INTERFACE) {
+ continue;
+ }
+
+ if (dbh_ptr->native_handle.database_interface_dbh->connection_options.database_interface != database_interface) {
+ continue;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Dropping DB connection %s\n", dbh_ptr->name);
+
+ database_interface->handle_destroy(&dbh_ptr->native_handle.database_interface_dbh);
+
+ del_handle(dbh_ptr);
+ switch_mutex_unlock(dbh_ptr->mutex);
+ switch_core_destroy_memory_pool(&dbh_ptr->pool);
+ }
+ }
+
+ switch_mutex_unlock(sql_manager.dbh_mutex);
+}
+
static switch_cache_db_handle_t *get_handle(const char *db_str, const char *user_str, const char *thread_str)
{
switch_ssize_t hlen = -1;
if (!r) {
for (dbh_ptr = sql_manager.handle_pool; dbh_ptr; dbh_ptr = dbh_ptr->next) {
- if (dbh_ptr->hash == hash && (dbh_ptr->type != SCDB_TYPE_PGSQL || !dbh_ptr->use_count) && !switch_test_flag(dbh_ptr, CDF_PRUNE) &&
+ if (dbh_ptr->hash == hash && ((dbh_ptr->type != SCDB_TYPE_PGSQL && dbh_ptr->type != SCDB_TYPE_DATABASE_INTERFACE) || !dbh_ptr->use_count) && !switch_test_flag(dbh_ptr, CDF_PRUNE) &&
switch_mutex_trylock(dbh_ptr->mutex) == SWITCH_STATUS_SUCCESS) {
r = dbh_ptr;
break;
dsn = "core";
}
- if ((r = _switch_cache_db_get_db_handle_dsn(dbh, dsn, file, func, line)) != SWITCH_STATUS_SUCCESS) {
+ if ((r = _switch_cache_db_get_db_handle_dsn_ex(dbh, dsn, SWITCH_TRUE, file, func, line)) != SWITCH_STATUS_SUCCESS) {
*dbh = NULL;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Dropping idle DB connection %s\n", dbh->name);
switch (dbh->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ database_interface->handle_destroy(&dbh->native_handle.database_interface_dbh);
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_handle_destroy(&dbh->native_handle.pgsql_dbh);
if (dbh && *dbh) {
switch((*dbh)->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = (*dbh)->native_handle.database_interface_dbh->connection_options.database_interface;
+ database_interface->flush((*dbh)->native_handle.database_interface_dbh);
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_flush((*dbh)->native_handle.pgsql_dbh);
switch_cache_db_release_db_handle(dbh);
}
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+SWITCH_DECLARE(switch_status_t) switch_core_check_core_db_dsn()
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+ switch_database_interface_t *database_interface;
+
+ if (!runtime.odbc_dsn) {
+ status = SWITCH_STATUS_SUCCESS;
+ } else {
+ char *colon_slashes = NULL;
+ if (NULL != (colon_slashes = strstr(runtime.odbc_dsn, "://")))
+ {
+ char prefix[16] = "";
+ strncpy(prefix, runtime.odbc_dsn, MIN(colon_slashes - runtime.odbc_dsn, 15));
+
+ if (!strncasecmp(prefix, "odbc", 4)) {
+ if (switch_odbc_available()) status = SWITCH_STATUS_SUCCESS;
+ }
+ else if (!strncasecmp(prefix, "sqlite", 6)) {
+ status = SWITCH_STATUS_SUCCESS;
+ }
+ else if (!strncasecmp(prefix, "pgsql", 5)) {
+ if (switch_pgsql_available()) status = SWITCH_STATUS_SUCCESS;
+ }
+ else if ((database_interface = switch_loadable_module_get_database_interface(prefix, NULL))) {
+ status = SWITCH_STATUS_SUCCESS;
+ UNPROTECT_INTERFACE(database_interface);
+ }
+ }
+ else if (strchr(runtime.odbc_dsn + 2, ':')) {
+ status = SWITCH_STATUS_SUCCESS;
+ }
+ }
+
+ return status;
+}
SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle_dsn(switch_cache_db_handle_t **dbh, const char *dsn,
+ const char *file, const char *func, int line)
+{
+ return _switch_cache_db_get_db_handle_dsn_ex(dbh, dsn, SWITCH_FALSE, file, func, line);
+}
+
+SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle_dsn_ex(switch_cache_db_handle_t **dbh, const char *dsn, switch_bool_t make_module_no_unloadable,
const char *file, const char *func, int line)
{
switch_cache_db_connection_options_t connection_options = { {0} };
switch_cache_db_handle_type_t type;
+ switch_database_interface_t *database_interface = NULL;
char tmp[256] = "";
char *p;
switch_status_t status = SWITCH_STATUS_FALSE;
int i;
- if (!strncasecmp(dsn, "pgsql://", 8)) {
- type = SCDB_TYPE_PGSQL;
- connection_options.pgsql_options.dsn = (char *)(dsn + 8);
- } else if (!strncasecmp(dsn, "sqlite://", 9)) {
- type = SCDB_TYPE_CORE_DB;
- connection_options.core_db_options.db_path = (char *)(dsn + 9);
- } else if ((!(i = strncasecmp(dsn, "odbc://", 7))) || strchr(dsn+2, ':')) {
- type = SCDB_TYPE_ODBC;
-
- if (i) {
- switch_set_string(tmp, dsn);
- } else {
- switch_set_string(tmp, dsn+7);
+ char *colon_slashes = NULL;
+ if ( NULL != (colon_slashes = strstr(dsn, "://")) )
+ {
+ char prefix[16] = "";
+ strncpy(prefix, dsn, MIN(colon_slashes - dsn, 15));
+
+ if ((database_interface = switch_loadable_module_get_database_interface(prefix, NULL))) {
+ type = SCDB_TYPE_DATABASE_INTERFACE;
+ connection_options.database_interface_options.make_module_no_unloadable = make_module_no_unloadable;
+ connection_options.database_interface_options.database_interface = database_interface;
+ connection_options.database_interface_options.dsn = colon_slashes + 3;
+ strcpy(connection_options.database_interface_options.prefix, prefix);
+ UNPROTECT_INTERFACE(database_interface);
}
+ }
+
+ if (!connection_options.database_interface_options.dsn)
+ {
+ if (!strncasecmp(dsn, "pgsql://", 8)) {
+ type = SCDB_TYPE_PGSQL;
+ connection_options.pgsql_options.dsn = (char *)(dsn + 8);
+ }
+ else if (!strncasecmp(dsn, "sqlite://", 9)) {
+ type = SCDB_TYPE_CORE_DB;
+ connection_options.core_db_options.db_path = (char *)(dsn + 9);
+ }
+ else if ((!(i = strncasecmp(dsn, "odbc://", 7))) || (strchr(dsn + 2, ':') && !colon_slashes)) {
+ type = SCDB_TYPE_ODBC;
- connection_options.odbc_options.dsn = tmp;
+ if (i) {
+ switch_set_string(tmp, dsn);
+ }
+ else {
+ switch_set_string(tmp, dsn + 7);
+ }
- if ((p = strchr(tmp, ':'))) {
- *p++ = '\0';
- connection_options.odbc_options.user = p;
+ connection_options.odbc_options.dsn = tmp;
- if ((p = strchr(connection_options.odbc_options.user, ':'))) {
+ if ((p = strchr(tmp, ':'))) {
*p++ = '\0';
- connection_options.odbc_options.pass = p;
+ connection_options.odbc_options.user = p;
+
+ if ((p = strchr(connection_options.odbc_options.user, ':'))) {
+ *p++ = '\0';
+ connection_options.odbc_options.pass = p;
+ }
}
}
- } else {
- type = SCDB_TYPE_CORE_DB;
- connection_options.core_db_options.db_path = (char *)dsn;
+ else {
+ type = SCDB_TYPE_CORE_DB;
+ connection_options.core_db_options.db_path = (char *)dsn;
+ }
}
status = _switch_cache_db_get_db_handle(dbh, type, &connection_options, file, func, line);
}
switch (type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ db_name = connection_options->database_interface_options.dsn;
+ odbc_user = NULL;
+ odbc_pass = NULL;
+ db_type = "database_interface";
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
db_name = connection_options->pgsql_options.dsn;
odbc_pass = NULL;
db_type = "pgsql";
}
+ break;
case SCDB_TYPE_ODBC:
{
db_name = connection_options->odbc_options.dsn;
snprintf(thread_str, sizeof(thread_str) - 1, "thread=\"%lu\"", (unsigned long) (intptr_t) self);
if ((new_dbh = get_handle(db_str, db_callsite_str, thread_str))) {
- switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10,
- "Reuse Unused Cached DB handle %s [%s]\n", new_dbh->name, switch_cache_db_type_name(new_dbh->type));
+ if (type == SCDB_TYPE_DATABASE_INTERFACE) {
+ switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10,
+ "Reuse Unused Cached DB handle %s [Database interface prefix: %s]\n", new_dbh->name, connection_options->database_interface_options.prefix);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10,
+ "Reuse Unused Cached DB handle %s [%s]\n", new_dbh->name, switch_cache_db_type_name(new_dbh->type));
+ }
} else {
switch_core_db_t *db = NULL;
switch_odbc_handle_t *odbc_dbh = NULL;
switch_pgsql_handle_t *pgsql_dbh = NULL;
+ switch_database_interface_handle_t *database_interface_dbh = NULL;
switch (type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = connection_options->database_interface_options.database_interface;
+
+ if (SWITCH_STATUS_SUCCESS != database_interface->handle_new(connection_options->database_interface_options.dsn, &database_interface_dbh)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! Can't create new handle! Can't connect to DSN %s\n", connection_options->database_interface_options.dsn);
+ goto end;
+ }
+
+ if (database_interface_dbh) {
+ database_interface_dbh->connection_options = connection_options->database_interface_options;
+
+ if (connection_options->database_interface_options.make_module_no_unloadable == SWITCH_TRUE)
+ {
+ PROTECT_INTERFACE(database_interface)
+ switch_loadable_module_protect(database_interface->parent->module_name);
+ UNPROTECT_INTERFACE(database_interface)
+ }
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
if (!switch_pgsql_available()) {
break;
case SCDB_TYPE_ODBC:
{
-
if (!switch_odbc_available()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! ODBC NOT AVAILABLE! Can't connect to DSN %s\n", connection_options->odbc_options.dsn);
goto end;
switch_odbc_handle_destroy(&odbc_dbh);
}
}
-
-
}
break;
case SCDB_TYPE_CORE_DB:
goto end;
}
- if (!db && !odbc_dbh && !pgsql_dbh) {
+ if (!db && !odbc_dbh && !pgsql_dbh && !database_interface_dbh) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure to connect to %s %s!\n", switch_cache_db_type_name(type), db_name);
goto end;
}
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10,
"Create Cached DB handle %s [%s] %s:%d\n", new_dbh->name, switch_cache_db_type_name(type), file, line);
- if (db) {
+ if (database_interface_dbh) {
+ new_dbh->native_handle.database_interface_dbh = database_interface_dbh;
+ } else if (db) {
new_dbh->native_handle.core_db_dbh = db;
} else if (odbc_dbh) {
new_dbh->native_handle.odbc_dbh = odbc_dbh;
}
switch (dbh->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ type = (char *)dbh->native_handle.database_interface_dbh->connection_options.prefix;
+ status = database_interface_handle_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, &errmsg);
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
type = "PGSQL";
return switch_odbc_handle_affected_rows(dbh->native_handle.odbc_dbh);
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ int affected_rows = 0;
+ database_interface->affected_rows(dbh->native_handle.database_interface_dbh, &affected_rows);
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
return switch_pgsql_handle_affected_rows(dbh->native_handle.pgsql_dbh);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "load extension not supported by type ODBC!\n");
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "load extension not supported by type DATABASE_INTERFACE!\n");
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "load extension not supported by type PGSQL!\n");
status = switch_odbc_handle_exec_string(dbh->native_handle.odbc_dbh, sql, str, len, err);
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ status = database_interface->exec_string(dbh->native_handle.database_interface_dbh, sql, str, len, err);
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
status = switch_pgsql_handle_exec_string(dbh->native_handle.pgsql_dbh, sql, str, len, err);
}
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface->sql_set_auto_commit_attr(dbh->native_handle.database_interface_dbh, 0)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to Set AutoCommit Off", result);
+ errmsg = strdup(tmp);
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_status_t result;
switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface->commit(dbh->native_handle.database_interface_dbh)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to commit transaction", result);
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_SQLEndTran(dbh->native_handle.pgsql_dbh, 1);
switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface->commit(dbh->native_handle.database_interface_dbh)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to commit transaction", result);
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_SQLEndTran(dbh->native_handle.pgsql_dbh, 1);
h.pdata = pdata;
switch (dbh->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface_handle_callback_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, helper_callback, &h, err)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to execute_sql_event_callback", result);
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, helper_callback, &h, err);
h.pdata = pdata;
switch (dbh->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface_handle_callback_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, helper_callback, &h, err)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to execute_sql_event_callback_err", result);
+ } else {
+ if (err && *err) {
+ (*err_callback)(pdata, (const char*)*err);
+ }
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, helper_callback, &h, err);
switch (dbh->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface_handle_callback_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, callback, pdata, err)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to execute_sql_callback", result);
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, callback, pdata, err);
switch (dbh->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface_handle_callback_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, callback, pdata, err)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to execute_sql_callback_err", result);
+ } else {
+ if (err && *err) {
+ (*err_callback)(pdata, (const char*)*err);
+ }
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, callback, pdata, err);
if (io_mutex) switch_mutex_lock(io_mutex);
switch (dbh->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface_handle_exec(database_interface, dbh->native_handle.database_interface_dbh, test_sql, NULL)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to test_reactive with test_sql", result);
+
+ if (drop_sql) {
+ if ((result = database_interface_handle_exec(database_interface, dbh->native_handle.database_interface_dbh, drop_sql, NULL)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to test_reactive with drop_sql", result);
+ }
+
+ if ((result = database_interface_handle_exec(database_interface, dbh->native_handle.database_interface_dbh, reactive_sql, NULL)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to test_reactive with reactive_sql", result);
+ }
+
+ r = result;
+ }
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
if (switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, test_sql, NULL) != SWITCH_PGSQL_SUCCESS) {
}
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = qm->event_db->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface->sql_set_auto_commit_attr(qm->event_db->native_handle.database_interface_dbh, 0)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to Set AutoCommit Off", result);
+ errmsg = strdup(tmp);
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_status_t result;
switch_odbc_SQLSetAutoCommitAttr(qm->event_db->native_handle.odbc_dbh, 1);
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = qm->event_db->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface->commit(qm->event_db->native_handle.database_interface_dbh)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to commit transaction", result);
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_SQLEndTran(qm->event_db->native_handle.pgsql_dbh, 1);
switch_mutex_lock(qm->cond_mutex);
switch (qm->event_db->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ break;
case SCDB_TYPE_PGSQL:
break;
case SCDB_TYPE_ODBC:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening DB\n");
switch (sql_manager.dbh->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
case SCDB_TYPE_PGSQL:
case SCDB_TYPE_ODBC:
if (switch_test_flag((&runtime), SCF_CLEAR_SQL)) {
switch (sql_manager.dbh->type) {
+ case SCDB_TYPE_DATABASE_INTERFACE:
case SCDB_TYPE_PGSQL:
case SCDB_TYPE_ODBC:
{
}
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = sql_manager.dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface->sql_set_auto_commit_attr(sql_manager.dbh->native_handle.database_interface_dbh, 0)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to Set AutoCommit Off", result);
+ err = strdup(tmp);
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_status_t result;
}
}
break;
+ case SCDB_TYPE_DATABASE_INTERFACE:
+ {
+ switch_database_interface_t *database_interface = sql_manager.dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+ switch_status_t result;
+
+ if ((result = database_interface->commit(sql_manager.dbh->native_handle.database_interface_dbh)) != SWITCH_STATUS_SUCCESS) {
+ char tmp[100];
+ switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to commit transaction", result);
+ err = strdup(tmp);
+ }
+ }
+ break;
case SCDB_TYPE_PGSQL:
{
if (switch_pgsql_SQLEndTran(sql_manager.dbh->native_handle.pgsql_dbh, 1) != SWITCH_PGSQL_SUCCESS ||
*
* Anthony Minessale II <anthm@freeswitch.org>
* Seven Du <dujinfang@gmail.com>
+ * Andrey Volk <andywolk@gmail.com>
*
* switch_loadable_module.c -- Loadable Modules
*
*/
#include <switch.h>
+#include "private/switch_core_pvt.h"
/* for apr_pstrcat */
#include <apr_strings.h>
struct switch_file_node_s *next;
} switch_file_node_t;
+typedef struct switch_database_node_s {
+ const switch_database_interface_t *ptr;
+ const char *interface_name;
+ struct switch_database_node_s *next;
+} switch_database_node_t;
+
typedef struct switch_codec_node_s {
const switch_codec_interface_t *ptr;
const char *interface_name;
switch_status_t status;
switch_thread_t *thread;
switch_bool_t shutting_down;
+ switch_loadable_module_type_t type;
};
struct switch_loadable_module_container {
switch_hash_t *say_hash;
switch_hash_t *management_hash;
switch_hash_t *limit_hash;
+ switch_hash_t *database_hash;
switch_hash_t *secondary_recover_hash;
switch_mutex_t *mutex;
switch_memory_pool_t *pool;
static struct switch_loadable_module_container loadable_modules;
static switch_status_t do_shutdown(switch_loadable_module_t *module, switch_bool_t shutdown, switch_bool_t unload, switch_bool_t fail_if_busy,
const char **err);
-static switch_status_t switch_loadable_module_load_module_ex(const char *dir, const char *fname, switch_bool_t runtime, switch_bool_t global, const char **err);
+static switch_status_t switch_loadable_module_load_module_ex(const char *dir, const char *fname, switch_bool_t runtime, switch_bool_t global, const char **err, switch_loadable_module_type_t type, switch_hash_t *event_hash);
static void *SWITCH_THREAD_FUNC switch_loadable_module_exec(switch_thread_t *thread, void *obj)
{
switch_mutex_unlock(loadable_modules.mutex);
}
-static switch_status_t switch_loadable_module_process(char *key, switch_loadable_module_t *new_module)
+static switch_status_t switch_loadable_module_process(char *key, switch_loadable_module_t *new_module, switch_hash_t *event_hash)
{
switch_event_t *event;
+ int *event_num = NULL;
+ char str_event_num[10];
+ void *val;
int added = 0;
+ if (event_hash) {
+ if ((val = switch_core_hash_find(event_hash, "0"))) {
+ event_num = (int*)val;
+ } else {
+ if (!(event_num = malloc(sizeof(int)))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Allocation error.\n");
+ return SWITCH_STATUS_MEMERR;
+ }
+
+ *event_num = 0;
+ switch_core_hash_insert(event_hash, "0", (const void*)event_num);
+ }
+ }
+
new_module->key = switch_core_strdup(new_module->pool, key);
switch_mutex_lock(loadable_modules.mutex);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ } else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
}
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
}
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.dialplan_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.timer_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.application_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.chat_application_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.api_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.json_api_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
node = switch_core_alloc(new_module->pool, sizeof(*node));
}
}
+ if (new_module->module_interface->database_interface) {
+ const switch_database_interface_t *ptr;
+
+ for (ptr = new_module->module_interface->database_interface; ptr; ptr = ptr->next) {
+ if (!ptr->interface_name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load database interface from %s due to no interface name.\n", key);
+ }
+ else if (!ptr->prefixes) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load database interface from %s due to no prefixes.\n", key);
+ }
+ else {
+ int i;
+ switch_database_node_t *node, *head;
+
+ for (i = 0; ptr->prefixes[i]; i++) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding dsn prefix '%s'\n", ptr->prefixes[i]);
+ if (switch_event_create(&event, SWITCH_EVENT_MODULE_LOAD) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "database");
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->prefixes[i]);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
+ added++;
+ }
+ node = switch_core_alloc(new_module->pool, sizeof(*node));
+ node->ptr = ptr;
+ node->interface_name = switch_core_strdup(new_module->pool, new_module->module_interface->module_name);
+ if ((head = switch_core_hash_find(loadable_modules.database_hash, ptr->prefixes[i]))) {
+ node->next = head;
+ }
+
+ switch_core_hash_insert(loadable_modules.database_hash, ptr->prefixes[i], (const void *)node);
+ }
+ }
+ }
+ }
+
if (new_module->module_interface->speech_interface) {
const switch_speech_interface_t *ptr;
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.speech_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.asr_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.directory_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.chat_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
switch_core_hash_insert(loadable_modules.say_hash, ptr->interface_name, (const void *) ptr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->relative_oid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
}
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
}
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
- switch_event_fire(&event);
+
+ if (!event_hash) {
+ switch_event_fire(&event);
+ }
+ else {
+ sprintf(str_event_num, "%i", ++*event_num);
+ switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+ }
+
added++;
}
}
}
}
+ if (old_module->module_interface->database_interface) {
+ const switch_database_interface_t *ptr;
+ switch_database_node_t *node, *head, *last = NULL;
+
+ for (ptr = old_module->module_interface->database_interface; ptr; ptr = ptr->next) {
+ if (ptr->interface_name) {
+ int i;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock interface '%s' to wait for existing references.\n",
+ ptr->interface_name);
+
+ if (switch_thread_rwlock_trywrlock_timeout(ptr->rwlock, 10) == SWITCH_STATUS_SUCCESS) {
+ switch_thread_rwlock_unlock(ptr->rwlock);
+ }
+ else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Giving up on '%s' waiting for existing references.\n", ptr->interface_name);
+ }
+
+ for (i = 0; ptr->prefixes[i]; i++) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Deleting dsn prefix '%s'\n", ptr->prefixes[i]);
+ if (switch_event_create(&event, SWITCH_EVENT_MODULE_UNLOAD) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "database");
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->prefixes[i]);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", old_module->module_interface->module_name);
+ switch_event_fire(&event);
+ removed++;
+ }
+
+ if ((head = switch_core_hash_find(loadable_modules.database_hash, ptr->prefixes[i]))) {
+ for (node = head; node; node = node->next) {
+ if (!strcmp(node->interface_name, old_module->module_interface->module_name)) {
+ if (node == head) {
+ if ((node = node->next)) {
+ switch_core_hash_insert(loadable_modules.database_hash, ptr->prefixes[i], (const void *)node);
+ }
+ else {
+ switch_core_hash_delete(loadable_modules.database_hash, ptr->prefixes[i]);
+ }
+ }
+ else {
+ if (last) {
+ last->next = node->next;
+ }
+ }
+ break;
+ }
+ last = node;
+ }
+ }
+ }
+
+ switch_cache_db_database_interface_flush_handles(old_module->module_interface->database_interface);
+ }
+ }
+ }
+
if (old_module->module_interface->speech_interface) {
const switch_speech_interface_t *ptr;
}
SWITCH_DECLARE(switch_status_t) switch_loadable_module_load_module(const char *dir, const char *fname, switch_bool_t runtime, const char **err)
{
- return switch_loadable_module_load_module_ex(dir, fname, runtime, SWITCH_FALSE, err);
+ return switch_loadable_module_load_module_ex(dir, fname, runtime, SWITCH_FALSE, err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, NULL);
}
-static switch_status_t switch_loadable_module_load_module_ex(const char *dir, const char *fname, switch_bool_t runtime, switch_bool_t global, const char **err)
+static switch_status_t switch_loadable_module_load_module_ex(const char *dir, const char *fname, switch_bool_t runtime, switch_bool_t global, const char **err, switch_loadable_module_type_t type, switch_hash_t *event_hash)
{
switch_size_t len = 0;
char *path;
*err = "Module already loaded";
status = SWITCH_STATUS_FALSE;
} else if ((status = switch_loadable_module_load_file(path, file, global, &new_module)) == SWITCH_STATUS_SUCCESS) {
- if ((status = switch_loadable_module_process(file, new_module)) == SWITCH_STATUS_SUCCESS && runtime) {
+ new_module->type = type;
+
+ if ((status = switch_loadable_module_process(file, new_module, event_hash)) == SWITCH_STATUS_SUCCESS && runtime) {
if (new_module->switch_module_runtime) {
new_module->thread = switch_core_launch_thread(switch_loadable_module_exec, new_module, new_module->pool);
}
return status;
}
+SWITCH_DECLARE(switch_status_t) switch_loadable_module_protect(const char *mod)
+{
+ switch_loadable_module_t *module = NULL;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (zstr(mod)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ switch_mutex_lock(loadable_modules.mutex);
+ if ((module = switch_core_hash_find(loadable_modules.module_hash, mod))) {
+ if (!module->perm) {
+ module->perm++;
+ }
+ status = SWITCH_STATUS_SUCCESS;
+ }
+ else {
+ status = SWITCH_STATUS_FALSE;
+ }
+ switch_mutex_unlock(loadable_modules.mutex);
+
+ return status;
+}
+
SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(const char *dir, const char *fname, switch_bool_t force, const char **err)
{
switch_loadable_module_t *module = NULL;
module->thread = switch_core_launch_thread(switch_loadable_module_exec, module, module->pool);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Successfully Loaded [%s]\n", module_interface->module_name);
- return switch_loadable_module_process((char *) module->filename, module);
+ return switch_loadable_module_process((char *) module->filename, module, NULL);
}
#ifdef WIN32
apr_finfo_t finfo = { 0 };
apr_dir_t *module_dir_handle = NULL;
apr_int32_t finfo_flags = APR_FINFO_DIRENT | APR_FINFO_TYPE | APR_FINFO_NAME;
+ char *precf = "pre_load_modules.conf";
char *cf = "modules.conf";
char *pcf = "post_load_modules.conf";
switch_xml_t cfg, xml;
unsigned char all = 0;
unsigned int count = 0;
const char *err;
+ switch_hash_t *event_hash;
+ switch_hash_index_t *hi;
+ void *hash_val;
+ switch_event_t *event;
#ifdef WIN32
switch_core_hash_init_nocase(&loadable_modules.say_hash);
switch_core_hash_init_nocase(&loadable_modules.management_hash);
switch_core_hash_init_nocase(&loadable_modules.limit_hash);
+ switch_core_hash_init_nocase(&loadable_modules.database_hash);
switch_core_hash_init_nocase(&loadable_modules.dialplan_hash);
switch_core_hash_init(&loadable_modules.secondary_recover_hash);
switch_mutex_init(&loadable_modules.mutex, SWITCH_MUTEX_NESTED, loadable_modules.pool);
if (!autoload) return SWITCH_STATUS_SUCCESS;
+
+ /*
+ switch_core_sqldb_init() is not yet ready and is executed after starting modules from pre_load_modules.conf
+ Modules loading procedure generates events used by sqldb.
+ This is why we should hold those events (storing in the event_hash) not firing them until sqldb is ready.
+ */
+ switch_core_hash_init(&event_hash);
- switch_loadable_module_load_module("", "CORE_SOFTTIMER_MODULE", SWITCH_FALSE, &err);
- switch_loadable_module_load_module("", "CORE_PCM_MODULE", SWITCH_FALSE, &err);
- switch_loadable_module_load_module("", "CORE_SPEEX_MODULE", SWITCH_FALSE, &err);
+ switch_loadable_module_load_module_ex("", "CORE_SOFTTIMER_MODULE", SWITCH_FALSE, SWITCH_FALSE, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, event_hash);
+ switch_loadable_module_load_module_ex("", "CORE_PCM_MODULE", SWITCH_FALSE, SWITCH_FALSE, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, event_hash);
+ switch_loadable_module_load_module_ex("", "CORE_SPEEX_MODULE", SWITCH_FALSE, SWITCH_FALSE, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, event_hash);
#ifdef SWITCH_HAVE_YUV
#ifdef SWITCH_HAVE_VPX
- switch_loadable_module_load_module("", "CORE_VPX_MODULE", SWITCH_FALSE, &err);
+ switch_loadable_module_load_module_ex("", "CORE_VPX_MODULE", SWITCH_FALSE, SWITCH_FALSE, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, event_hash);
#endif
#endif
+ if ((xml = switch_xml_open_cfg(precf, &cfg, NULL))) {
+ switch_xml_t mods, ld;
+ if ((mods = switch_xml_child(cfg, "modules"))) {
+ for (ld = switch_xml_child(mods, "load"); ld; ld = ld->next) {
+ switch_bool_t global = SWITCH_FALSE;
+ const char *val = switch_xml_attr_soft(ld, "module");
+ const char *path = switch_xml_attr_soft(ld, "path");
+ const char *critical = switch_xml_attr_soft(ld, "critical");
+ const char *sglobal = switch_xml_attr_soft(ld, "global");
+
+ if (zstr(val) || (strchr(val, '.') && !strstr(val, ext) && !strstr(val, EXT))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Invalid extension for %s\n", val);
+ continue;
+ }
+ global = switch_true(sglobal);
+
+ if (path && zstr(path)) {
+ path = SWITCH_GLOBAL_dirs.mod_dir;
+ }
+ if (switch_loadable_module_load_module_ex((char *)path, (char *)val, SWITCH_FALSE, global, &err, SWITCH_LOADABLE_MODULE_TYPE_PRELOAD, event_hash) == SWITCH_STATUS_GENERR) {
+ if (critical && switch_true(critical)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load critical module '%s', abort()\n", val);
+
+ if ((hash_val = switch_core_hash_find(event_hash, "0"))) {
+ switch_safe_free(hash_val);
+ }
+ switch_core_hash_destroy(&event_hash);
+
+ abort();
+ }
+ }
+ count++;
+ }
+ }
+ switch_xml_free(xml);
+
+ }
+ else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "open of %s failed\n", cf);
+ }
+
+ if (switch_core_sqldb_init(&err) != SWITCH_STATUS_SUCCESS)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Loading modules interrupted. [Error: %s]\n", err);
+ if ((hash_val = switch_core_hash_find(event_hash, "0"))) {
+ switch_safe_free(hash_val);
+ }
+ switch_core_hash_destroy(&event_hash);
+ return SWITCH_STATUS_GENERR;
+ }
+
+ /* sqldb is ready. Fire holding events! */
+ if ((hash_val = switch_core_hash_find(event_hash, "0"))) {
+ switch_safe_free(hash_val);
+ switch_core_hash_delete(event_hash, "0");
+ }
+
+ for (hi = switch_core_hash_first(event_hash); hi; hi = switch_core_hash_next(&hi)) {
+ switch_core_hash_this(hi, NULL, NULL, &hash_val);
+ event = (switch_event_t *)hash_val;
+ switch_event_fire(&event);
+ }
+
+ switch_core_hash_destroy(&event_hash);
+
if ((xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
switch_xml_t mods, ld;
if ((mods = switch_xml_child(cfg, "modules"))) {
if (path && zstr(path)) {
path = SWITCH_GLOBAL_dirs.mod_dir;
}
- if (switch_loadable_module_load_module_ex(path, val, SWITCH_FALSE, global, &err) == SWITCH_STATUS_GENERR) {
+ if (switch_loadable_module_load_module_ex(path, val, SWITCH_FALSE, global, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, NULL) == SWITCH_STATUS_GENERR) {
if (critical && switch_true(critical)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load critical module '%s', abort()\n", val);
abort();
if (path && zstr(path)) {
path = SWITCH_GLOBAL_dirs.mod_dir;
}
- switch_loadable_module_load_module_ex(path, val, SWITCH_FALSE, global, &err);
+ switch_loadable_module_load_module_ex(path, val, SWITCH_FALSE, global, &err, SWITCH_LOADABLE_MODULE_TYPE_POSTLOAD, NULL);
count++;
}
}
{
switch_hash_index_t *hi;
void *val;
+ const void *key;
switch_loadable_module_t *module;
int i;
for (hi = switch_core_hash_first(loadable_modules.module_hash); hi; hi = switch_core_hash_next(&hi)) {
switch_core_hash_this(hi, NULL, NULL, &val);
- module = (switch_loadable_module_t *) val;
- if (!module->perm) {
+ module = (switch_loadable_module_t *)val;
+ if (module->type != SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
do_shutdown(module, SWITCH_TRUE, SWITCH_FALSE, SWITCH_FALSE, NULL);
}
}
switch_yield(1000000);
+ for (hi = switch_core_hash_first(loadable_modules.module_hash); hi;) {
+ switch_core_hash_this(hi, &key, NULL, &val);
+ module = (switch_loadable_module_t *)val;
+
+ hi = switch_core_hash_next(&hi);
+
+ if (module->type != SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
+ if (do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL) == SWITCH_STATUS_SUCCESS)
+ {
+ switch_core_hash_delete(loadable_modules.module_hash, key);
+ }
+ }
+ }
+
+ switch_core_sqldb_destroy();
+
for (hi = switch_core_hash_first(loadable_modules.module_hash); hi; hi = switch_core_hash_next(&hi)) {
switch_core_hash_this(hi, NULL, NULL, &val);
- module = (switch_loadable_module_t *) val;
- if (!module->perm) {
- do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL);
+ if ((module = (switch_loadable_module_t *)val)) {
+ if (module->type == SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
+ do_shutdown(module, SWITCH_TRUE, SWITCH_FALSE, SWITCH_FALSE, NULL);
+ }
+ }
+ }
+
+ switch_yield(1000000);
+
+ for (hi = switch_core_hash_first(loadable_modules.module_hash); hi; hi = switch_core_hash_next(&hi)) {
+ switch_core_hash_this(hi, NULL, NULL, &val);
+ if ((module = (switch_loadable_module_t *)val)) {
+ if (module->type == SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
+ do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL);
+ }
}
}
switch_core_hash_destroy(&loadable_modules.say_hash);
switch_core_hash_destroy(&loadable_modules.management_hash);
switch_core_hash_destroy(&loadable_modules.limit_hash);
+ switch_core_hash_destroy(&loadable_modules.database_hash);
switch_core_hash_destroy(&loadable_modules.dialplan_hash);
switch_core_destroy_memory_pool(&loadable_modules.pool);
return i;
}
+SWITCH_DECLARE(switch_database_interface_t *) switch_loadable_module_get_database_interface(const char *name, const char *modname)
+{
+ switch_database_interface_t *i = NULL;
+ switch_database_node_t *node, *head;
+
+ switch_mutex_lock(loadable_modules.mutex);
+
+ if ((head = switch_core_hash_find(loadable_modules.database_hash, name))) {
+ if (modname) {
+ for (node = head; node; node = node->next) {
+ if (!strcasecmp(node->interface_name, modname)) {
+ i = (switch_database_interface_t *)node->ptr;
+ break;
+ }
+ }
+ }
+ else {
+ i = (switch_database_interface_t *)head->ptr;
+ }
+ }
+
+ switch_mutex_unlock(loadable_modules.mutex);
+
+ if (i) PROTECT_INTERFACE(i);
+
+ return i;
+}
+
SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(const char *name, const char *modname)
{
switch_codec_interface_t *codec = NULL;
case SWITCH_LIMIT_INTERFACE:
ALLOC_INTERFACE(limit)
+ case SWITCH_DATABASE_INTERFACE:
+ ALLOC_INTERFACE(database)
+
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Module Type!\n");
return NULL;