FS-10801: [core] Add a database interface to the FreeSWITCH Core.

This commit is contained in:
Andrey Volk 2018-04-02 14:02:19 +03:00
parent fbbac95744
commit 07e0d4f90c
8 changed files with 943 additions and 77 deletions

View File

@ -24,6 +24,7 @@
* Contributor(s): * Contributor(s):
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Andrey Volk <andywolk@gmail.com>
* *
* *
* switch_core.h -- Core Library Private Data (not to be installed into the system) * 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); 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_sqldb_stop(void);
void switch_core_session_init(switch_memory_pool_t *pool); void switch_core_session_init(switch_memory_pool_t *pool);

View File

@ -27,6 +27,7 @@
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC) * Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
* Joseph Sullivan <jossulli@amazon.com> * Joseph Sullivan <jossulli@amazon.com>
* Emmanuel Schmidbauer <eschmidbauer@gmail.com> * Emmanuel Schmidbauer <eschmidbauer@gmail.com>
* Andrey Volk <andywolk@gmail.com>
* *
* switch_core.h -- Core Library * switch_core.h -- Core Library
* *
@ -2474,13 +2475,15 @@ typedef enum {
typedef enum { typedef enum {
SCDB_TYPE_CORE_DB, SCDB_TYPE_CORE_DB,
SCDB_TYPE_ODBC, SCDB_TYPE_ODBC,
SCDB_TYPE_PGSQL SCDB_TYPE_PGSQL,
SCDB_TYPE_DATABASE_INTERFACE
} switch_cache_db_handle_type_t; } switch_cache_db_handle_type_t;
typedef union { typedef union {
switch_core_db_t *core_db_dbh; switch_core_db_t *core_db_dbh;
switch_odbc_handle_t *odbc_dbh; switch_odbc_handle_t *odbc_dbh;
switch_pgsql_handle_t *pgsql_dbh; switch_pgsql_handle_t *pgsql_dbh;
switch_database_interface_handle_t *database_interface_dbh;
} switch_cache_db_native_handle_t; } switch_cache_db_native_handle_t;
typedef struct { typedef struct {
@ -2497,10 +2500,18 @@ typedef struct {
char *dsn; char *dsn;
} switch_cache_db_pgsql_options_t; } 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 { typedef union {
switch_cache_db_core_db_options_t core_db_options; switch_cache_db_core_db_options_t core_db_options;
switch_cache_db_odbc_options_t odbc_options; switch_cache_db_odbc_options_t odbc_options;
switch_cache_db_pgsql_options_t pgsql_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; } switch_cache_db_connection_options_t;
struct switch_cache_db_handle; 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"; const char *type_str = "INVALID";
switch (type) { switch (type) {
case SCDB_TYPE_DATABASE_INTERFACE:
{
type_str = "DATABASE_INTERFACE";
}
break;
case SCDB_TYPE_PGSQL: case SCDB_TYPE_PGSQL:
{ {
type_str = "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); 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__) #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, 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); 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__) #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); 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) #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(void) switch_core_set_signal_handlers(void);
SWITCH_DECLARE(uint32_t) switch_core_debug_level(void); SWITCH_DECLARE(uint32_t) switch_core_debug_level(void);
SWITCH_DECLARE(int32_t) switch_core_sps(void); SWITCH_DECLARE(int32_t) switch_core_sps(void);

View File

@ -24,6 +24,7 @@
* Contributor(s): * Contributor(s):
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Andrey Volk <andywolk@gmail.com>
* *
* *
* switch_loadable_module.h -- Loadable Modules * switch_loadable_module.h -- Loadable Modules
@ -51,6 +52,14 @@ SWITCH_BEGIN_EXTERN_C
\ingroup core1 \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 */ /*! \brief The abstraction of a loadable module */
struct switch_loadable_module_interface { struct switch_loadable_module_interface {
/*! the name of the module */ /*! the name of the module */
@ -87,6 +96,8 @@ SWITCH_BEGIN_EXTERN_C
switch_management_interface_t *management_interface; switch_management_interface_t *management_interface;
/*! the table of limit interfaces the module has implemented */ /*! the table of limit interfaces the module has implemented */
switch_limit_interface_t *limit_interface; 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; switch_thread_rwlock_t *rwlock;
int refs; int refs;
switch_memory_pool_t *pool; 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); 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 \brief Retrieve the speech interface by it's registered name
\param name the name of the speech interface \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); 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 \brief Unoad a module
\param dir the directory where the module resides \param dir the directory where the module resides

View File

@ -25,6 +25,7 @@
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC) * Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
* Andrey Volk <andywolk@gmail.com>
* *
* *
* switch_module_interfaces.h -- Module Interface Definitions * switch_module_interfaces.h -- Module Interface Definitions
@ -614,6 +615,38 @@ struct switch_directory_handle {
void *private_info; 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 { struct switch_audio_codec_settings {
int unused; int unused;
}; };

View File

@ -28,6 +28,7 @@
* Joseph Sullivan <jossulli@amazon.com> * Joseph Sullivan <jossulli@amazon.com>
* Raymond Chandler <intralanman@freeswitch.org> * Raymond Chandler <intralanman@freeswitch.org>
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com> * Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
* Andrey Volk <andywolk@gmail.com>
* *
* switch_types.h -- Data Types * switch_types.h -- Data Types
* *
@ -400,6 +401,7 @@ typedef enum {
SWITCH_LIMIT_INTERFACE, SWITCH_LIMIT_INTERFACE,
SWITCH_CHAT_APPLICATION_INTERFACE, SWITCH_CHAT_APPLICATION_INTERFACE,
SWITCH_JSON_API_INTERFACE, SWITCH_JSON_API_INTERFACE,
SWITCH_DATABASE_INTERFACE,
} switch_module_interface_name_t; } switch_module_interface_name_t;
typedef enum { 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_odbc_handle switch_odbc_handle_t;
typedef struct switch_pgsql_handle switch_pgsql_handle_t; typedef struct switch_pgsql_handle switch_pgsql_handle_t;
typedef struct switch_pgsql_result switch_pgsql_result_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_io_routines switch_io_routines_t;
typedef struct switch_speech_handle switch_speech_handle_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_core_port_allocator switch_core_port_allocator_t;
typedef struct switch_media_bug switch_media_bug_t; typedef struct switch_media_bug switch_media_bug_t;
typedef struct switch_limit_interface switch_limit_interface_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); typedef void (*hashtable_destructor_t)(void *ptr);

View File

@ -29,6 +29,7 @@
* Marcel Barbulescu <marcelbarbulescu@gmail.com> * Marcel Barbulescu <marcelbarbulescu@gmail.com>
* Joseph Sullivan <jossulli@amazon.com> * Joseph Sullivan <jossulli@amazon.com>
* Seven Du <dujinfang@gmail.com> * Seven Du <dujinfang@gmail.com>
* Andrey Volk <andywolk@gmail.com>
* *
* switch_core.c -- Main Core Library * 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); 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_core_media_init();
switch_scheduler_task_thread_start(); 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)) { } else if (!strcasecmp(var, "core-db-name") && !zstr(val)) {
runtime.dbname = switch_core_strdup(runtime.memory_pool, val); runtime.dbname = switch_core_strdup(runtime.memory_pool, val);
} else if (!strcasecmp(var, "core-db-dsn") && !zstr(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); 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");
}
} else if (!strcasecmp(var, "core-non-sqlite-db-required") && !zstr(val)) { } else if (!strcasecmp(var, "core-non-sqlite-db-required") && !zstr(val)) {
switch_set_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ); switch_set_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ);
} else if (!strcasecmp(var, "core-dbtype") && !zstr(val)) { } else if (!strcasecmp(var, "core-dbtype") && !zstr(val)) {
@ -2425,6 +2418,20 @@ SWITCH_DECLARE(const char *) switch_core_banner(void)
"\n"); "\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) 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; 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_DECLARE(switch_status_t) switch_core_destroy(void)
{ {
switch_event_t *event; switch_event_t *event;
@ -2989,9 +3003,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
switch_ssl_destroy_ssl_locks(); switch_ssl_destroy_ssl_locks();
if (switch_test_flag((&runtime), SCF_USE_SQL)) {
switch_core_sqldb_stop();
}
switch_scheduler_task_thread_stop(); switch_scheduler_task_thread_stop();
switch_rtp_shutdown(); switch_rtp_shutdown();

View File

@ -27,6 +27,7 @@
* Michael Jerris <mike@jerris.com> * Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org> * Paul D. Tinsley <pdt at jackhammer.org>
* Emmanuel Schmidbauer <eschmidbauer@gmail.com> * Emmanuel Schmidbauer <eschmidbauer@gmail.com>
* Andrey Volk <andywolk@gmail.com>
* *
* *
* switch_core_sqldb.c -- Main Core Library (statistics tracker) * 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_start_thread(void);
static void switch_core_sqldb_stop_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) static switch_cache_db_handle_t *create_handle(switch_cache_db_handle_type_t type)
{ {
switch_cache_db_handle_t *new_dbh = NULL; 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_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) 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; 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) { if (!r) {
for (dbh_ptr = sql_manager.handle_pool; dbh_ptr; dbh_ptr = dbh_ptr->next) { 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) { switch_mutex_trylock(dbh_ptr->mutex) == SWITCH_STATUS_SUCCESS) {
r = dbh_ptr; r = dbh_ptr;
break; break;
@ -198,7 +231,7 @@ SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t
dsn = "core"; 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; *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_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Dropping idle DB connection %s\n", dbh->name);
switch (dbh->type) { 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: case SCDB_TYPE_PGSQL:
{ {
switch_pgsql_handle_destroy(&dbh->native_handle.pgsql_dbh); 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) { if (dbh && *dbh) {
switch((*dbh)->type) { 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: case SCDB_TYPE_PGSQL:
{ {
switch_pgsql_flush((*dbh)->native_handle.pgsql_dbh); switch_pgsql_flush((*dbh)->native_handle.pgsql_dbh);
@ -331,29 +376,96 @@ SWITCH_DECLARE(void) switch_cache_db_dismiss_db_handle(switch_cache_db_handle_t
switch_cache_db_release_db_handle(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, 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) 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_connection_options_t connection_options = { {0} };
switch_cache_db_handle_type_t type; switch_cache_db_handle_type_t type;
switch_database_interface_t *database_interface = NULL;
char tmp[256] = ""; char tmp[256] = "";
char *p; char *p;
switch_status_t status = SWITCH_STATUS_FALSE; switch_status_t status = SWITCH_STATUS_FALSE;
int i; int i;
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)) { if (!strncasecmp(dsn, "pgsql://", 8)) {
type = SCDB_TYPE_PGSQL; type = SCDB_TYPE_PGSQL;
connection_options.pgsql_options.dsn = (char *)(dsn + 8); connection_options.pgsql_options.dsn = (char *)(dsn + 8);
} else if (!strncasecmp(dsn, "sqlite://", 9)) { }
else if (!strncasecmp(dsn, "sqlite://", 9)) {
type = SCDB_TYPE_CORE_DB; type = SCDB_TYPE_CORE_DB;
connection_options.core_db_options.db_path = (char *)(dsn + 9); connection_options.core_db_options.db_path = (char *)(dsn + 9);
} else if ((!(i = strncasecmp(dsn, "odbc://", 7))) || strchr(dsn+2, ':')) { }
else if ((!(i = strncasecmp(dsn, "odbc://", 7))) || (strchr(dsn + 2, ':') && !colon_slashes)) {
type = SCDB_TYPE_ODBC; type = SCDB_TYPE_ODBC;
if (i) { if (i) {
switch_set_string(tmp, dsn); switch_set_string(tmp, dsn);
} else { }
else {
switch_set_string(tmp, dsn + 7); switch_set_string(tmp, dsn + 7);
} }
@ -368,10 +480,12 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle_dsn(switch_cache_
connection_options.odbc_options.pass = p; connection_options.odbc_options.pass = p;
} }
} }
} else { }
else {
type = SCDB_TYPE_CORE_DB; type = SCDB_TYPE_CORE_DB;
connection_options.core_db_options.db_path = (char *)dsn; connection_options.core_db_options.db_path = (char *)dsn;
} }
}
status = _switch_cache_db_get_db_handle(dbh, type, &connection_options, file, func, line); 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) { 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: case SCDB_TYPE_PGSQL:
{ {
db_name = connection_options->pgsql_options.dsn; 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; odbc_pass = NULL;
db_type = "pgsql"; db_type = "pgsql";
} }
break;
case SCDB_TYPE_ODBC: case SCDB_TYPE_ODBC:
{ {
db_name = connection_options->odbc_options.dsn; 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); 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))) { if ((new_dbh = get_handle(db_str, db_callsite_str, thread_str))) {
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, 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)); "Reuse Unused Cached DB handle %s [%s]\n", new_dbh->name, switch_cache_db_type_name(new_dbh->type));
}
} else { } else {
switch_core_db_t *db = NULL; switch_core_db_t *db = NULL;
switch_odbc_handle_t *odbc_dbh = NULL; switch_odbc_handle_t *odbc_dbh = NULL;
switch_pgsql_handle_t *pgsql_dbh = NULL; switch_pgsql_handle_t *pgsql_dbh = NULL;
switch_database_interface_handle_t *database_interface_dbh = NULL;
switch (type) { 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: case SCDB_TYPE_PGSQL:
{ {
if (!switch_pgsql_available()) { if (!switch_pgsql_available()) {
@ -478,7 +628,6 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
break; break;
case SCDB_TYPE_ODBC: case SCDB_TYPE_ODBC:
{ {
if (!switch_odbc_available()) { 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); 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; 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); switch_odbc_handle_destroy(&odbc_dbh);
} }
} }
} }
break; break;
case SCDB_TYPE_CORE_DB: 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; 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); 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; 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, 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); "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; new_dbh->native_handle.core_db_dbh = db;
} else if (odbc_dbh) { } else if (odbc_dbh) {
new_dbh->native_handle.odbc_dbh = 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) { 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: case SCDB_TYPE_PGSQL:
{ {
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); return switch_odbc_handle_affected_rows(dbh->native_handle.odbc_dbh);
} }
break; 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: case SCDB_TYPE_PGSQL:
{ {
return switch_pgsql_handle_affected_rows(dbh->native_handle.pgsql_dbh); 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"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "load extension not supported by type ODBC!\n");
} }
break; 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: case SCDB_TYPE_PGSQL:
{ {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "load extension not supported by type PGSQL!\n"); 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); status = switch_odbc_handle_exec_string(dbh->native_handle.odbc_dbh, sql, str, len, err);
} }
break; 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: case SCDB_TYPE_PGSQL:
{ {
status = switch_pgsql_handle_exec_string(dbh->native_handle.pgsql_dbh, sql, str, len, err); 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; 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: case SCDB_TYPE_PGSQL:
{ {
switch_pgsql_status_t result; 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); switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
} }
break; 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: case SCDB_TYPE_PGSQL:
{ {
switch_pgsql_SQLEndTran(dbh->native_handle.pgsql_dbh, 1); 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); switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
} }
break; 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: case SCDB_TYPE_PGSQL:
{ {
switch_pgsql_SQLEndTran(dbh->native_handle.pgsql_dbh, 1); 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; h.pdata = pdata;
switch (dbh->type) { 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: case SCDB_TYPE_PGSQL:
{ {
status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, helper_callback, &h, err); 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; h.pdata = pdata;
switch (dbh->type) { 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: case SCDB_TYPE_PGSQL:
{ {
status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, helper_callback, &h, err); 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) { 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: case SCDB_TYPE_PGSQL:
{ {
status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, callback, pdata, err); 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) { 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: case SCDB_TYPE_PGSQL:
{ {
status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, callback, pdata, err); 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); if (io_mutex) switch_mutex_lock(io_mutex);
switch (dbh->type) { 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: case SCDB_TYPE_PGSQL:
{ {
if (switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, test_sql, NULL) != SWITCH_PGSQL_SUCCESS) { 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; 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: case SCDB_TYPE_PGSQL:
{ {
switch_pgsql_status_t result; 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); switch_odbc_SQLSetAutoCommitAttr(qm->event_db->native_handle.odbc_dbh, 1);
} }
break; 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: case SCDB_TYPE_PGSQL:
{ {
switch_pgsql_SQLEndTran(qm->event_db->native_handle.pgsql_dbh, 1); 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_mutex_lock(qm->cond_mutex);
switch (qm->event_db->type) { switch (qm->event_db->type) {
case SCDB_TYPE_DATABASE_INTERFACE:
break;
case SCDB_TYPE_PGSQL: case SCDB_TYPE_PGSQL:
break; break;
case SCDB_TYPE_ODBC: 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_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening DB\n");
switch (sql_manager.dbh->type) { switch (sql_manager.dbh->type) {
case SCDB_TYPE_DATABASE_INTERFACE:
case SCDB_TYPE_PGSQL: case SCDB_TYPE_PGSQL:
case SCDB_TYPE_ODBC: case SCDB_TYPE_ODBC:
if (switch_test_flag((&runtime), SCF_CLEAR_SQL)) { 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) { switch (sql_manager.dbh->type) {
case SCDB_TYPE_DATABASE_INTERFACE:
case SCDB_TYPE_PGSQL: case SCDB_TYPE_PGSQL:
case SCDB_TYPE_ODBC: case SCDB_TYPE_ODBC:
{ {
@ -3481,6 +3793,18 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
} }
} }
break; 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: case SCDB_TYPE_PGSQL:
{ {
switch_pgsql_status_t result; switch_pgsql_status_t result;
@ -3514,6 +3838,18 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
} }
} }
break; 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: case SCDB_TYPE_PGSQL:
{ {
if (switch_pgsql_SQLEndTran(sql_manager.dbh->native_handle.pgsql_dbh, 1) != SWITCH_PGSQL_SUCCESS || if (switch_pgsql_SQLEndTran(sql_manager.dbh->native_handle.pgsql_dbh, 1) != SWITCH_PGSQL_SUCCESS ||

View File

@ -25,12 +25,14 @@
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Seven Du <dujinfang@gmail.com> * Seven Du <dujinfang@gmail.com>
* Andrey Volk <andywolk@gmail.com>
* *
* switch_loadable_module.c -- Loadable Modules * switch_loadable_module.c -- Loadable Modules
* *
*/ */
#include <switch.h> #include <switch.h>
#include "private/switch_core_pvt.h"
/* for apr_pstrcat */ /* for apr_pstrcat */
#include <apr_strings.h> #include <apr_strings.h>
@ -47,6 +49,12 @@ typedef struct switch_file_node_s {
struct switch_file_node_s *next; struct switch_file_node_s *next;
} switch_file_node_t; } 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 { typedef struct switch_codec_node_s {
const switch_codec_interface_t *ptr; const switch_codec_interface_t *ptr;
const char *interface_name; const char *interface_name;
@ -67,6 +75,7 @@ struct switch_loadable_module {
switch_status_t status; switch_status_t status;
switch_thread_t *thread; switch_thread_t *thread;
switch_bool_t shutting_down; switch_bool_t shutting_down;
switch_loadable_module_type_t type;
}; };
struct switch_loadable_module_container { struct switch_loadable_module_container {
@ -87,6 +96,7 @@ struct switch_loadable_module_container {
switch_hash_t *say_hash; switch_hash_t *say_hash;
switch_hash_t *management_hash; switch_hash_t *management_hash;
switch_hash_t *limit_hash; switch_hash_t *limit_hash;
switch_hash_t *database_hash;
switch_hash_t *secondary_recover_hash; switch_hash_t *secondary_recover_hash;
switch_mutex_t *mutex; switch_mutex_t *mutex;
switch_memory_pool_t *pool; switch_memory_pool_t *pool;
@ -95,7 +105,7 @@ struct switch_loadable_module_container {
static struct switch_loadable_module_container loadable_modules; 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, 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); 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) 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); 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; switch_event_t *event;
int *event_num = NULL;
char str_event_num[10];
void *val;
int added = 0; 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); new_module->key = switch_core_strdup(new_module->pool, key);
switch_mutex_lock(loadable_modules.mutex); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; 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, "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, "filename", new_module->filename);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name);
if (!event_hash) {
switch_event_fire(&event); 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++; 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.dialplan_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.timer_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.application_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.chat_application_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.api_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.json_api_hash, ptr->interface_name, (const void *) ptr); 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, "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, "filename", new_module->filename);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
node = switch_core_alloc(new_module->pool, sizeof(*node)); 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) { if (new_module->module_interface->speech_interface) {
const switch_speech_interface_t *ptr; 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.speech_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.asr_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.directory_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.chat_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; added++;
} }
switch_core_hash_insert(loadable_modules.say_hash, ptr->interface_name, (const void *) ptr); 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; 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, "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, "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, "filename", new_module->filename);
if (!event_hash) {
switch_event_fire(&event); 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++; 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) { if (old_module->module_interface->speech_interface) {
const switch_speech_interface_t *ptr; 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) 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; switch_size_t len = 0;
char *path; char *path;
@ -1593,7 +1857,9 @@ static switch_status_t switch_loadable_module_load_module_ex(const char *dir, co
*err = "Module already loaded"; *err = "Module already loaded";
status = SWITCH_STATUS_FALSE; status = SWITCH_STATUS_FALSE;
} else if ((status = switch_loadable_module_load_file(path, file, global, &new_module)) == SWITCH_STATUS_SUCCESS) { } 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) { if (new_module->switch_module_runtime) {
new_module->thread = switch_core_launch_thread(switch_loadable_module_exec, new_module, new_module->pool); 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; 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_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; 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); 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); 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 #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_finfo_t finfo = { 0 };
apr_dir_t *module_dir_handle = NULL; apr_dir_t *module_dir_handle = NULL;
apr_int32_t finfo_flags = APR_FINFO_DIRENT | APR_FINFO_TYPE | APR_FINFO_NAME; 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 *cf = "modules.conf";
char *pcf = "post_load_modules.conf"; char *pcf = "post_load_modules.conf";
switch_xml_t cfg, xml; switch_xml_t cfg, xml;
unsigned char all = 0; unsigned char all = 0;
unsigned int count = 0; unsigned int count = 0;
const char *err; const char *err;
switch_hash_t *event_hash;
switch_hash_index_t *hi;
void *hash_val;
switch_event_t *event;
#ifdef WIN32 #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.say_hash);
switch_core_hash_init_nocase(&loadable_modules.management_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.limit_hash);
switch_core_hash_init_nocase(&loadable_modules.database_hash);
switch_core_hash_init_nocase(&loadable_modules.dialplan_hash); switch_core_hash_init_nocase(&loadable_modules.dialplan_hash);
switch_core_hash_init(&loadable_modules.secondary_recover_hash); switch_core_hash_init(&loadable_modules.secondary_recover_hash);
switch_mutex_init(&loadable_modules.mutex, SWITCH_MUTEX_NESTED, loadable_modules.pool); switch_mutex_init(&loadable_modules.mutex, SWITCH_MUTEX_NESTED, loadable_modules.pool);
if (!autoload) return SWITCH_STATUS_SUCCESS; if (!autoload) return SWITCH_STATUS_SUCCESS;
switch_loadable_module_load_module("", "CORE_SOFTTIMER_MODULE", SWITCH_FALSE, &err); /*
switch_loadable_module_load_module("", "CORE_PCM_MODULE", SWITCH_FALSE, &err); switch_core_sqldb_init() is not yet ready and is executed after starting modules from pre_load_modules.conf
switch_loadable_module_load_module("", "CORE_SPEEX_MODULE", SWITCH_FALSE, &err); 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_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_YUV
#ifdef SWITCH_HAVE_VPX #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
#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))) { if ((xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
switch_xml_t mods, ld; switch_xml_t mods, ld;
if ((mods = switch_xml_child(cfg, "modules"))) { 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)) { if (path && zstr(path)) {
path = SWITCH_GLOBAL_dirs.mod_dir; 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)) { if (critical && switch_true(critical)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load critical module '%s', abort()\n", val); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load critical module '%s', abort()\n", val);
abort(); abort();
@ -1935,7 +2303,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo
if (path && zstr(path)) { if (path && zstr(path)) {
path = SWITCH_GLOBAL_dirs.mod_dir; 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++; count++;
} }
} }
@ -2047,6 +2415,7 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void)
{ {
switch_hash_index_t *hi; switch_hash_index_t *hi;
void *val; void *val;
const void *key;
switch_loadable_module_t *module; switch_loadable_module_t *module;
int i; int i;
@ -2069,20 +2438,48 @@ 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)) { 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); switch_core_hash_this(hi, NULL, NULL, &val);
module = (switch_loadable_module_t *)val; module = (switch_loadable_module_t *)val;
if (!module->perm) { if (module->type != SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
do_shutdown(module, SWITCH_TRUE, SWITCH_FALSE, SWITCH_FALSE, NULL); do_shutdown(module, SWITCH_TRUE, SWITCH_FALSE, SWITCH_FALSE, NULL);
} }
} }
switch_yield(1000000); 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)) { 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); switch_core_hash_this(hi, NULL, NULL, &val);
module = (switch_loadable_module_t *) val; if ((module = (switch_loadable_module_t *)val)) {
if (!module->perm) { if (module->type == SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL); do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL);
} }
} }
}
switch_core_hash_destroy(&loadable_modules.module_hash); switch_core_hash_destroy(&loadable_modules.module_hash);
switch_core_hash_destroy(&loadable_modules.endpoint_hash); switch_core_hash_destroy(&loadable_modules.endpoint_hash);
@ -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.say_hash);
switch_core_hash_destroy(&loadable_modules.management_hash); switch_core_hash_destroy(&loadable_modules.management_hash);
switch_core_hash_destroy(&loadable_modules.limit_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_hash_destroy(&loadable_modules.dialplan_hash);
switch_core_destroy_memory_pool(&loadable_modules.pool); 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; 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_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(const char *name, const char *modname)
{ {
switch_codec_interface_t *codec = NULL; 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: case SWITCH_LIMIT_INTERFACE:
ALLOC_INTERFACE(limit) ALLOC_INTERFACE(limit)
case SWITCH_DATABASE_INTERFACE:
ALLOC_INTERFACE(database)
default: default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Module Type!\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Module Type!\n");
return NULL; return NULL;