diff --git a/Makefile.am b/Makefile.am index f10b10ef63..c829af74aa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -103,6 +103,11 @@ CORE_CFLAGS += $(RESAMPLE_CFLAGS) CORE_LIBS = libs/apr/libapr-1.la libs/apr-util/libaprutil-1.la CORE_LIBS += libs/sqlite/libsqlite3.la libs/pcre/libpcre.la CORE_LIBS += libs/srtp/libsrtp.la $(RESAMPLE_LIB) +if ADD_ODBC +libfreeswitch_la_SOURCES += src/switch_odbc.c +library_include_HEADERS += src/include/switch_odbc.h +CORE_LIBS += -lodbc +endif lib_LTLIBRARIES = libfreeswitch.la libfreeswitch_la_CFLAGS = $(CORE_CFLAGS) $(AM_CFLAGS) diff --git a/configure.in b/configure.in index 14b67d349a..c238e10f43 100644 --- a/configure.in +++ b/configure.in @@ -314,10 +314,14 @@ AC_SUBST(LIBCURL_DEPS) AC_ARG_ENABLE(crash-protection, [ --enable-crash-protection Compile with CRASH Protection],,[enable_crash_prot="no"]) +AC_ARG_ENABLE(core-odbc-support, + [ --enable-core-odbc-support Compile with ODBC Support],,[enable_core_odbc_support="no"]) + #AX_LIB_MYSQL([MINIMUM-VERSION]) AX_LIB_MYSQL AM_CONDITIONAL([CRASHPROT],[test "x$enable_crash_prot" != "xno"]) +AM_CONDITIONAL([ADD_ODBC],[test "x$enable_core_odbc_support" != "xno"]) AM_CONDITIONAL([HAVE_MYSQL],[test "$have_mysql" = "yes"]) AC_CONFIG_FILES([Makefile diff --git a/src/include/switch_odbc.h b/src/include/switch_odbc.h new file mode 100644 index 0000000000..7b4c908cad --- /dev/null +++ b/src/include/switch_odbc.h @@ -0,0 +1,82 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * switch_odbc.h -- ODBC + * + */ + +#ifndef SWITCH_ODBC_H +#define SWITCH_ODBC_H + +#include +#include +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4201) +#include +#pragma warning(pop) +#else +#include +#endif +#include + +SWITCH_BEGIN_EXTERN_C struct switch_odbc_handle; + +typedef enum { + SWITCH_ODBC_STATE_INIT, + SWITCH_ODBC_STATE_DOWN, + SWITCH_ODBC_STATE_CONNECTED, + SWITCH_ODBC_STATE_ERROR +} switch_odbc_state_t; +typedef struct switch_odbc_handle switch_odbc_handle_t; + +typedef enum { + SWITCH_ODBC_SUCCESS = 0, + SWITCH_ODBC_FAIL = -1 +} switch_odbc_status_t; + +SWITCH_DECLARE(switch_odbc_handle_t) * switch_odbc_handle_new(char *dsn, char *username, char *password); +SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_disconnect(switch_odbc_handle_t *handle); +SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_connect(switch_odbc_handle_t *handle); +SWITCH_DECLARE(void) switch_odbc_handle_destroy(switch_odbc_handle_t **handlep); +SWITCH_DECLARE(switch_odbc_state_t) switch_odbc_handle_get_state(switch_odbc_handle_t *handle); +SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_exec(switch_odbc_handle_t *handle, char *sql, SQLHSTMT * rstmt); +SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec(switch_odbc_handle_t *handle, + char *sql, switch_core_db_callback_func_t callback, void *pdata); +SWITCH_DECLARE(char *) switch_odbc_handle_get_error(switch_odbc_handle_t *handle, SQLHSTMT stmt); +SWITCH_END_EXTERN_C +#endif +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */ diff --git a/src/mod/endpoints/mod_sofia/Makefile b/src/mod/endpoints/mod_sofia/Makefile index 67f0aeca64..79517d58c6 100644 --- a/src/mod/endpoints/mod_sofia/Makefile +++ b/src/mod/endpoints/mod_sofia/Makefile @@ -12,6 +12,8 @@ LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/sdp -I$(SOFIAUA_DIR)/sip LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/soa -I$(SOFIAUA_DIR)/sresolv LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/stun -I$(SOFIAUA_DIR)/su LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/tport -I$(SOFIAUA_DIR)/url +LOCAL_CFLAGS += `if test -f $(BASE)/.libs/libfreeswitch_la-switch_odbc.o ; then echo -DSWITCH_HAVE_ODBC; fi ;` + LOCAL_OBJS=sofia.o sofia_glue.o sofia_presence.o sofia_reg.o LOCAL_SOURCES=sofia.c sofia_glue.c sofia_presense.c sofia_reg.c mod_sofia.c diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 3f55cee1f8..6ec4b9669c 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -40,6 +40,9 @@ #define HAVE_APR #include +#ifdef SWITCH_HAVE_ODBC +#include +#endif static const char modname[] = "mod_sofia"; static const switch_state_handler_table_t noop_state_handler = { 0 }; @@ -221,6 +224,13 @@ struct sofia_profile { su_home_t *home; switch_hash_t *profile_hash; switch_hash_t *chat_hash; + switch_core_db_t *master_db; +#ifdef SWITCH_HAVE_ODBC + char *odbc_dsn; + char *odbc_user; + char *odbc_pass; + switch_odbc_handle_t *master_odbc; +#endif }; @@ -328,8 +338,6 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session); uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t * sdp); -char *sofia_reg_get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex); - void sofia_presence_establish_presence(sofia_profile_t * profile); void sofia_handle_sip_i_state(int status, @@ -387,8 +395,8 @@ void sofia_presence_handle_sip_i_subscribe(int status, sofia_profile_t *sofia_glue_find_profile(char *key); void sofia_glue_add_profile(char *key, sofia_profile_t * profile); -void sofia_glue_execute_sql(char *dbname, char *sql, switch_mutex_t * mutex); -void sofia_reg_check_expire(switch_core_db_t *db, sofia_profile_t * profile, time_t now); +void sofia_glue_execute_sql(sofia_profile_t *profile, switch_bool_t master, char *sql, switch_mutex_t *mutex); +void sofia_reg_check_expire(sofia_profile_t * profile, time_t now); void sofia_reg_check_gateway(sofia_profile_t * profile, time_t now); void sofia_reg_unregister(sofia_profile_t * profile); switch_status_t sofia_glue_ext_address_lookup(char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool); @@ -404,3 +412,12 @@ void sofia_presence_set_chat_hash(private_object_t * tech_pvt, sip_t const *sip) switch_status_t sofia_on_hangup(switch_core_session_t *session); char *sofia_glue_get_url_from_contact(char *buf, uint8_t to_dup); void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip); +void sofia_glue_sql_close(sofia_profile_t *profile); +int sofia_glue_init_sql(sofia_profile_t *profile); +switch_bool_t sofia_glue_execute_sql_callback(sofia_profile_t *profile, + switch_bool_t master, + switch_mutex_t *mutex, + char *sql, + switch_core_db_callback_func_t callback, + void *pdata); +char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index ee8dec5636..a26552d7ee 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -36,41 +36,6 @@ extern su_log_t tport_log[]; -static char reg_sql[] = - "CREATE TABLE sip_registrations (\n" - " user VARCHAR(255),\n" - " host VARCHAR(255),\n" - " contact VARCHAR(1024),\n" - " status VARCHAR(255),\n" - " rpid VARCHAR(255),\n" - " expires INTEGER(8)" ");\n"; - - -static char sub_sql[] = - "CREATE TABLE sip_subscriptions (\n" - " proto VARCHAR(255),\n" - " user VARCHAR(255),\n" - " host VARCHAR(255),\n" - " sub_to_user VARCHAR(255),\n" - " sub_to_host VARCHAR(255),\n" - " event VARCHAR(255),\n" - " contact VARCHAR(1024),\n" - " call_id VARCHAR(255),\n" - " full_from VARCHAR(255),\n" - " full_via VARCHAR(255),\n" - " expires INTEGER(8)" ");\n"; - - -static char auth_sql[] = - "CREATE TABLE sip_authentication (\n" - " user VARCHAR(255),\n" - " host VARCHAR(255),\n" - " passwd VARCHAR(255),\n" - " nonce VARCHAR(255),\n" - " expires INTEGER(8)" - ");\n"; - - void sofia_event_callback(nua_event_t event, int status, char const *phrase, @@ -253,7 +218,7 @@ void event_handler(switch_event_t *event) } if (sql) { - sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex); + sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, profile->ireg_mutex); switch_safe_free(sql); sql = NULL; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Propagating registration for %s@%s->%s\n", from_user, from_host, contact_str); @@ -272,7 +237,6 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t * thread, void sip_alias_node_t *node; uint32_t ireg_loops = 0; uint32_t gateway_loops = 0; - switch_core_db_t *db; switch_event_t *s_event; profile->s_root = su_root_create(NULL); @@ -320,11 +284,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t * thread, void } - if ((db = switch_core_db_open_file(profile->dbname))) { - switch_core_db_test_reactive(db, "select contact from sip_registrations", reg_sql); - switch_core_db_test_reactive(db, "select contact from sip_subscriptions", sub_sql); - switch_core_db_test_reactive(db, "select * from sip_authentication", auth_sql); - } else { + if (!sofia_glue_init_sql(profile)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n"); return NULL; } @@ -362,7 +322,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t * thread, void while (mod_sofia_globals.running == 1) { if (++ireg_loops >= IREG_SECONDS) { - sofia_reg_check_expire(db, profile, time(NULL)); + sofia_reg_check_expire(profile, time(NULL)); ireg_loops = 0; } @@ -373,8 +333,9 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t * thread, void su_root_step(profile->s_root, 1000); } + + sofia_glue_sql_close(profile); - switch_core_db_close(db); sofia_reg_unregister(profile); su_home_unref(profile->home); @@ -496,6 +457,7 @@ switch_status_t config_sofia(int reload) profile->name = switch_core_strdup(profile->pool, xprofilename); snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename); + profile->dbname = switch_core_strdup(profile->pool, url); switch_core_hash_init(&profile->chat_hash, profile->pool); @@ -510,6 +472,22 @@ switch_status_t config_sofia(int reload) profile->debug = atoi(val); } else if (!strcasecmp(var, "use-rtp-timer") && switch_true(val)) { switch_set_flag(profile, TFLAG_TIMER); + + } else if (!strcasecmp(var, "odbc-dsn")) { +#ifdef SWITCH_HAVE_ODBC + profile->odbc_dsn = switch_core_strdup(profile->pool, val); + if ((profile->odbc_user = strchr(profile->odbc_dsn, ':'))) { + *profile->odbc_user++ = '\0'; + } + if ((profile->odbc_pass = strchr(profile->odbc_user, ':'))) { + *profile->odbc_pass++ = '\0'; + } + + +#else + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n"); +#endif + } else if (!strcasecmp(var, "inbound-no-media") && switch_true(val)) { switch_set_flag(profile, TFLAG_INB_NOMEDIA); } else if (!strcasecmp(var, "inbound-late-negotiation") && switch_true(val)) { diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index a8cba82812..d4353eb538 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -1119,7 +1119,91 @@ void sofia_glue_add_profile(char *key, sofia_profile_t * profile) switch_mutex_unlock(mod_sofia_globals.hash_mutex); } -void sofia_glue_execute_sql(char *dbname, char *sql, switch_mutex_t * mutex) +int sofia_glue_init_sql(sofia_profile_t *profile) +{ + + + char reg_sql[] = + "CREATE TABLE sip_registrations (\n" + " user VARCHAR(255),\n" + " host VARCHAR(255),\n" + " contact VARCHAR(1024),\n" + " status VARCHAR(255),\n" + " rpid VARCHAR(255),\n" + " expires INTEGER(8)" ");\n"; + + + char sub_sql[] = + "CREATE TABLE sip_subscriptions (\n" + " proto VARCHAR(255),\n" + " user VARCHAR(255),\n" + " host VARCHAR(255),\n" + " sub_to_user VARCHAR(255),\n" + " sub_to_host VARCHAR(255),\n" + " event VARCHAR(255),\n" + " contact VARCHAR(1024),\n" + " call_id VARCHAR(255),\n" + " full_from VARCHAR(255),\n" + " full_via VARCHAR(255),\n" + " expires INTEGER(8)" ");\n"; + + + char auth_sql[] = + "CREATE TABLE sip_authentication (\n" + " user VARCHAR(255),\n" + " host VARCHAR(255),\n" + " passwd VARCHAR(255),\n" + " nonce VARCHAR(255),\n" + " expires INTEGER(8)" + ");\n"; + +#ifdef SWITCH_HAVE_ODBC + if (profile->odbc_dsn) { + if (!(profile->master_odbc = switch_odbc_handle_new(profile->odbc_dsn, profile->odbc_user, profile->odbc_pass))) { + return 0; + } + if (switch_odbc_handle_connect(profile->master_odbc) != SWITCH_ODBC_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Connecting ODBC DSN: %s\n", profile->odbc_dsn); + return 0; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected ODBC DSN: %s\n", profile->odbc_dsn); + + switch_odbc_handle_exec(profile->master_odbc, reg_sql, NULL); + switch_odbc_handle_exec(profile->master_odbc, sub_sql, NULL); + switch_odbc_handle_exec(profile->master_odbc, auth_sql, NULL); + } else { +#endif + if (!(profile->master_db = switch_core_db_open_file(profile->dbname))) { + return 0; + } + + switch_core_db_test_reactive(profile->master_db, "select contact from sip_registrations", reg_sql); + switch_core_db_test_reactive(profile->master_db, "select contact from sip_subscriptions", sub_sql); + switch_core_db_test_reactive(profile->master_db, "select * from sip_authentication", auth_sql); + +#ifdef SWITCH_HAVE_ODBC + } +#endif + + return 1; +} + +void sofia_glue_sql_close(sofia_profile_t *profile) +{ +#ifdef SWITCH_HAVE_ODBC + if (profile->odbc_dsn) { + switch_odbc_handle_destroy(&profile->master_odbc); + } else { +#endif + switch_core_db_close(profile->master_db); +#ifdef SWITCH_HAVE_ODBC + } +#endif +} + + +void sofia_glue_execute_sql(sofia_profile_t *profile, switch_bool_t master, char *sql, switch_mutex_t *mutex) { switch_core_db_t *db; @@ -1127,12 +1211,38 @@ void sofia_glue_execute_sql(char *dbname, char *sql, switch_mutex_t * mutex) switch_mutex_lock(mutex); } - if (!(db = switch_core_db_open_file(dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname); - goto end; +#ifdef SWITCH_HAVE_ODBC + if (profile->odbc_dsn) { + SQLHSTMT stmt; + if (switch_odbc_handle_exec(profile->master_odbc, sql, &stmt) != SWITCH_ODBC_SUCCESS) { + char *err_str; + err_str = switch_odbc_handle_get_error(profile->master_odbc, stmt); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(err_str)); + switch_safe_free(err_str); + } + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } else { +#endif + + + if (master) { + db = profile->master_db; + } else { + if (!(db = switch_core_db_open_file(profile->dbname))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); + goto end; + } } switch_core_db_persistant_execute(db, sql, 25); - switch_core_db_close(db); + if (!master) { + switch_core_db_close(db); + } + + +#ifdef SWITCH_HAVE_ODBC + } +#endif + end: if (mutex) { @@ -1141,6 +1251,159 @@ void sofia_glue_execute_sql(char *dbname, char *sql, switch_mutex_t * mutex) } +switch_bool_t sofia_glue_execute_sql_callback(sofia_profile_t *profile, + switch_bool_t master, + switch_mutex_t *mutex, + char *sql, + switch_core_db_callback_func_t callback, + void *pdata) +{ + switch_bool_t ret = SWITCH_FALSE; + switch_core_db_t *db; + char *errmsg = NULL; + + if (mutex) { + switch_mutex_lock(mutex); + } + + +#ifdef SWITCH_HAVE_ODBC + if (profile->odbc_dsn) { + switch_odbc_handle_callback_exec(profile->master_odbc, sql, callback, pdata); + } else { +#endif + + + if (master) { + db = profile->master_db; + } else { + if (!(db = switch_core_db_open_file(profile->dbname))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); + goto end; + } + } + + switch_core_db_exec(db, sql, callback, pdata, &errmsg); + + if (errmsg) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg); + free(errmsg); + } + + if (!master && db) { + switch_core_db_close(db); + } + +#ifdef SWITCH_HAVE_ODBC + } +#endif + + + end: + + if (mutex) { + switch_mutex_unlock(mutex); + } + + + + return ret; + +} + +#ifdef SWITCH_HAVE_ODBC +static char *sofia_glue_execute_sql2str_odbc(sofia_profile_t *profile, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len) +{ + char *ret = NULL; + SQLHSTMT stmt; + SQLCHAR name[1024]; + SQLINTEGER m = 0; + + if (switch_odbc_handle_exec(profile->master_odbc, sql, &stmt) == SWITCH_ODBC_SUCCESS) { + SQLSMALLINT NameLength, DataType, DecimalDigits, Nullable; + SQLUINTEGER ColumnSize; + SQLRowCount(stmt, &m); + + if (m <= 0) { + return NULL; + } + + if (SQLFetch(stmt) != SQL_SUCCESS) { + return NULL; + } + + SQLDescribeCol(stmt, 1, name, sizeof(name), &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable); + SQLGetData(stmt, 1, SQL_C_CHAR, (SQLCHAR *)resbuf, len, NULL); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ret = resbuf; + } + + return ret; +} + +#endif + +char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len) +{ + switch_core_db_t *db; + switch_core_db_stmt_t *stmt; + char *ret = NULL; + +#ifdef SWITCH_HAVE_ODBC + if (profile->odbc_dsn) { + return sofia_glue_execute_sql2str_odbc(profile, mutex, sql, resbuf, len); + } +#endif + + if (mutex) { + switch_mutex_lock(mutex); + } + + if (!(db = switch_core_db_open_file(profile->dbname))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); + goto end; + } + + if (switch_core_db_prepare(db, sql, -1, &stmt, 0)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Statement Error!\n"); + goto fail; + } else { + int running = 1; + int colcount; + + while (running < 5000) { + int result = switch_core_db_step(stmt); + + if (result == SWITCH_CORE_DB_ROW) { + if ((colcount = switch_core_db_column_count(stmt))) { + switch_copy_string(resbuf, (char *) switch_core_db_column_text(stmt, 0), len); + ret = resbuf; + } + break; + } else if (result == SWITCH_CORE_DB_BUSY) { + running++; + switch_yield(1000); + continue; + } + break; + } + + switch_core_db_finalize(stmt); + } + + + fail: + + switch_core_db_close(db); + + end: + if (mutex) { + switch_mutex_unlock(mutex); + } + + return ret; +} + int sofia_glue_get_user_host(char *in, char **user, char **host) { char *p, *h, *u = in; diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index c3562560e1..18411a2dc0 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -105,8 +105,7 @@ switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char void sofia_presence_cancel(void) { - char *sql, *errmsg = NULL; - switch_core_db_t *db; + char *sql; sofia_profile_t *profile; switch_hash_index_t *hi; void *val; @@ -120,47 +119,30 @@ void sofia_presence_cancel(void) continue; } - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); + if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_sub_callback, profile) != SWITCH_TRUE) { continue; } - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sofia_presence_sub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_core_db_close(db); } switch_safe_free(sql); + switch_mutex_unlock(mod_sofia_globals.hash_mutex); } - switch_mutex_unlock(mod_sofia_globals.hash_mutex); } void sofia_presence_establish_presence(sofia_profile_t * profile) { - char *sql, *errmsg = NULL; - switch_core_db_t *db; - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); + if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, + "select user,host,'Registered','unknown','' from sip_registrations", + sofia_presence_resub_callback, profile) != SWITCH_TRUE) { return; } - if ((sql = switch_mprintf("select user,host,'Registered','unknown','' sip_registrations"))) { - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sofia_presence_resub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_safe_free(sql); + if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, + "select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions " + "where proto='ext' or proto='user' or proto='conf'", + sofia_presence_resub_callback, profile) != SWITCH_TRUE) { + return; } - - if ((sql = switch_mprintf("select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions " - "where proto='ext' or proto='user' or proto='conf'"))) { - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sofia_presence_resub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_safe_free(sql); - } - - switch_core_db_close(db); - } @@ -196,9 +178,7 @@ void sofia_presence_mwi_event_handler(switch_event_t *event) { char *account, *dup_account, *yn, *host, *user; char *sql; - switch_core_db_t *db; sofia_profile_t *profile; - char *errmsg = NULL; switch_stream_handle_t stream = { 0 }; switch_event_header_t *hp; @@ -222,13 +202,7 @@ void sofia_presence_mwi_event_handler(switch_event_t *event) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find profile for host %s\n", switch_str_nil(host)); return; } - - - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - return; - } - + SWITCH_STANDARD_STREAM(stream); for (hp = event->headers; hp; hp = hp->next) { @@ -246,12 +220,14 @@ void sofia_presence_mwi_event_handler(switch_event_t *event) assert (sql != NULL); - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sofia_presence_mwi_callback, profile, &errmsg); - if (errmsg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: %s\n", errmsg); - } - switch_mutex_unlock(profile->ireg_mutex); + sofia_glue_execute_sql_callback(profile, + SWITCH_FALSE, + profile->ireg_mutex, + sql, + sofia_presence_mwi_callback, + profile); + + switch_safe_free(sql); switch_safe_free(dup_account); } @@ -269,8 +245,6 @@ void sofia_presence_event_handler(switch_event_t *event) //char *event_subtype = switch_event_get_header(event, "event_subtype"); char *sql = NULL; char *euser = NULL, *user = NULL, *host = NULL; - char *errmsg; - switch_core_db_t *db; if (rpid && !strcasecmp(rpid, "n/a")) { @@ -310,7 +284,8 @@ void sofia_presence_event_handler(switch_event_t *event) } else { sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence'", status, rpid); } - + + assert(sql != NULL); switch_mutex_lock(mod_sofia_globals.hash_mutex); for (hi = switch_hash_first(switch_hash_pool_get(mod_sofia_globals.profile_hash), mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, NULL, NULL, &val); @@ -319,20 +294,18 @@ void sofia_presence_event_handler(switch_event_t *event) continue; } - if (sql) { - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - continue; - } - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sofia_presence_sub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_core_db_close(db); - } + + sofia_glue_execute_sql_callback(profile, + SWITCH_FALSE, + profile->ireg_mutex, + sql, + sofia_presence_sub_callback, + profile); + } switch_mutex_unlock(mod_sofia_globals.hash_mutex); - + free(sql); return; } @@ -365,7 +338,6 @@ void sofia_presence_event_handler(switch_event_t *event) switch (event->event_id) { case SWITCH_EVENT_PRESENCE_PROBE: if (proto) { - switch_core_db_t *db = NULL; char *to = switch_event_get_header(event, "to"); char *user, *euser, *host, *p; @@ -382,23 +354,19 @@ void sofia_presence_event_handler(switch_event_t *event) } if (euser && host && - (sql = - switch_mprintf("select user,host,status,rpid,'' from sip_registrations where user='%q' and host='%q'", - euser, host)) && (profile = sofia_glue_find_profile(host))) { - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - switch_safe_free(user); - switch_safe_free(sql); - return; - } + (sql = switch_mprintf("select user,host,status,rpid,'' from sip_registrations where user='%q' and host='%q'", + euser, host)) && (profile = sofia_glue_find_profile(host))) { + + sofia_glue_execute_sql_callback(profile, + SWITCH_FALSE, + profile->ireg_mutex, + sql, + sofia_presence_resub_callback, + profile); - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sofia_presence_resub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); switch_safe_free(sql); } switch_safe_free(user); - switch_core_db_close(db); } return; case SWITCH_EVENT_PRESENCE_IN: @@ -426,15 +394,13 @@ void sofia_presence_event_handler(switch_event_t *event) } if (sql) { - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - continue; - } - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sofia_presence_sub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); + sofia_glue_execute_sql_callback(profile, + SWITCH_FALSE, + profile->ireg_mutex, + sql, + sofia_presence_sub_callback, + profile); - switch_core_db_close(db); } } switch_mutex_unlock(mod_sofia_globals.hash_mutex); @@ -665,8 +631,6 @@ void sofia_presence_handle_sip_i_subscribe(int status, char *to_str = NULL; char *full_from = NULL; char *full_via = NULL; - switch_core_db_t *db; - char *errmsg; char *sstr; const char *display = "\"user\""; switch_event_t *sevent; @@ -762,17 +726,28 @@ void sofia_presence_handle_sip_i_subscribe(int status, from_host = "n/a"; } - if ((sql = switch_mprintf("delete from sip_subscriptions where " - "proto='%q' and user='%q' and host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q';\n" - "insert into sip_subscriptions values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld)", - proto, - from_user, - from_host, - to_user, - to_host, event, proto, from_user, from_host, to_user, to_host, event, contact_str, call_id, full_from, full_via, exp))) { - sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex); - switch_safe_free(sql); - } + switch_mutex_lock(profile->ireg_mutex); + + sql = switch_mprintf("delete from sip_subscriptions where " + "proto='%q' and user='%q' and host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'", + proto, + from_user, + from_host, + to_user, + to_host, event, proto + ); + + assert(sql != NULL); + sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, NULL); + free(sql); + sql = switch_mprintf("insert into sip_subscriptions values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld)", + proto, from_user, from_host, to_user, to_host, event, contact_str, call_id, full_from, full_via, exp); + + assert(sql != NULL); + sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, NULL); + free(sql); + + switch_mutex_unlock(profile->ireg_mutex); sstr = switch_mprintf("active;expires=%ld", exp_raw); @@ -784,18 +759,17 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_safe_free(sstr); - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - goto end; - } if ((sql = switch_mprintf("select * from sip_subscriptions where user='%q' and host='%q'", to_user, to_host, to_user, to_host))) { - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sofia_presence_sub_reg_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); + sofia_glue_execute_sql_callback(profile, + SWITCH_FALSE, + profile->ireg_mutex, + sql, + sofia_presence_sub_reg_callback, + profile); + switch_safe_free(sql); } - switch_core_db_close(db); - end: + end: if (event) { su_free(profile->home, event); @@ -878,7 +852,7 @@ void sofia_presence_handle_sip_i_publish(nua_t * nua, sofia_profile_t * profile, if ((sql = switch_mprintf("update sip_registrations set status='%q',rpid='%q' where user='%q' and host='%q'", note_txt, rpid, from_user, from_host))) { - sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex); + sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, profile->ireg_mutex); switch_safe_free(sql); } diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 6b14295218..3969d265c8 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -35,7 +35,7 @@ #include "mod_sofia.h" -void sofia_reg_unregister(sofia_profile_t * profile) +void sofia_reg_unregister(sofia_profile_t *profile) { outbound_reg_t *gateway_ptr; for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { @@ -48,7 +48,7 @@ void sofia_reg_unregister(sofia_profile_t * profile) } } -void sofia_reg_check_gateway(sofia_profile_t * profile, time_t now) +void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) { outbound_reg_t *gateway_ptr; for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { @@ -133,73 +133,74 @@ int sofia_reg_del_callback(void *pArg, int argc, char **argv, char **columnNames return 0; } -void sofia_reg_check_expire(switch_core_db_t *db, sofia_profile_t * profile, time_t now) +void sofia_reg_check_expire(sofia_profile_t *profile, time_t now) { char sql[1024]; - char *errmsg; - if (!db) { +#ifdef SWITCH_HAVE_ODBC + if (profile->odbc_dsn) { + if (!profile->master_odbc) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); + return; + } + } else { +#endif + if (!profile->master_db) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); return; } +#ifdef SWITCH_HAVE_ODBC + } +#endif + + snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0 and expires <= %ld", profile->name, (long) now); switch_mutex_lock(profile->ireg_mutex); - snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0 and expires < %ld", profile->name, (long) now); - switch_core_db_exec(db, sql, sofia_reg_del_callback, NULL, &errmsg); - - if (errmsg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", sql, errmsg); - switch_safe_free(errmsg); - errmsg = NULL; - } - - snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires < %ld", (long) now); - switch_core_db_persistant_execute(db, sql, 1000); - snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires < %ld", (long) now); - switch_core_db_persistant_execute(db, sql, 1000); - snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires < %ld", (long) now); - switch_core_db_persistant_execute(db, sql, 1000); + sofia_glue_execute_sql_callback(profile, + SWITCH_TRUE, + NULL, + sql, + sofia_reg_del_callback, + NULL); + + snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires <= %ld", (long) now); + sofia_glue_execute_sql(profile, SWITCH_TRUE, sql, NULL); + snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires <= %ld", (long) now); + sofia_glue_execute_sql(profile, SWITCH_TRUE, sql, NULL); + snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires <= %ld", (long) now); + sofia_glue_execute_sql(profile, SWITCH_TRUE, sql, NULL); switch_mutex_unlock(profile->ireg_mutex); } -char *sofia_reg_find_reg_url(sofia_profile_t * profile, const char *user, const char *host, char *val, switch_size_t len) +char *sofia_reg_find_reg_url(sofia_profile_t *profile, const char *user, const char *host, char *val, switch_size_t len) { - char *errmsg; struct callback_t cbt = { 0 }; - switch_core_db_t *db; if (!user) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Called with null user!\n"); return NULL; } - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - return NULL; - } - cbt.val = val; cbt.len = len; - switch_mutex_lock(profile->ireg_mutex); + if (host) { snprintf(val, len, "select contact from sip_registrations where user='%s' and host='%s'", user, host); } else { snprintf(val, len, "select contact from sip_registrations where user='%s'", user); } - switch_core_db_exec(db, val, sofia_reg_find_callback, &cbt, &errmsg); - if (errmsg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", val, errmsg); - switch_safe_free(errmsg); - errmsg = NULL; - } + sofia_glue_execute_sql_callback(profile, + SWITCH_FALSE, + profile->ireg_mutex, + val, + sofia_reg_find_callback, + &cbt); - switch_mutex_unlock(profile->ireg_mutex); - switch_core_db_close(db); if (cbt.matches) { return val; } else { @@ -207,73 +208,20 @@ char *sofia_reg_find_reg_url(sofia_profile_t * profile, const char *user, const } } -char *sofia_reg_get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex) +static char *sofia_reg_get_auth_data(sofia_profile_t *profile, char *nonce, char *npassword, size_t len, switch_mutex_t *mutex) { - switch_core_db_t *db; - switch_core_db_stmt_t *stmt; - char *sql = NULL, *ret = NULL; - - if (mutex) { - switch_mutex_lock(mutex); - } - - if (!dbname) { - goto end; - } - - if (!(db = switch_core_db_open_file(dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname); - goto end; - } - + char *sql, *ret; + sql = switch_mprintf("select passwd from sip_authentication where nonce='%q'", nonce); - if (switch_core_db_prepare(db, sql, -1, &stmt, 0)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Statement Error!\n"); - goto fail; - } else { - int running = 1; - int colcount; + assert(sql != NULL); - while (running < 5000) { - int result = switch_core_db_step(stmt); - - if (result == SWITCH_CORE_DB_ROW) { - if ((colcount = switch_core_db_column_count(stmt))) { - switch_copy_string(npassword, (char *) switch_core_db_column_text(stmt, 0), len); - ret = npassword; - } - break; - } else if (result == SWITCH_CORE_DB_BUSY) { - running++; - switch_yield(1000); - continue; - } - break; - } - - switch_core_db_finalize(stmt); - } - - - fail: - - switch_core_db_close(db); - - end: - if (mutex) { - switch_mutex_unlock(mutex); - } - - if (sql) { - switch_safe_free(sql); - } + ret = sofia_glue_execute_sql2str(profile, mutex, sql, npassword, len); + free(sql); return ret; } - - -uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sip_t const *sip, sofia_regtype_t regtype, char *key, +uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t *profile, nua_handle_t * nh, sip_t const *sip, sofia_regtype_t regtype, char *key, uint32_t keylen) { sip_from_t const *from = NULL; @@ -433,9 +381,18 @@ uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_ha a1_hash = hexdigest; } - sql = switch_mprintf("delete from sip_authentication where user='%q' and host='%q';\n" - "insert into sip_authentication values('%q','%q','%q','%q', %ld)", - from_user, from_host, from_user, from_host, a1_hash, uuid_str, time(NULL) + profile->nonce_ttl); + switch_mutex_lock(profile->ireg_mutex); + sql = switch_mprintf("delete from sip_authentication where user='%q' and host='%q';", from_user, from_host); + assert(sql != NULL); + sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, NULL); + switch_safe_free(sql); + sql = switch_mprintf("insert into sip_authentication values('%q','%q','%q','%q', %ld)", + from_user, from_host, a1_hash, uuid_str, time(NULL) + profile->nonce_ttl); + assert(sql != NULL); + sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, NULL); + switch_safe_free(sql); + switch_mutex_unlock(profile->ireg_mutex); + auth_str = switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", from_host, uuid_str, stale ? " stale=\"true\"," : ""); @@ -448,8 +405,6 @@ uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_ha } - sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex); - switch_safe_free(sql); switch_safe_free(auth_str); ret = 1; } else { @@ -488,7 +443,7 @@ uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_ha } if (sql) { - sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex); + sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, profile->ireg_mutex); switch_safe_free(sql); sql = NULL; } @@ -509,7 +464,7 @@ uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_ha } } else { if ((sql = switch_mprintf("delete from sip_subscriptions where user='%q' and host='%q'", from_user, from_host))) { - sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex); + sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, profile->ireg_mutex); switch_safe_free(sql); sql = NULL; } @@ -542,7 +497,7 @@ uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_ha -void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) +void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t *profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) { char key[128] = ""; @@ -564,7 +519,7 @@ void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t * profile, nua void sofia_reg_handle_sip_r_register(int status, char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) + nua_t * nua, sofia_profile_t *profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) { if (sofia_private && sofia_private->gateway) { switch (status) { @@ -594,7 +549,7 @@ void sofia_reg_handle_sip_r_register(int status, void sofia_reg_handle_sip_r_challenge(int status, char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]) + nua_t * nua, sofia_profile_t *profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]) { outbound_reg_t *gateway = NULL; sip_www_authenticate_t const *authenticate = NULL; @@ -698,7 +653,7 @@ void sofia_reg_handle_sip_r_challenge(int status, } -auth_res_t parse_auth(sofia_profile_t * profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen) +auth_res_t parse_auth(sofia_profile_t *profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen) { int indexnum; const char *cur; @@ -758,7 +713,7 @@ auth_res_t parse_auth(sofia_profile_t * profile, sip_authorization_t const *auth } if (switch_strlen_zero(np)) { - if (!sofia_reg_get_auth_data(profile->dbname, nonce, np, nplen, profile->ireg_mutex)) { + if (!sofia_reg_get_auth_data(profile, nonce, np, nplen, profile->ireg_mutex)) { ret = AUTH_STALE; goto end; } diff --git a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c index 7169852abe..b0ac37fe2e 100644 --- a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c +++ b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c @@ -2761,16 +2761,19 @@ static void message_query_handler(switch_event_t *event) char *account = switch_event_get_header(event, "message-account"); if (account) { - char *text; + char *path, *cmd; - text = switch_mprintf("%s%smwi.js", SWITCH_GLOBAL_dirs.script_dir, SWITCH_PATH_SEPARATOR); - assert(text != NULL); + path = switch_mprintf("%s%smwi.js", SWITCH_GLOBAL_dirs.script_dir, SWITCH_PATH_SEPARATOR); + assert(path != NULL); - if (switch_file_exists(text) == SWITCH_STATUS_SUCCESS) { - js_thread_launch(text); + if (switch_file_exists(path) == SWITCH_STATUS_SUCCESS) { + cmd = switch_mprintf("%s %s", path, account); + assert(cmd != NULL); + js_thread_launch(cmd); + switch_safe_free(cmd); } - free(text); + switch_safe_free(path); } } diff --git a/src/mod/languages/mod_spidermonkey_odbc/Makefile b/src/mod/languages/mod_spidermonkey_odbc/Makefile index f64608c506..e53aaf4f05 100644 --- a/src/mod/languages/mod_spidermonkey_odbc/Makefile +++ b/src/mod/languages/mod_spidermonkey_odbc/Makefile @@ -1,28 +1,4 @@ switch_srcdir=../../../.. -ODBC=unixODBC-2.2.12 -ODBC_DIR=$(switch_srcdir)/libs/$(ODBC) -ODBCLA=libodbc.la - -UNINST_ODBCLA=$(ODBC_DIR)/DriverManager/$(ODBCLA) -INST_ODBCLA=$(DESTDIR)$(PREFIX)/lib/$(ODBCLA) - -LOCAL_CFLAGS=-I$(ODBC_DIR)/include -LOCAL_LDFLAGS= -LOCAL_LIBADD=$(UNINST_ODBCLA) - include ../mod_spidermonkey/sm.mak -$(ODBC_DIR): - $(GETLIB) $(ODBC).tar.gz - cd $(ODBC_DIR) && ./configure --prefix=$(PREFIX) --disable-gui --without-x --with-pic - -$(UNINST_ODBCLA): $(ODBC_DIR) - cd $(ODBC_DIR) && $(MAKE) - $(TOUCH_TARGET) - -depend_install: $(INST_ODBCLA) - -$(INST_ODBCLA): $(UNINST_ODBCLA) - cd $(ODBC_DIR) && $(MAKE) install - @$(TOUCH_TARGET) diff --git a/src/mod/languages/mod_spidermonkey_odbc/mod_spidermonkey_odbc.c b/src/mod/languages/mod_spidermonkey_odbc/mod_spidermonkey_odbc.c index 13ec900692..37e695c69e 100644 --- a/src/mod/languages/mod_spidermonkey_odbc/mod_spidermonkey_odbc.c +++ b/src/mod/languages/mod_spidermonkey_odbc/mod_spidermonkey_odbc.c @@ -30,48 +30,19 @@ * */ #include "mod_spidermonkey.h" - - -#include -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4201) -#include -#pragma warning(pop) -#else -#include -#endif -#include +#include static const char modname[] = "ODBC"; struct odbc_obj { - char *dsn; - char *username; - char *password; - SQLHENV env; - SQLHDBC con; + switch_odbc_handle_t *handle; SQLHSTMT stmt; - uint32_t state; SQLCHAR *colbuf; int32 cblen; SQLCHAR *code; int32 codelen; }; - -typedef enum { - ODBC_STATE_INIT, - ODBC_STATE_DOWN, - ODBC_STATE_CONNECTED, - ODBC_STATE_ERROR -} odbc_state_t; -typedef struct odbc_obj odbc_obj_t; - -typedef enum { - ODBC_SUCCESS = 0, - ODBC_FAIL = -1 -} odbc_status_t; - +typedef struct odbc_obj odbc_obj_t; static odbc_obj_t *new_odbc_obj(char *dsn, char *username, char *password) { @@ -81,122 +52,39 @@ static odbc_obj_t *new_odbc_obj(char *dsn, char *username, char *password) goto err; } - if (!(new_obj->dsn = strdup(dsn))) { + if (!(new_obj->handle = switch_odbc_handle_new(dsn, username, password))) { goto err; } - - if (!(new_obj->username = strdup(username))) { - goto err; - } - - if (!(new_obj->password = strdup(password))) { - goto err; - } - - new_obj->env = SQL_NULL_HANDLE; - new_obj->state = ODBC_STATE_INIT; - + return new_obj; err: if (new_obj) { - switch_safe_free(new_obj->dsn); - switch_safe_free(new_obj->username); - switch_safe_free(new_obj->password); + if (new_obj->handle) { + switch_odbc_handle_destroy(&new_obj->handle); + } switch_safe_free(new_obj); } return NULL; } -odbc_status_t odbc_obj_disconnect(odbc_obj_t * obj) +switch_odbc_status_t odbc_obj_connect(odbc_obj_t *obj) { - int result; - - if (obj->state == ODBC_STATE_CONNECTED) { - result = SQLDisconnect(obj->con); - if (result == ODBC_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disconnected %d from [%s]\n", result, obj->dsn); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Disconnectiong [%s]\n", obj->dsn); - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "[%s] already disconnected\n", obj->dsn); - } - - obj->state = ODBC_STATE_DOWN; - - return ODBC_SUCCESS; -} - -odbc_status_t odbc_obj_connect(odbc_obj_t * obj) -{ - int result; - SQLINTEGER err; - int16_t mlen; - unsigned char msg[200], stat[10]; - - if (obj->env == SQL_NULL_HANDLE) { - result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &obj->env); - - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error AllocHandle\n"); - return ODBC_FAIL; - } - - result = SQLSetEnvAttr(obj->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); - - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error SetEnv\n"); - SQLFreeHandle(SQL_HANDLE_ENV, obj->env); - return ODBC_FAIL; - } - - result = SQLAllocHandle(SQL_HANDLE_DBC, obj->env, &obj->con); - - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error AllocHDB %d\n", result); - SQLFreeHandle(SQL_HANDLE_ENV, obj->env); - return ODBC_FAIL; - } - SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); - } - if (obj->state == ODBC_STATE_CONNECTED) { - odbc_obj_disconnect(obj); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-connecting %s\n", obj->dsn); - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connecting %s\n", obj->dsn); - - result = SQLConnect(obj->con, (SQLCHAR *) obj->dsn, SQL_NTS, (SQLCHAR *) obj->username, SQL_NTS, (SQLCHAR *) obj->password, SQL_NTS); - - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { - SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); - SQLFreeHandle(SQL_HANDLE_ENV, obj->env); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error SQLConnect=%d errno=%d %s\n", result, (int) err, msg); - return ODBC_FAIL; - } else { - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connected to [%s]\n", obj->dsn); - obj->state = ODBC_STATE_CONNECTED; - } - - return ODBC_SUCCESS; + + return switch_odbc_handle_connect(obj->handle); } static void destroy_odbc_obj(odbc_obj_t ** objp) { odbc_obj_t *obj = *objp; - odbc_obj_disconnect(obj); - - SQLFreeHandle(SQL_HANDLE_STMT, obj->stmt); - SQLFreeHandle(SQL_HANDLE_DBC, obj->con); - SQLFreeHandle(SQL_HANDLE_ENV, obj->env); - - switch_safe_free(obj->dsn); - switch_safe_free(obj->username); - switch_safe_free(obj->password); + if (obj->handle) { + switch_odbc_handle_destroy(&obj->handle); + } + if (obj->stmt) { + SQLFreeHandle(SQL_HANDLE_STMT, obj->stmt); + } switch_safe_free(obj->colbuf); switch_safe_free(obj->code); switch_safe_free(obj); @@ -205,7 +93,7 @@ static void destroy_odbc_obj(odbc_obj_t ** objp) /* ODBC Object */ /*********************************************************************************/ -static JSBool odbc_construct(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) +static JSBool odbc_construct(JSContext * cx, JSObject * obj, uintN argc, jsval *argv, jsval *rval) { odbc_obj_t *odbc_obj = NULL; char *dsn, *username, *password; @@ -228,7 +116,15 @@ static JSBool odbc_construct(JSContext * cx, JSObject * obj, uintN argc, jsval * } } - if (dsn && username && password) { + if (switch_strlen_zero(username)) { + username = NULL; + } + + if (switch_strlen_zero(password)) { + password = NULL; + } + + if (dsn) { odbc_obj = new_odbc_obj(dsn, username, password); } @@ -266,13 +162,13 @@ static void odbc_destroy(JSContext * cx, JSObject * obj) } } -static JSBool odbc_connect(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) +static JSBool odbc_connect(JSContext * cx, JSObject * obj, uintN argc, jsval *argv, jsval *rval) { odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj); JSBool tf = JS_TRUE; if (odbc_obj) { - if (odbc_obj_connect(odbc_obj) == ODBC_SUCCESS) { + if (odbc_obj_connect(odbc_obj) == SWITCH_ODBC_SUCCESS) { tf = JS_TRUE; } else { tf = JS_FALSE; @@ -284,18 +180,18 @@ static JSBool odbc_connect(JSContext * cx, JSObject * obj, uintN argc, jsval * a return JS_TRUE; } -static JSBool odbc_exec(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) +static JSBool odbc_exec(JSContext * cx, JSObject * obj, uintN argc, jsval *argv, jsval *rval) { odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj); char *sql; JSBool tf = JS_FALSE; - int result; if (argc < 1) { goto done; } - if (odbc_obj->state != ODBC_STATE_CONNECTED) { + if (switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n"); goto done; } @@ -306,17 +202,8 @@ static JSBool odbc_exec(JSContext * cx, JSObject * obj, uintN argc, jsval * argv sql = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); - if (SQLAllocHandle(SQL_HANDLE_STMT, odbc_obj->con, &odbc_obj->stmt) != SQL_SUCCESS) { - goto done; - } - if (SQLPrepare(odbc_obj->stmt, (unsigned char *) sql, SQL_NTS) != SQL_SUCCESS) { - goto done; - } - - result = SQLExecute(odbc_obj->stmt); - - if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { + if (switch_odbc_handle_exec(odbc_obj->handle, sql, &odbc_obj->stmt) != SWITCH_ODBC_SUCCESS) { goto done; } @@ -329,13 +216,14 @@ static JSBool odbc_exec(JSContext * cx, JSObject * obj, uintN argc, jsval * argv return JS_TRUE; } -static JSBool odbc_num_rows(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) +static JSBool odbc_num_rows(JSContext * cx, JSObject * obj, uintN argc, jsval *argv, jsval *rval) { odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj); SQLSMALLINT rows = 0; - if (odbc_obj->state != ODBC_STATE_CONNECTED) { + if (switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n"); goto done; } @@ -352,15 +240,17 @@ static JSBool odbc_num_rows(JSContext * cx, JSObject * obj, uintN argc, jsval * } -static JSBool odbc_next_row(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) +static JSBool odbc_next_row(JSContext * cx, JSObject * obj, uintN argc, jsval *argv, jsval *rval) { odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj); int result = 0; JSBool tf = JS_FALSE; - if (odbc_obj->state != ODBC_STATE_CONNECTED) { - goto done; - } + if (switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n"); + goto done; + } + if (odbc_obj->stmt) { if ((result = SQLFetch(odbc_obj->stmt) == SQL_SUCCESS)) { @@ -412,19 +302,20 @@ static char *escape_data(char *in) } -static JSBool odbc_get_data(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) +static JSBool odbc_get_data(JSContext * cx, JSObject * obj, uintN argc, jsval *argv, jsval *rval) { odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj); JSBool tf = JS_FALSE; - if (odbc_obj->state != ODBC_STATE_CONNECTED) { - goto done; - } + if (switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n"); + goto done; + } if (odbc_obj->stmt) { SQLSMALLINT c = 0, x = 0; - int result; + SQLINTEGER m = 0; char code[66560]; snprintf(code, sizeof(code), "~var _oDbC_dB_RoW_DaTa_ = {}"); @@ -433,15 +324,16 @@ static JSBool odbc_get_data(JSContext * cx, JSObject * obj, uintN argc, jsval * return JS_TRUE; } - result = SQLNumResultCols(odbc_obj->stmt, &c); - if (result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO) { + SQLNumResultCols(odbc_obj->stmt, &c); + SQLRowCount(odbc_obj->stmt, &m); + if (m > 0) { for (x = 1; x <= c; x++) { SQLSMALLINT NameLength, DataType, DecimalDigits, Nullable; SQLUINTEGER ColumnSize; SQLCHAR name[1024] = ""; SQLCHAR *data = odbc_obj->colbuf; SQLCHAR *esc = NULL; - + SQLDescribeCol(odbc_obj->stmt, x, name, sizeof(name), &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable); SQLGetData(odbc_obj->stmt, x, SQL_C_CHAR, odbc_obj->colbuf, odbc_obj->cblen, NULL); diff --git a/src/switch_odbc.c b/src/switch_odbc.c new file mode 100644 index 0000000000..ff69f9d001 --- /dev/null +++ b/src/switch_odbc.c @@ -0,0 +1,407 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * switch_odbc.c -- ODBC + * + */ +#include + +struct switch_odbc_handle { + char *dsn; + char *username; + char *password; + SQLHENV env; + SQLHDBC con; + switch_odbc_state_t state; +}; + + +SWITCH_DECLARE(switch_odbc_handle_t *) switch_odbc_handle_new(char *dsn, char *username, char *password) +{ + switch_odbc_handle_t *new_handle; + + if (!(new_handle = malloc(sizeof(*new_handle)))) { + goto err; + } + + memset(new_handle, 0, sizeof(*new_handle)); + + if (!(new_handle->dsn = strdup(dsn))) { + goto err; + } + + if (username) { + if (!(new_handle->username = strdup(username))) { + goto err; + } + } + + if (password) { + if (!(new_handle->password = strdup(password))) { + goto err; + } + } + + new_handle->env = SQL_NULL_HANDLE; + new_handle->state = SWITCH_ODBC_STATE_INIT; + + return new_handle; + + err: + if (new_handle) { + switch_safe_free(new_handle->dsn); + switch_safe_free(new_handle->username); + switch_safe_free(new_handle->password); + switch_safe_free(new_handle); + } + + return NULL; +} + +SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_disconnect(switch_odbc_handle_t *handle) +{ + int result; + + if (handle->state == SWITCH_ODBC_STATE_CONNECTED) { + result = SQLDisconnect(handle->con); + if (result == SWITCH_ODBC_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disconnected %d from [%s]\n", result, handle->dsn); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Disconnectiong [%s]\n", handle->dsn); + } + } + //else { + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "[%s] already disconnected\n", handle->dsn); + //} + + handle->state = SWITCH_ODBC_STATE_DOWN; + + return SWITCH_ODBC_SUCCESS; +} + +SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_connect(switch_odbc_handle_t *handle) +{ + int result; + SQLINTEGER err; + int16_t mlen; + unsigned char msg[200], stat[10]; + + if (handle->env == SQL_NULL_HANDLE) { + result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handle->env); + + if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error AllocHandle\n"); + return SWITCH_ODBC_FAIL; + } + + result = SQLSetEnvAttr(handle->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); + + if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error SetEnv\n"); + SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + return SWITCH_ODBC_FAIL; + } + + result = SQLAllocHandle(SQL_HANDLE_DBC, handle->env, &handle->con); + + if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error AllocHDB %d\n", result); + SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + return SWITCH_ODBC_FAIL; + } + SQLSetConnectAttr(handle->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); + } + if (handle->state == SWITCH_ODBC_STATE_CONNECTED) { + switch_odbc_handle_disconnect(handle); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-connecting %s\n", handle->dsn); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connecting %s\n", handle->dsn); + + result = SQLConnect(handle->con, (SQLCHAR *) handle->dsn, SQL_NTS, (SQLCHAR *) handle->username, SQL_NTS, (SQLCHAR *) handle->password, SQL_NTS); + + if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { + char *err_str; + if ((err_str = switch_odbc_handle_get_error(handle, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n",err_str); + free(err_str); + } else { + SQLGetDiagRec(SQL_HANDLE_DBC, handle->con, 1, stat, &err, msg, 100, &mlen); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error SQLConnect=%d errno=%d %s\n", result, (int) err, msg); + } + SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + return SWITCH_ODBC_FAIL; + } else { + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connected to [%s]\n", handle->dsn); + handle->state = SWITCH_ODBC_STATE_CONNECTED; + return SWITCH_ODBC_SUCCESS; + } + + return SWITCH_ODBC_FAIL; +} + +static int db_is_up(switch_odbc_handle_t *handle) +{ + int ret = 0; + SQLHSTMT stmt; + SQLINTEGER m = 0; + int result; + switch_event_t *event; + switch_odbc_status_t recon; + char *err_str = NULL; + SQLCHAR sql[] = "select 1"; + + if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) { + goto error; + } + + if (SQLPrepare(stmt, sql, SQL_NTS) != SQL_SUCCESS) { + goto error; + } + + result = SQLExecute(stmt); + + SQLRowCount(stmt, &m); + ret = (int) m; + + goto done; + + error: + + recon = switch_odbc_handle_connect(handle); + err_str = switch_odbc_handle_get_error(handle, stmt); + + if (switch_event_create(&event, SWITCH_EVENT_TRAP) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Failure-Message", "The sql server is not responding for DSN %s [%s]", + switch_str_nil(handle->dsn), switch_str_nil(err_str)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The sql server is not responding for DSN %s [%s]\n", + switch_str_nil(handle->dsn), switch_str_nil(err_str)); + + if (recon == SWITCH_ODBC_SUCCESS) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection has been re-established"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "The connection has been re-established\n"); + } else { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection could not be re-established"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The connection could not be re-established\n"); + } + switch_event_fire(&event); + } + + done: + + switch_safe_free(err_str); + + if (stmt) { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + + return ret; + +} + + +SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_exec(switch_odbc_handle_t *handle, char *sql, SQLHSTMT *rstmt) +{ + SQLHSTMT stmt; + int result; + + if (!db_is_up(handle)) { + goto error; + } + + if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) { + goto error; + } + + if (SQLPrepare(stmt, (unsigned char *) sql, SQL_NTS) != SQL_SUCCESS) { + goto error; + } + + result = SQLExecute(stmt); + + if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { + goto error; + } + + if (rstmt) { + *rstmt = stmt; + } else { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + + return SWITCH_ODBC_SUCCESS; + + error: + if (rstmt) { + *rstmt = stmt; + } else if (stmt) { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + return SWITCH_ODBC_FAIL; + +} + + +SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec(switch_odbc_handle_t *handle, + char *sql, switch_core_db_callback_func_t callback, void *pdata) +{ + SQLHSTMT stmt; + SQLSMALLINT c = 0, x = 0; + SQLINTEGER m = 0; + int result; + + assert(callback != NULL); + + if (!db_is_up(handle)) { + goto error; + } + + if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) { + goto error; + } + + if (SQLPrepare(stmt, (unsigned char *) sql, SQL_NTS) != SQL_SUCCESS) { + goto error; + } + + result = SQLExecute(stmt); + + if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { + goto error; + } + + + SQLNumResultCols(stmt, &c); + SQLRowCount(stmt, &m); + + if (m > 0) { + int name_len = 256; + char **names; + char **vals; + int y = 0; + + if (!(result = SQLFetch(stmt)) == SQL_SUCCESS) { + goto error; + } + + names = calloc(c, sizeof(*names)); + vals = calloc(c, sizeof(*names)); + + assert(names && vals); + + for (x = 1; x <= c; x++) { + SQLSMALLINT NameLength, DataType, DecimalDigits, Nullable; + SQLUINTEGER ColumnSize; + names[y] = malloc(name_len); + memset(names[y], 0, name_len); + + SQLDescribeCol(stmt, x, (SQLCHAR *) names[y], name_len, &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable); + ColumnSize++; + + vals[y] = malloc(ColumnSize); + memset(vals[y], 0, ColumnSize); + SQLGetData(stmt, x, SQL_C_CHAR, (SQLCHAR *) vals[y], ColumnSize, NULL); + y++; + } + + callback(pdata, y, vals, names); + + for (x = 0; x < y; x++) { + free(names[x]); + free(vals[x]); + } + free(names); + free(vals); + } + + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + + return SWITCH_ODBC_SUCCESS; + + error: + + if (stmt) { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + + return SWITCH_ODBC_FAIL; + +} + + +SWITCH_DECLARE(void) switch_odbc_handle_destroy(switch_odbc_handle_t **handlep) +{ + switch_odbc_handle_t *handle = NULL; + + if (handlep) { + handle = *handlep; + } + + if (handle) { + switch_odbc_handle_disconnect(handle); + + SQLFreeHandle(SQL_HANDLE_DBC, handle->con); + SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + switch_safe_free(handle->dsn); + switch_safe_free(handle->username); + switch_safe_free(handle->password); + free(handle); + } +} + +SWITCH_DECLARE(switch_odbc_state_t) switch_odbc_handle_get_state(switch_odbc_handle_t *handle) +{ + return handle ? handle->state : SWITCH_ODBC_STATE_INIT; +} + +SWITCH_DECLARE(char *) switch_odbc_handle_get_error(switch_odbc_handle_t *handle, SQLHSTMT stmt) +{ + char buffer[SQL_MAX_MESSAGE_LENGTH + 1]; + char sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER sqlcode; + SQLSMALLINT length; + char *ret = NULL; + + if (SQLError(handle->env, handle->con, stmt, (SQLCHAR *)sqlstate, &sqlcode, (SQLCHAR *)buffer, sizeof(buffer), &length) == SQL_SUCCESS) { + ret = switch_mprintf("STATE: %s CODE %ld ERROR: %s\n", switch_str_nil(sqlstate), sqlcode, switch_str_nil(buffer)); + }; + + return ret; +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */