diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index 8f8076a5bf..6057734123 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -24,6 +24,7 @@ * Contributor(s): * * Anthony Minessale II + * Andrey Volk * * * switch_core.h -- Core Library Private Data (not to be installed into the system) @@ -334,6 +335,8 @@ extern struct switch_session_manager session_manager; +switch_status_t switch_core_sqldb_init(const char **err); +void switch_core_sqldb_destroy(); switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_t manage); void switch_core_sqldb_stop(void); void switch_core_session_init(switch_memory_pool_t *pool); diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 7631fc287f..e82690dfef 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -27,6 +27,7 @@ * Luke Dashjr (OpenMethods, LLC) * Joseph Sullivan * Emmanuel Schmidbauer + * Andrey Volk * * switch_core.h -- Core Library * @@ -2474,13 +2475,15 @@ typedef enum { typedef enum { SCDB_TYPE_CORE_DB, SCDB_TYPE_ODBC, - SCDB_TYPE_PGSQL + SCDB_TYPE_PGSQL, + SCDB_TYPE_DATABASE_INTERFACE } switch_cache_db_handle_type_t; typedef union { switch_core_db_t *core_db_dbh; switch_odbc_handle_t *odbc_dbh; switch_pgsql_handle_t *pgsql_dbh; + switch_database_interface_handle_t *database_interface_dbh; } switch_cache_db_native_handle_t; typedef struct { @@ -2497,10 +2500,18 @@ typedef struct { char *dsn; } switch_cache_db_pgsql_options_t; +typedef struct { + char *dsn; + char prefix[16]; + switch_database_interface_t *database_interface; + switch_bool_t make_module_no_unloadable; +} switch_cache_db_database_interface_options_t; + typedef union { switch_cache_db_core_db_options_t core_db_options; switch_cache_db_odbc_options_t odbc_options; switch_cache_db_pgsql_options_t pgsql_options; + switch_cache_db_database_interface_options_t database_interface_options; } switch_cache_db_connection_options_t; struct switch_cache_db_handle; @@ -2511,6 +2522,11 @@ static inline const char *switch_cache_db_type_name(switch_cache_db_handle_type_ const char *type_str = "INVALID"; switch (type) { + case SCDB_TYPE_DATABASE_INTERFACE: + { + type_str = "DATABASE_INTERFACE"; + } + break; case SCDB_TYPE_PGSQL: { type_str = "PGSQL"; @@ -2559,6 +2575,8 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h const char *file, const char *func, int line); #define switch_cache_db_get_db_handle(_a, _b, _c) _switch_cache_db_get_db_handle(_a, _b, _c, __FILE__, __SWITCH_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_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); #define switch_cache_db_get_db_handle_dsn(_a, _b) _switch_cache_db_get_db_handle_dsn(_a, _b, __FILE__, __SWITCH_FUNC__, __LINE__) @@ -2643,6 +2661,13 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans_full(sw const char *inner_post_trans_execute); #define switch_cache_db_persistant_execute_trans(_d, _s, _r) switch_cache_db_persistant_execute_trans_full(_d, _s, _r, NULL, NULL, NULL, NULL) +SWITCH_DECLARE(void) switch_cache_db_database_interface_flush_handles(switch_database_interface_t *database_interface); + +/*! +\brief Returns error if no suitable database interface found to serve core db dsn. +*/ +SWITCH_DECLARE(switch_status_t) switch_core_check_core_db_dsn(); + SWITCH_DECLARE(void) switch_core_set_signal_handlers(void); SWITCH_DECLARE(uint32_t) switch_core_debug_level(void); SWITCH_DECLARE(int32_t) switch_core_sps(void); diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h index 87295a641b..be32c99e2e 100644 --- a/src/include/switch_loadable_module.h +++ b/src/include/switch_loadable_module.h @@ -24,6 +24,7 @@ * Contributor(s): * * Anthony Minessale II + * Andrey Volk * * * switch_loadable_module.h -- Loadable Modules @@ -51,6 +52,14 @@ SWITCH_BEGIN_EXTERN_C \ingroup core1 \{ */ + +/*! \brief List of loadable module types */ + typedef enum { + SWITCH_LOADABLE_MODULE_TYPE_PRELOAD, + SWITCH_LOADABLE_MODULE_TYPE_COMMON, + SWITCH_LOADABLE_MODULE_TYPE_POSTLOAD + } switch_loadable_module_type_t; + /*! \brief The abstraction of a loadable module */ struct switch_loadable_module_interface { /*! the name of the module */ @@ -87,6 +96,8 @@ SWITCH_BEGIN_EXTERN_C switch_management_interface_t *management_interface; /*! the table of limit interfaces the module has implemented */ switch_limit_interface_t *limit_interface; + /*! the table of database interfaces the module has implemented */ + switch_database_interface_t *database_interface; switch_thread_rwlock_t *rwlock; int refs; switch_memory_pool_t *pool; @@ -205,6 +216,13 @@ SWITCH_DECLARE(switch_json_api_interface_t *) switch_loadable_module_get_json_ap */ SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interface(const char *name, const char *modname); +/*! +\brief Retrieve the database interface by it's registered name +\param name the name of the dsn prefix +\return the desired database format interface +*/ +SWITCH_DECLARE(switch_database_interface_t *) switch_loadable_module_get_database_interface(const char *name, const char *modname); + /*! \brief Retrieve the speech interface by it's registered name \param name the name of the speech interface @@ -311,6 +329,13 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_load_module(const char *d */ SWITCH_DECLARE(switch_status_t) switch_loadable_module_exists(const char *mod); +/*! +\brief Protect module from beeing unloaded +\param mod the module name +\return the status +*/ +SWITCH_DECLARE(switch_status_t) switch_loadable_module_protect(const char *mod); + /*! \brief Unoad a module \param dir the directory where the module resides diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 798695d090..54cd7b2de2 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -25,6 +25,7 @@ * * Anthony Minessale II * Luke Dashjr (OpenMethods, LLC) + * Andrey Volk * * * switch_module_interfaces.h -- Module Interface Definitions @@ -614,6 +615,38 @@ struct switch_directory_handle { void *private_info; }; +/*! \brief Abstract interface to a database module */ +struct switch_database_interface { + /*! the name of the interface */ + const char *interface_name; + switch_status_t(*handle_new)(char *dsn, switch_database_interface_handle_t **dih); + switch_status_t(*handle_destroy)(switch_database_interface_handle_t **dih); + switch_status_t(*flush)(switch_database_interface_handle_t *dih); + switch_status_t(*exec_detailed)(const char *file, const char *func, int line, + switch_database_interface_handle_t *dih, const char *sql, char **err); + switch_status_t(*exec_string)(switch_database_interface_handle_t *dih, const char *sql, char *resbuf, size_t len, char **err); + switch_status_t(*sql_set_auto_commit_attr)(switch_database_interface_handle_t *dih, switch_bool_t on); + switch_status_t(*commit)(switch_database_interface_handle_t *dih); + switch_status_t(*rollback)(switch_database_interface_handle_t *dih); + switch_status_t(*callback_exec_detailed)(const char *file, const char *func, int line, + switch_database_interface_handle_t *dih, const char *sql, switch_core_db_callback_func_t callback, void *pdata, char **err); + switch_status_t(*affected_rows)(switch_database_interface_handle_t *dih, int *affected_rows); + + /*! list of supported dsn prefixes */ + char **prefixes; + switch_thread_rwlock_t *rwlock; + int refs; + switch_mutex_t *reflock; + switch_loadable_module_interface_t *parent; + struct switch_database_interface *next; +}; + +/*! an abstract representation of a database interface. */ +struct switch_database_interface_handle { + switch_cache_db_database_interface_options_t connection_options; + void *handle; +}; + struct switch_audio_codec_settings { int unused; }; diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 53c25c395c..de2effd336 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -28,6 +28,7 @@ * Joseph Sullivan * Raymond Chandler * Emmanuel Schmidbauer + * Andrey Volk * * switch_types.h -- Data Types * @@ -400,6 +401,7 @@ typedef enum { SWITCH_LIMIT_INTERFACE, SWITCH_CHAT_APPLICATION_INTERFACE, SWITCH_JSON_API_INTERFACE, + SWITCH_DATABASE_INTERFACE, } switch_module_interface_name_t; typedef enum { @@ -2290,6 +2292,7 @@ typedef struct switch_codec_fmtp switch_codec_fmtp_t; typedef struct switch_odbc_handle switch_odbc_handle_t; typedef struct switch_pgsql_handle switch_pgsql_handle_t; typedef struct switch_pgsql_result switch_pgsql_result_t; +typedef struct switch_database_interface_handle switch_database_interface_handle_t; typedef struct switch_io_routines switch_io_routines_t; typedef struct switch_speech_handle switch_speech_handle_t; @@ -2313,6 +2316,7 @@ typedef struct switch_management_interface switch_management_interface_t; typedef struct switch_core_port_allocator switch_core_port_allocator_t; typedef struct switch_media_bug switch_media_bug_t; typedef struct switch_limit_interface switch_limit_interface_t; +typedef struct switch_database_interface switch_database_interface_t; typedef void (*hashtable_destructor_t)(void *ptr); diff --git a/src/switch_core.c b/src/switch_core.c index b4128cc19a..d81b7e520c 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -29,6 +29,7 @@ * Marcel Barbulescu * Joseph Sullivan * Seven Du + * Andrey Volk * * switch_core.c -- Main Core Library * @@ -2015,10 +2016,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc switch_core_state_machine_init(runtime.memory_pool); - if (switch_core_sqldb_start(runtime.memory_pool, switch_test_flag((&runtime), SCF_USE_SQL) ? SWITCH_TRUE : SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) { - *err = "Error activating database"; - return SWITCH_STATUS_FALSE; - } switch_core_media_init(); switch_scheduler_task_thread_start(); @@ -2343,11 +2340,7 @@ static void switch_load_core_config(const char *file) } else if (!strcasecmp(var, "core-db-name") && !zstr(val)) { runtime.dbname = switch_core_strdup(runtime.memory_pool, val); } else if (!strcasecmp(var, "core-db-dsn") && !zstr(val)) { - if (switch_odbc_available() || switch_pgsql_available()) { - runtime.odbc_dsn = switch_core_strdup(runtime.memory_pool, val); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC AND PGSQL ARE NOT AVAILABLE!\n"); - } + runtime.odbc_dsn = switch_core_strdup(runtime.memory_pool, val); } else if (!strcasecmp(var, "core-non-sqlite-db-required") && !zstr(val)) { switch_set_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ); } else if (!strcasecmp(var, "core-dbtype") && !zstr(val)) { @@ -2425,6 +2418,20 @@ SWITCH_DECLARE(const char *) switch_core_banner(void) "\n"); } +switch_status_t switch_core_sqldb_init(const char **err) +{ + if (switch_core_check_core_db_dsn() != SWITCH_STATUS_SUCCESS) { + *err = "NO SUITABLE DATABASE INTERFACE IS AVAILABLE TO SERVE 'core-db-dsn'!\n"; + return SWITCH_STATUS_GENERR; + } + + if (switch_core_sqldb_start(runtime.memory_pool, switch_test_flag((&runtime), SCF_USE_SQL) ? SWITCH_TRUE : SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) { + *err = "Error activating database"; + return SWITCH_STATUS_GENERR; + } + + return SWITCH_STATUS_SUCCESS; +} SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(switch_core_flag_t flags, switch_bool_t console, const char **err) { @@ -2969,6 +2976,13 @@ SWITCH_DECLARE(switch_bool_t) switch_core_ready_outbound(void) return (switch_test_flag((&runtime), SCF_SHUTTING_DOWN) || switch_test_flag((&runtime), SCF_NO_NEW_OUTBOUND_SESSIONS)) ? SWITCH_FALSE : SWITCH_TRUE; } +void switch_core_sqldb_destroy() +{ + if (switch_test_flag((&runtime), SCF_USE_SQL)) { + switch_core_sqldb_stop(); + } +} + SWITCH_DECLARE(switch_status_t) switch_core_destroy(void) { switch_event_t *event; @@ -2989,9 +3003,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void) switch_ssl_destroy_ssl_locks(); - if (switch_test_flag((&runtime), SCF_USE_SQL)) { - switch_core_sqldb_stop(); - } switch_scheduler_task_thread_stop(); switch_rtp_shutdown(); diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index feb69d6b8e..9c6dc1ab55 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -27,6 +27,7 @@ * Michael Jerris * Paul D. Tinsley * Emmanuel Schmidbauer + * Andrey Volk * * * switch_core_sqldb.c -- Main Core Library (statistics tracker) @@ -77,6 +78,9 @@ static struct { 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; @@ -135,6 +139,35 @@ static void del_handle(switch_cache_db_handle_t *dbh) 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; @@ -155,7 +188,7 @@ static switch_cache_db_handle_t *get_handle(const char *db_str, const char *user 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; @@ -198,7 +231,7 @@ SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t 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; } @@ -234,6 +267,12 @@ static void sql_close(time_t prune) 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); @@ -299,6 +338,12 @@ SWITCH_DECLARE(void) switch_cache_db_release_db_handle(switch_cache_db_handle_t 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); @@ -331,46 +376,115 @@ SWITCH_DECLARE(void) switch_cache_db_dismiss_db_handle(switch_cache_db_handle_t 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; + char *colon_slashes = NULL; + if ( NULL != (colon_slashes = strstr(dsn, "://")) ) + { + char prefix[16] = ""; + strncpy(prefix, dsn, MIN(colon_slashes - dsn, 15)); - if (i) { - switch_set_string(tmp, dsn); - } else { - switch_set_string(tmp, dsn+7); + 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); } + } - connection_options.odbc_options.dsn = tmp; + 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; - if ((p = strchr(tmp, ':'))) { - *p++ = '\0'; - connection_options.odbc_options.user = p; + if (i) { + switch_set_string(tmp, dsn); + } + else { + switch_set_string(tmp, dsn + 7); + } - if ((p = strchr(connection_options.odbc_options.user, ':'))) { + connection_options.odbc_options.dsn = tmp; + + 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); @@ -416,6 +530,14 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h } 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; @@ -423,6 +545,7 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h odbc_pass = NULL; db_type = "pgsql"; } + break; case SCDB_TYPE_ODBC: { db_name = connection_options->odbc_options.dsn; @@ -454,14 +577,41 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h 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()) { @@ -478,7 +628,6 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h 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; @@ -490,8 +639,6 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h switch_odbc_handle_destroy(&odbc_dbh); } } - - } break; case SCDB_TYPE_CORE_DB: @@ -504,7 +651,7 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h 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; } @@ -514,7 +661,9 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h 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; @@ -552,6 +701,13 @@ static switch_status_t switch_cache_db_execute_sql_real(switch_cache_db_handle_t } 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"; @@ -698,6 +854,13 @@ SWITCH_DECLARE(int) switch_cache_db_affected_rows(switch_cache_db_handle_t *dbh) 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); @@ -721,6 +884,11 @@ SWITCH_DECLARE(int) switch_cache_db_load_extension(switch_cache_db_handle_t *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"); @@ -783,6 +951,12 @@ SWITCH_DECLARE(char *) switch_cache_db_execute_sql2str(switch_cache_db_handle_t 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); @@ -887,6 +1061,18 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans_full(sw } } 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; @@ -922,6 +1108,17 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans_full(sw 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); @@ -997,6 +1194,17 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans_full(sw 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); @@ -1058,6 +1266,17 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_event_callback(switc 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); @@ -1113,6 +1332,21 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_event_callback_err(s 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); @@ -1173,6 +1407,17 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_callback(switch_cach 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); @@ -1223,6 +1468,21 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_callback_err(switch_ 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); @@ -1318,6 +1578,31 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand 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) { @@ -1940,6 +2225,18 @@ static uint32_t do_trans(switch_sql_queue_manager_t *qm) } } 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; @@ -2016,6 +2313,17 @@ static uint32_t do_trans(switch_sql_queue_manager_t *qm) 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); @@ -2072,6 +2380,8 @@ static void *SWITCH_THREAD_FUNC switch_user_sql_thread(switch_thread_t *thread, 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: @@ -3390,6 +3700,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ 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)) { @@ -3440,6 +3751,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ switch (sql_manager.dbh->type) { + case SCDB_TYPE_DATABASE_INTERFACE: case SCDB_TYPE_PGSQL: case SCDB_TYPE_ODBC: { @@ -3481,6 +3793,18 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ } } 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; @@ -3514,6 +3838,18 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ } } 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 || diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index 38de325d2c..dfd8f310a9 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -25,12 +25,14 @@ * * Anthony Minessale II * Seven Du + * Andrey Volk * * switch_loadable_module.c -- Loadable Modules * */ #include +#include "private/switch_core_pvt.h" /* for apr_pstrcat */ #include @@ -47,6 +49,12 @@ typedef struct switch_file_node_s { 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; @@ -67,6 +75,7 @@ struct switch_loadable_module { switch_status_t status; switch_thread_t *thread; switch_bool_t shutting_down; + switch_loadable_module_type_t type; }; struct switch_loadable_module_container { @@ -87,6 +96,7 @@ 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; @@ -95,7 +105,7 @@ struct switch_loadable_module_container { 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) { @@ -143,11 +153,28 @@ static void switch_loadable_module_runtime(void) 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); @@ -166,7 +193,14 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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++; } } @@ -232,7 +266,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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++; } } @@ -253,7 +295,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -274,7 +324,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -297,7 +355,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -320,7 +386,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -343,7 +417,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -366,7 +448,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -394,7 +484,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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)); @@ -410,6 +508,52 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable } } + 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; @@ -423,7 +567,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -444,7 +596,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -465,7 +625,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -486,7 +654,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -507,7 +683,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); @@ -534,7 +718,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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++; } } @@ -561,7 +753,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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++; } } @@ -576,7 +776,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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++; } } @@ -1215,6 +1423,62 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t } } + 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; @@ -1546,10 +1810,10 @@ static switch_status_t switch_loadable_module_load_file(char *path, char *filena } 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; @@ -1593,7 +1857,9 @@ static switch_status_t switch_loadable_module_load_module_ex(const char *dir, co *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); } @@ -1628,6 +1894,30 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_exists(const char *mod) 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; @@ -1801,7 +2091,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_build_dynamic(char *filen 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 @@ -1826,12 +2116,17 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo 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 @@ -1869,21 +2164,94 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo 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"))) { @@ -1902,7 +2270,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo 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(); @@ -1935,7 +2303,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo 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++; } } @@ -2047,6 +2415,7 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void) { switch_hash_index_t *hi; void *val; + const void *key; switch_loadable_module_t *module; int i; @@ -2068,19 +2437,47 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void) 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); + 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); - 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_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL); + } } } @@ -2100,6 +2497,7 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void) 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); @@ -2147,6 +2545,34 @@ SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interf 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; @@ -2711,6 +3137,9 @@ SWITCH_DECLARE(void *) switch_loadable_module_create_interface(switch_loadable_m 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;