#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/options.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/res_odbc.h"
#include "asterisk/time.h"
Go to the source code of this file.
Data Structures | |
struct | odbc_class |
struct | odbc_list |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
int | ast_odbc_backslash_is_escape (struct odbc_obj *obj) |
Checks if the database natively supports backslash as an escape character. | |
SQLHSTMT | ast_odbc_prepare_and_execute (struct odbc_obj *obj, SQLHSTMT(*prepare_cb)(struct odbc_obj *obj, void *data), void *data) |
Prepares, executes, and returns the resulting statement handle. | |
void | ast_odbc_release_obj (struct odbc_obj *obj) |
Releases an ODBC object previously allocated by odbc_request_obj(). | |
odbc_obj * | ast_odbc_request_obj (const char *name, int check) |
Retrieves a connected ODBC object. | |
int | ast_odbc_sanity_check (struct odbc_obj *obj) |
Checks an ODBC object to ensure it is still connected. | |
int | ast_odbc_smart_execute (struct odbc_obj *obj, SQLHSTMT stmt) |
Executes a prepared statement handle. | |
static int | load_module (void) |
static int | load_odbc_config (void) |
static odbc_status | odbc_obj_connect (struct odbc_obj *obj) |
static odbc_status | odbc_obj_disconnect (struct odbc_obj *obj) |
static int | odbc_register_class (struct odbc_class *class, int connect) |
static int | odbc_show_command (int fd, int argc, char **argv) |
static int | reload (void) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "ODBC Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_cli_entry | cli_odbc [] |
static char | show_usage [] |
Anthony Minessale II <anthmct@yahoo.com>
Definition in file res_odbc.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 739 of file res_odbc.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 739 of file res_odbc.c.
int ast_odbc_backslash_is_escape | ( | struct odbc_obj * | obj | ) |
Checks if the database natively supports backslash as an escape character.
obj | The ODBC object |
Definition at line 394 of file res_odbc.c.
References odbc_class::backslash_is_escape, and odbc_obj::parent.
Referenced by realtime_multi_odbc(), and realtime_odbc().
00395 { 00396 return obj->parent->backslash_is_escape; 00397 }
SQLHSTMT ast_odbc_prepare_and_execute | ( | struct odbc_obj * | obj, | |
SQLHSTMT(*)(struct odbc_obj *obj, void *data) | prepare_cb, | |||
void * | data | |||
) |
Prepares, executes, and returns the resulting statement handle.
obj | The ODBC object | |
prepare_cb | A function callback, which, when called, should return a statement handle prepared, with any necessary parameters or result columns bound. | |
data | A parameter to be passed to the prepare_cb parameter function, indicating which statement handle is to be prepared. |
Definition at line 82 of file res_odbc.c.
References ast_log(), ast_odbc_sanity_check(), ast_tvnow(), and LOG_WARNING.
Referenced by acf_odbc_read(), acf_odbc_write(), config_odbc(), realtime_multi_odbc(), realtime_odbc(), and update_odbc().
00083 { 00084 int res = 0, i, attempt; 00085 SQLINTEGER nativeerror=0, numfields=0; 00086 SQLSMALLINT diagbytes=0; 00087 unsigned char state[10], diagnostic[256]; 00088 SQLHSTMT stmt; 00089 00090 for (attempt = 0; attempt < 2; attempt++) { 00091 /* This prepare callback may do more than just prepare -- it may also 00092 * bind parameters, bind results, etc. The real key, here, is that 00093 * when we disconnect, all handles become invalid for most databases. 00094 * We must therefore redo everything when we establish a new 00095 * connection. */ 00096 stmt = prepare_cb(obj, data); 00097 00098 if (stmt) { 00099 res = SQLExecute(stmt); 00100 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00101 if (res == SQL_ERROR) { 00102 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00103 for (i = 0; i < numfields; i++) { 00104 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00105 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00106 if (i > 10) { 00107 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00108 break; 00109 } 00110 } 00111 } 00112 00113 ast_log(LOG_WARNING, "SQL Execute error %d! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn); 00114 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00115 stmt = NULL; 00116 00117 if (!ast_odbc_sanity_check(obj)) { 00118 break; 00119 } 00120 continue; 00121 } else 00122 obj->last_used = ast_tvnow(); 00123 break; 00124 } else { 00125 ast_log(LOG_WARNING, "SQL Prepare failed. Verifying connection to %s [%s]\n", obj->parent->name, obj->parent->dsn); 00126 ast_odbc_sanity_check(obj); 00127 } 00128 } 00129 00130 return stmt; 00131 }
void ast_odbc_release_obj | ( | struct odbc_obj * | obj | ) |
Releases an ODBC object previously allocated by odbc_request_obj().
obj | The ODBC object |
Definition at line 387 of file res_odbc.c.
References odbc_obj::used.
Referenced by acf_odbc_read(), acf_odbc_write(), config_odbc(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), and update_odbc().
00388 { 00389 /* For pooled connections, this frees the connection to be 00390 * reused. For non-pooled connections, it does nothing. */ 00391 obj->used = 0; 00392 }
struct odbc_obj* ast_odbc_request_obj | ( | const char * | name, | |
int | check | |||
) |
Retrieves a connected ODBC object.
name | The name of the ODBC class for which a connection is needed. | |
check | Whether to ensure that a connection is valid before returning the handle. Usually unnecessary. |
Definition at line 399 of file res_odbc.c.
References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_odbc_sanity_check(), ast_tvdiff_ms(), ast_tvnow(), free, odbc_class::idlecheck, odbc_obj::last_used, odbc_class::list, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), odbc_obj::parent, and odbc_obj::used.
Referenced by acf_odbc_read(), acf_odbc_write(), config_odbc(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), and update_odbc().
00400 { 00401 struct odbc_obj *obj = NULL; 00402 struct odbc_class *class; 00403 00404 AST_LIST_LOCK(&odbc_list); 00405 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00406 if (!strcmp(class->name, name)) 00407 break; 00408 } 00409 AST_LIST_UNLOCK(&odbc_list); 00410 00411 if (!class) 00412 return NULL; 00413 00414 AST_LIST_LOCK(&class->odbc_obj); 00415 if (class->haspool) { 00416 /* Recycle connections before building another */ 00417 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00418 if (! obj->used) { 00419 obj->used = 1; 00420 break; 00421 } 00422 } 00423 00424 if (!obj && (class->count < class->limit)) { 00425 class->count++; 00426 obj = ast_calloc(1, sizeof(*obj)); 00427 if (!obj) { 00428 AST_LIST_UNLOCK(&class->odbc_obj); 00429 return NULL; 00430 } 00431 ast_mutex_init(&obj->lock); 00432 obj->parent = class; 00433 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00434 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00435 ast_mutex_destroy(&obj->lock); 00436 free(obj); 00437 obj = NULL; 00438 class->count--; 00439 } else { 00440 obj->used = 1; 00441 AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list); 00442 } 00443 } 00444 } else { 00445 /* Non-pooled connection: multiple modules can use the same connection. */ 00446 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00447 /* Non-pooled connection: if there is an entry, return it */ 00448 break; 00449 } 00450 00451 if (!obj) { 00452 /* No entry: build one */ 00453 obj = ast_calloc(1, sizeof(*obj)); 00454 if (!obj) { 00455 AST_LIST_UNLOCK(&class->odbc_obj); 00456 return NULL; 00457 } 00458 ast_mutex_init(&obj->lock); 00459 obj->parent = class; 00460 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00461 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00462 ast_mutex_destroy(&obj->lock); 00463 free(obj); 00464 obj = NULL; 00465 } else { 00466 AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list); 00467 } 00468 } 00469 } 00470 AST_LIST_UNLOCK(&class->odbc_obj); 00471 00472 if (obj && check) { 00473 ast_odbc_sanity_check(obj); 00474 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_ms(ast_tvnow(), obj->last_used) / 1000 > obj->parent->idlecheck) 00475 odbc_obj_connect(obj); 00476 00477 return obj; 00478 }
int ast_odbc_sanity_check | ( | struct odbc_obj * | obj | ) |
Checks an ODBC object to ensure it is still connected.
obj | The ODBC object |
Definition at line 176 of file res_odbc.c.
References ast_log(), odbc_obj::con, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), and odbc_obj::up.
Referenced by ast_odbc_prepare_and_execute(), ast_odbc_request_obj(), and odbc_show_command().
00177 { 00178 char *test_sql = "select 1"; 00179 SQLHSTMT stmt; 00180 int res = 0; 00181 00182 if (obj->up) { 00183 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00184 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00185 obj->up = 0; 00186 } else { 00187 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00188 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00189 obj->up = 0; 00190 } else { 00191 res = SQLExecute(stmt); 00192 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00193 obj->up = 0; 00194 } 00195 } 00196 } 00197 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00198 } 00199 00200 if (!obj->up) { /* Try to reconnect! */ 00201 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00202 odbc_obj_disconnect(obj); 00203 odbc_obj_connect(obj); 00204 } 00205 return obj->up; 00206 }
int ast_odbc_smart_execute | ( | struct odbc_obj * | obj, | |
SQLHSTMT | stmt | |||
) |
Executes a prepared statement handle.
obj | The non-NULL result of odbc_request_obj() | |
stmt | The prepared statement handle |
This function really only ever worked with MySQL, where the statement handle is not prepared on the server. If you are not using MySQL, you should avoid it.
Definition at line 133 of file res_odbc.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_tvnow(), odbc_obj::last_used, odbc_obj::lock, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), and odbc_obj::up.
00134 { 00135 int res = 0, i; 00136 SQLINTEGER nativeerror=0, numfields=0; 00137 SQLSMALLINT diagbytes=0; 00138 unsigned char state[10], diagnostic[256]; 00139 00140 res = SQLExecute(stmt); 00141 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00142 if (res == SQL_ERROR) { 00143 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00144 for (i = 0; i < numfields; i++) { 00145 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00146 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00147 if (i > 10) { 00148 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00149 break; 00150 } 00151 } 00152 } 00153 #if 0 00154 /* This is a really bad method of trying to correct a dead connection. It 00155 * only ever really worked with MySQL. It will not work with any other 00156 * database, since most databases prepare their statements on the server, 00157 * and if you disconnect, you invalidate the statement handle. Hence, if 00158 * you disconnect, you're going to fail anyway, whether you try to execute 00159 * a second time or not. 00160 */ 00161 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); 00162 ast_mutex_lock(&obj->lock); 00163 obj->up = 0; 00164 ast_mutex_unlock(&obj->lock); 00165 odbc_obj_disconnect(obj); 00166 odbc_obj_connect(obj); 00167 res = SQLExecute(stmt); 00168 #endif 00169 } else 00170 obj->last_used = ast_tvnow(); 00171 00172 return res; 00173 }
static int load_module | ( | void | ) | [static] |
Definition at line 726 of file res_odbc.c.
References ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_DECLINE, cli_odbc, load_odbc_config(), and LOG_NOTICE.
00727 { 00728 if(load_odbc_config() == -1) 00729 return AST_MODULE_LOAD_DECLINE; 00730 ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry)); 00731 ast_log(LOG_NOTICE, "res_odbc loaded.\n"); 00732 return 0; 00733 }
static int load_odbc_config | ( | void | ) | [static] |
Definition at line 208 of file res_odbc.c.
References ast_category_browse(), ast_config_load(), ast_false(), ast_log(), ast_true(), ast_variable_browse(), config, odbc_class::dsn, enabled, odbc_class::idlecheck, odbc_class::limit, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, odbc_class::password, odbc_class::username, and ast_variable::value.
Referenced by load_module().
00209 { 00210 static char *cfg = "res_odbc.conf"; 00211 struct ast_config *config; 00212 struct ast_variable *v; 00213 char *cat, *dsn, *username, *password; 00214 int enabled, pooling, limit, bse; 00215 unsigned int idlecheck; 00216 int connect = 0, res = 0; 00217 00218 struct odbc_class *new; 00219 00220 config = ast_config_load(cfg); 00221 if (!config) { 00222 ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n"); 00223 return -1; 00224 } 00225 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00226 if (!strcasecmp(cat, "ENV")) { 00227 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00228 setenv(v->name, v->value, 1); 00229 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00230 } 00231 } else { 00232 /* Reset all to defaults for each class of odbc connections */ 00233 dsn = username = password = NULL; 00234 enabled = 1; 00235 connect = idlecheck = 0; 00236 pooling = 0; 00237 limit = 0; 00238 bse = 1; 00239 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00240 if (!strcasecmp(v->name, "pooling")) { 00241 if (ast_true(v->value)) 00242 pooling = 1; 00243 } else if (!strcasecmp(v->name, "limit")) { 00244 sscanf(v->value, "%4d", &limit); 00245 if (ast_true(v->value) && !limit) { 00246 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Setting limit to 1023 for ODBC class '%s'.\n", v->value, cat); 00247 limit = 1023; 00248 } else if (ast_false(v->value)) { 00249 /* Limit=no probably means "no limit", which is the maximum */ 00250 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Setting limit to 1023 for ODBC class '%s'.\n", v->value, cat); 00251 limit = 1023; 00252 break; 00253 } else if (limit > 1023) { 00254 ast_log(LOG_WARNING, "Maximum limit in 1.4 is 1023. Setting limit to 1023 for ODBC class '%s'.\n", cat); 00255 limit = 1023; 00256 } 00257 } else if (!strcasecmp(v->name, "idlecheck")) { 00258 sscanf(v->value, "%30u", &idlecheck); 00259 } else if (!strcasecmp(v->name, "enabled")) { 00260 enabled = ast_true(v->value); 00261 } else if (!strcasecmp(v->name, "pre-connect")) { 00262 connect = ast_true(v->value); 00263 } else if (!strcasecmp(v->name, "dsn")) { 00264 dsn = v->value; 00265 } else if (!strcasecmp(v->name, "username")) { 00266 username = v->value; 00267 } else if (!strcasecmp(v->name, "password")) { 00268 password = v->value; 00269 } else if (!strcasecmp(v->name, "backslash_is_escape")) { 00270 bse = ast_true(v->value); 00271 } 00272 } 00273 00274 if (enabled && !ast_strlen_zero(dsn)) { 00275 new = ast_calloc(1, sizeof(*new)); 00276 00277 if (!new) { 00278 res = -1; 00279 break; 00280 } 00281 00282 if (cat) 00283 ast_copy_string(new->name, cat, sizeof(new->name)); 00284 if (dsn) 00285 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00286 if (username) 00287 ast_copy_string(new->username, username, sizeof(new->username)); 00288 if (password) 00289 ast_copy_string(new->password, password, sizeof(new->password)); 00290 00291 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00292 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00293 00294 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00295 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00296 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00297 return res; 00298 } 00299 00300 if (pooling) { 00301 new->haspool = pooling; 00302 if (limit) { 00303 new->limit = limit; 00304 } else { 00305 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00306 new->limit = 5; 00307 } 00308 } 00309 00310 new->backslash_is_escape = bse ? 1 : 0; 00311 new->idlecheck = idlecheck; 00312 00313 odbc_register_class(new, connect); 00314 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00315 } 00316 } 00317 } 00318 ast_config_destroy(config); 00319 return res; 00320 }
static odbc_status odbc_obj_connect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 515 of file res_odbc.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_tvnow(), odbc_obj::con, odbc_class::dsn, odbc_class::env, odbc_obj::last_used, odbc_obj::lock, LOG_NOTICE, LOG_WARNING, odbc_class::name, ODBC_FAIL, odbc_obj_disconnect(), ODBC_SUCCESS, odbc_obj::parent, odbc_class::password, odbc_obj::up, and odbc_class::username.
Referenced by ast_odbc_request_obj(), ast_odbc_sanity_check(), and ast_odbc_smart_execute().
00516 { 00517 int res; 00518 SQLINTEGER err; 00519 short int mlen; 00520 unsigned char msg[200], stat[10]; 00521 #ifdef NEEDTRACE 00522 SQLINTEGER enable = 1; 00523 char *tracefile = "/tmp/odbc.trace"; 00524 #endif 00525 ast_mutex_lock(&obj->lock); 00526 00527 if (obj->up) { 00528 odbc_obj_disconnect(obj); 00529 ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name); 00530 } else { 00531 ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name); 00532 } 00533 00534 res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con); 00535 00536 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00537 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res); 00538 ast_mutex_unlock(&obj->lock); 00539 return ODBC_FAIL; 00540 } 00541 SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); 00542 SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) 10, 0); 00543 #ifdef NEEDTRACE 00544 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); 00545 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); 00546 #endif 00547 00548 res = SQLConnect(obj->con, 00549 (SQLCHAR *) obj->parent->dsn, SQL_NTS, 00550 (SQLCHAR *) obj->parent->username, SQL_NTS, 00551 (SQLCHAR *) obj->parent->password, SQL_NTS); 00552 00553 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00554 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); 00555 ast_mutex_unlock(&obj->lock); 00556 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg); 00557 return ODBC_FAIL; 00558 } else { 00559 ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn); 00560 obj->up = 1; 00561 obj->last_used = ast_tvnow(); 00562 } 00563 00564 ast_mutex_unlock(&obj->lock); 00565 return ODBC_SUCCESS; 00566 }
static odbc_status odbc_obj_disconnect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 480 of file res_odbc.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::con, odbc_class::dsn, odbc_obj::lock, LOG_DEBUG, LOG_WARNING, odbc_class::name, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.
Referenced by ast_odbc_sanity_check(), ast_odbc_smart_execute(), and odbc_obj_connect().
00481 { 00482 int res; 00483 SQLINTEGER err; 00484 short int mlen; 00485 unsigned char msg[200], stat[10]; 00486 00487 /* Nothing to disconnect */ 00488 if (!obj->con) { 00489 return ODBC_SUCCESS; 00490 } 00491 00492 ast_mutex_lock(&obj->lock); 00493 00494 res = SQLDisconnect(obj->con); 00495 00496 if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) { 00497 ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn); 00498 } else { 00499 ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn); 00500 } 00501 00502 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == SQL_SUCCESS)) { 00503 obj->con = NULL; 00504 ast_log(LOG_DEBUG, "Database handle deallocated\n"); 00505 } else { 00506 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); 00507 ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg); 00508 } 00509 00510 obj->up = 0; 00511 ast_mutex_unlock(&obj->lock); 00512 return ODBC_SUCCESS; 00513 }
static int odbc_register_class | ( | struct odbc_class * | class, | |
int | connect | |||
) | [static] |
Definition at line 365 of file res_odbc.c.
References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_odbc_release_obj(), ast_odbc_request_obj(), LOG_WARNING, and odbc_class::name.
00366 { 00367 struct odbc_obj *obj; 00368 if (class) { 00369 AST_LIST_LOCK(&odbc_list); 00370 AST_LIST_INSERT_HEAD(&odbc_list, class, list); 00371 AST_LIST_UNLOCK(&odbc_list); 00372 00373 if (connect) { 00374 /* Request and release builds a connection */ 00375 obj = ast_odbc_request_obj(class->name, 0); 00376 if (obj) 00377 ast_odbc_release_obj(obj); 00378 } 00379 00380 return 0; 00381 } else { 00382 ast_log(LOG_WARNING, "Attempted to register a NULL class?\n"); 00383 return -1; 00384 } 00385 }
static int odbc_show_command | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 322 of file res_odbc.c.
References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_odbc_sanity_check(), odbc_obj::up, and odbc_obj::used.
00323 { 00324 struct odbc_class *class; 00325 struct odbc_obj *current; 00326 00327 AST_LIST_LOCK(&odbc_list); 00328 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00329 if ((argc == 2) || (argc == 3 && !strcmp(argv[2], "all")) || (!strcmp(argv[2], class->name))) { 00330 int count = 0; 00331 ast_cli(fd, "Name: %s\nDSN: %s\n", class->name, class->dsn); 00332 00333 if (class->haspool) { 00334 ast_cli(fd, "Pooled: yes\nLimit: %d\nConnections in use: %d\n", class->limit, class->count); 00335 00336 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00337 ast_cli(fd, " Connection %d: %s\n", ++count, current->used ? "in use" : current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected"); 00338 } 00339 } else { 00340 /* Should only ever be one of these */ 00341 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00342 ast_cli(fd, "Pooled: no\nConnected: %s\n", current->up && ast_odbc_sanity_check(current) ? "yes" : "no"); 00343 } 00344 } 00345 00346 ast_cli(fd, "\n"); 00347 } 00348 } 00349 AST_LIST_UNLOCK(&odbc_list); 00350 00351 return 0; 00352 }
static int reload | ( | void | ) | [static] |
Definition at line 568 of file res_odbc.c.
References ast_category_browse(), ast_config_load(), ast_false(), AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_log(), ast_true(), ast_variable_browse(), config, enabled, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, and ast_variable::value.
00569 { 00570 static char *cfg = "res_odbc.conf"; 00571 struct ast_config *config; 00572 struct ast_variable *v; 00573 char *cat, *dsn, *username, *password; 00574 int enabled, pooling, limit, bse; 00575 unsigned int idlecheck; 00576 int connect = 0, res = 0; 00577 00578 struct odbc_class *new, *class; 00579 struct odbc_obj *current; 00580 00581 /* First, mark all to be purged */ 00582 AST_LIST_LOCK(&odbc_list); 00583 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00584 class->delme = 1; 00585 } 00586 00587 config = ast_config_load(cfg); 00588 if (config) { 00589 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00590 if (!strcasecmp(cat, "ENV")) { 00591 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00592 setenv(v->name, v->value, 1); 00593 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00594 } 00595 } else { 00596 /* Reset all to defaults for each class of odbc connections */ 00597 dsn = username = password = NULL; 00598 enabled = 1; 00599 connect = idlecheck = 0; 00600 pooling = 0; 00601 limit = 0; 00602 bse = 1; 00603 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00604 if (!strcasecmp(v->name, "pooling")) { 00605 pooling = 1; 00606 } else if (!strcasecmp(v->name, "limit")) { 00607 sscanf(v->value, "%4d", &limit); 00608 if (ast_true(v->value) && !limit) { 00609 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Setting limit to 1023 for ODBC class '%s'.\n", v->value, cat); 00610 limit = 1023; 00611 } else if (ast_false(v->value)) { 00612 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); 00613 enabled = 0; 00614 break; 00615 } 00616 } else if (!strcasecmp(v->name, "idlecheck")) { 00617 sscanf(v->value, "%30u", &idlecheck); 00618 } else if (!strcasecmp(v->name, "enabled")) { 00619 enabled = ast_true(v->value); 00620 } else if (!strcasecmp(v->name, "pre-connect")) { 00621 connect = ast_true(v->value); 00622 } else if (!strcasecmp(v->name, "dsn")) { 00623 dsn = v->value; 00624 } else if (!strcasecmp(v->name, "username")) { 00625 username = v->value; 00626 } else if (!strcasecmp(v->name, "password")) { 00627 password = v->value; 00628 } else if (!strcasecmp(v->name, "backslash_is_escape")) { 00629 bse = ast_true(v->value); 00630 } 00631 } 00632 00633 if (enabled && !ast_strlen_zero(dsn)) { 00634 /* First, check the list to see if it already exists */ 00635 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00636 if (!strcmp(class->name, cat)) { 00637 class->delme = 0; 00638 break; 00639 } 00640 } 00641 00642 if (class) { 00643 new = class; 00644 } else { 00645 new = ast_calloc(1, sizeof(*new)); 00646 } 00647 00648 if (!new) { 00649 res = -1; 00650 break; 00651 } 00652 00653 if (cat) 00654 ast_copy_string(new->name, cat, sizeof(new->name)); 00655 if (dsn) 00656 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00657 if (username) 00658 ast_copy_string(new->username, username, sizeof(new->username)); 00659 if (password) 00660 ast_copy_string(new->password, password, sizeof(new->password)); 00661 00662 if (!class) { 00663 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00664 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00665 00666 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00667 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00668 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00669 AST_LIST_UNLOCK(&odbc_list); 00670 return res; 00671 } 00672 } 00673 00674 if (pooling) { 00675 new->haspool = pooling; 00676 if (limit) { 00677 new->limit = limit; 00678 } else { 00679 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00680 new->limit = 5; 00681 } 00682 } 00683 00684 new->backslash_is_escape = bse; 00685 new->idlecheck = idlecheck; 00686 00687 if (class) { 00688 ast_log(LOG_NOTICE, "Refreshing ODBC class '%s' dsn->[%s]\n", cat, dsn); 00689 } else { 00690 odbc_register_class(new, connect); 00691 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00692 } 00693 } 00694 } 00695 } 00696 ast_config_destroy(config); 00697 } 00698 00699 /* Purge classes that we know can go away (pooled with 0, only) */ 00700 AST_LIST_TRAVERSE_SAFE_BEGIN(&odbc_list, class, list) { 00701 if (class->delme && class->haspool && class->count == 0) { 00702 AST_LIST_TRAVERSE_SAFE_BEGIN(&(class->odbc_obj), current, list) { 00703 AST_LIST_REMOVE_CURRENT(&(class->odbc_obj), list); 00704 odbc_obj_disconnect(current); 00705 ast_mutex_destroy(¤t->lock); 00706 free(current); 00707 } 00708 AST_LIST_TRAVERSE_SAFE_END; 00709 00710 AST_LIST_REMOVE_CURRENT(&odbc_list, list); 00711 free(class); 00712 } 00713 } 00714 AST_LIST_TRAVERSE_SAFE_END; 00715 AST_LIST_UNLOCK(&odbc_list); 00716 00717 return 0; 00718 }
static int unload_module | ( | void | ) | [static] |
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "ODBC Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 739 of file res_odbc.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 739 of file res_odbc.c.
struct ast_cli_entry cli_odbc[] [static] |
Initial value:
{ { { "odbc", "show", NULL }, odbc_show_command, "List ODBC DSN(s)", show_usage }, }
Definition at line 359 of file res_odbc.c.
Referenced by load_module().
char show_usage[] [static] |
Initial value:
"Usage: odbc show [<class>]\n" " List settings of a particular ODBC class.\n" " or, if not specified, all classes.\n"
Definition at line 354 of file res_odbc.c.