#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 |
Functions | |
AST_LIST_HEAD_STATIC (odbc_list, odbc_class) | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"ODBC Resource",.load=load_module,.unload=unload_module,.reload=reload,) | |
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_cli_entry | cli_odbc [] |
static char | show_usage [] |
Anthony Minessale II <anthmct@yahoo.com>
Definition in file res_odbc.c.
AST_LIST_HEAD_STATIC | ( | odbc_list | , | |
odbc_class | ||||
) |
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_GLOBAL_SYMBOLS | , | |||
"ODBC Resource" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
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 396 of file res_odbc.c.
References odbc_obj::parent.
Referenced by realtime_multi_odbc(), and realtime_odbc().
00397 { 00398 return obj->parent->backslash_is_escape; 00399 }
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(), LOG_WARNING, odbc_obj_connect(), and odbc_obj_disconnect().
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! Attempting a reconnect...\n", res); 00114 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00115 stmt = NULL; 00116 00117 obj->up = 0; 00118 /* 00119 * While this isn't the best way to try to correct an error, this won't automatically 00120 * fail when the statement handle invalidates. 00121 */ 00122 /* XXX Actually, it might, if we're using a non-pooled connection. Possible race here. XXX */ 00123 odbc_obj_disconnect(obj); 00124 odbc_obj_connect(obj); 00125 continue; 00126 } else 00127 obj->last_used = ast_tvnow(); 00128 break; 00129 } else { 00130 ast_log(LOG_WARNING, "SQL Prepare failed. Attempting a reconnect...\n"); 00131 odbc_obj_disconnect(obj); 00132 odbc_obj_connect(obj); 00133 } 00134 } 00135 00136 return stmt; 00137 }
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 389 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().
00390 { 00391 /* For pooled connections, this frees the connection to be 00392 * reused. For non-pooled connections, it does nothing. */ 00393 obj->used = 0; 00394 }
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 401 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(), free, odbc_obj::last_used, 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().
00402 { 00403 struct odbc_obj *obj = NULL; 00404 struct odbc_class *class; 00405 00406 AST_LIST_LOCK(&odbc_list); 00407 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00408 if (!strcmp(class->name, name)) 00409 break; 00410 } 00411 AST_LIST_UNLOCK(&odbc_list); 00412 00413 if (!class) 00414 return NULL; 00415 00416 AST_LIST_LOCK(&class->odbc_obj); 00417 if (class->haspool) { 00418 /* Recycle connections before building another */ 00419 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00420 if (! obj->used) { 00421 obj->used = 1; 00422 break; 00423 } 00424 } 00425 00426 if (!obj && (class->count < class->limit)) { 00427 class->count++; 00428 obj = ast_calloc(1, sizeof(*obj)); 00429 if (!obj) { 00430 AST_LIST_UNLOCK(&class->odbc_obj); 00431 return NULL; 00432 } 00433 ast_mutex_init(&obj->lock); 00434 obj->parent = class; 00435 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00436 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00437 ast_mutex_destroy(&obj->lock); 00438 free(obj); 00439 obj = NULL; 00440 class->count--; 00441 } else { 00442 obj->used = 1; 00443 AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list); 00444 } 00445 } 00446 } else { 00447 /* Non-pooled connection: multiple modules can use the same connection. */ 00448 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00449 /* Non-pooled connection: if there is an entry, return it */ 00450 break; 00451 } 00452 00453 if (!obj) { 00454 /* No entry: build one */ 00455 obj = ast_calloc(1, sizeof(*obj)); 00456 if (!obj) { 00457 AST_LIST_UNLOCK(&class->odbc_obj); 00458 return NULL; 00459 } 00460 ast_mutex_init(&obj->lock); 00461 obj->parent = class; 00462 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00463 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00464 ast_mutex_destroy(&obj->lock); 00465 free(obj); 00466 obj = NULL; 00467 } else { 00468 AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list); 00469 } 00470 } 00471 } 00472 AST_LIST_UNLOCK(&class->odbc_obj); 00473 00474 if (obj && check) { 00475 ast_odbc_sanity_check(obj); 00476 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_ms(ast_tvnow(), obj->last_used) / 1000 > obj->parent->idlecheck) 00477 odbc_obj_connect(obj); 00478 00479 return obj; 00480 }
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 182 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_request_obj(), and odbc_show_command().
00183 { 00184 char *test_sql = "select 1"; 00185 SQLHSTMT stmt; 00186 int res = 0; 00187 00188 if (obj->up) { 00189 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00190 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00191 obj->up = 0; 00192 } else { 00193 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00194 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00195 obj->up = 0; 00196 } else { 00197 res = SQLExecute(stmt); 00198 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00199 obj->up = 0; 00200 } 00201 } 00202 } 00203 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00204 } 00205 00206 if (!obj->up) { /* Try to reconnect! */ 00207 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00208 odbc_obj_disconnect(obj); 00209 odbc_obj_connect(obj); 00210 } 00211 return obj->up; 00212 }
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 139 of file res_odbc.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::last_used, odbc_obj::lock, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), and odbc_obj::up.
00140 { 00141 int res = 0, i; 00142 SQLINTEGER nativeerror=0, numfields=0; 00143 SQLSMALLINT diagbytes=0; 00144 unsigned char state[10], diagnostic[256]; 00145 00146 res = SQLExecute(stmt); 00147 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00148 if (res == SQL_ERROR) { 00149 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00150 for (i = 0; i < numfields; i++) { 00151 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00152 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00153 if (i > 10) { 00154 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00155 break; 00156 } 00157 } 00158 } 00159 #if 0 00160 /* This is a really bad method of trying to correct a dead connection. It 00161 * only ever really worked with MySQL. It will not work with any other 00162 * database, since most databases prepare their statements on the server, 00163 * and if you disconnect, you invalidate the statement handle. Hence, if 00164 * you disconnect, you're going to fail anyway, whether you try to execute 00165 * a second time or not. 00166 */ 00167 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); 00168 ast_mutex_lock(&obj->lock); 00169 obj->up = 0; 00170 ast_mutex_unlock(&obj->lock); 00171 odbc_obj_disconnect(obj); 00172 odbc_obj_connect(obj); 00173 res = SQLExecute(stmt); 00174 #endif 00175 } else 00176 obj->last_used = ast_tvnow(); 00177 00178 return res; 00179 }
static int load_module | ( | void | ) | [static] |
Definition at line 722 of file res_odbc.c.
References ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_DECLINE, cli_odbc, load_odbc_config(), and LOG_NOTICE.
00723 { 00724 if(load_odbc_config() == -1) 00725 return AST_MODULE_LOAD_DECLINE; 00726 ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry)); 00727 ast_log(LOG_NOTICE, "res_odbc loaded.\n"); 00728 return 0; 00729 }
static int load_odbc_config | ( | void | ) | [static] |
Definition at line 214 of file res_odbc.c.
References ast_category_browse(), ast_config_load(), ast_false(), ast_log(), ast_true(), ast_variable_browse(), config, dsn, enabled, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, password, setenv(), username, and ast_variable::value.
Referenced by load_module().
00215 { 00216 static char *cfg = "res_odbc.conf"; 00217 struct ast_config *config; 00218 struct ast_variable *v; 00219 char *cat, *dsn, *username, *password; 00220 int enabled, pooling, limit, bse; 00221 unsigned int idlecheck; 00222 int connect = 0, res = 0; 00223 00224 struct odbc_class *new; 00225 00226 config = ast_config_load(cfg); 00227 if (!config) { 00228 ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n"); 00229 return -1; 00230 } 00231 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00232 if (!strcasecmp(cat, "ENV")) { 00233 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00234 setenv(v->name, v->value, 1); 00235 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00236 } 00237 } else { 00238 /* Reset all to defaults for each class of odbc connections */ 00239 dsn = username = password = NULL; 00240 enabled = 1; 00241 connect = idlecheck = 0; 00242 pooling = 0; 00243 limit = 0; 00244 bse = 1; 00245 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00246 if (!strcasecmp(v->name, "pooling")) { 00247 if (ast_true(v->value)) 00248 pooling = 1; 00249 } else if (!strcasecmp(v->name, "limit")) { 00250 sscanf(v->value, "%d", &limit); 00251 if (ast_true(v->value) && !limit) { 00252 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); 00253 limit = 1023; 00254 } else if (ast_false(v->value)) { 00255 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); 00256 enabled = 0; 00257 break; 00258 } 00259 } else if (!strcasecmp(v->name, "idlecheck")) { 00260 sscanf(v->value, "%d", &idlecheck); 00261 } else if (!strcasecmp(v->name, "enabled")) { 00262 enabled = ast_true(v->value); 00263 } else if (!strcasecmp(v->name, "pre-connect")) { 00264 connect = ast_true(v->value); 00265 } else if (!strcasecmp(v->name, "dsn")) { 00266 dsn = v->value; 00267 } else if (!strcasecmp(v->name, "username")) { 00268 username = v->value; 00269 } else if (!strcasecmp(v->name, "password")) { 00270 password = v->value; 00271 } else if (!strcasecmp(v->name, "backslash_is_escape")) { 00272 bse = ast_true(v->value); 00273 } 00274 } 00275 00276 if (enabled && !ast_strlen_zero(dsn)) { 00277 new = ast_calloc(1, sizeof(*new)); 00278 00279 if (!new) { 00280 res = -1; 00281 break; 00282 } 00283 00284 if (cat) 00285 ast_copy_string(new->name, cat, sizeof(new->name)); 00286 if (dsn) 00287 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00288 if (username) 00289 ast_copy_string(new->username, username, sizeof(new->username)); 00290 if (password) 00291 ast_copy_string(new->password, password, sizeof(new->password)); 00292 00293 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00294 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00295 00296 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00297 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00298 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00299 return res; 00300 } 00301 00302 if (pooling) { 00303 new->haspool = pooling; 00304 if (limit) { 00305 new->limit = limit; 00306 } else { 00307 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00308 new->limit = 5; 00309 } 00310 } 00311 00312 new->backslash_is_escape = bse ? 1 : 0; 00313 new->idlecheck = idlecheck; 00314 00315 odbc_register_class(new, connect); 00316 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00317 } 00318 } 00319 } 00320 ast_config_destroy(config); 00321 return res; 00322 }
static odbc_status odbc_obj_connect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 511 of file res_odbc.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::con, odbc_obj::last_used, odbc_obj::lock, LOG_NOTICE, LOG_WARNING, ODBC_FAIL, odbc_obj_disconnect(), ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.
Referenced by ast_odbc_prepare_and_execute(), ast_odbc_request_obj(), ast_odbc_sanity_check(), and ast_odbc_smart_execute().
00512 { 00513 int res; 00514 SQLINTEGER err; 00515 short int mlen; 00516 unsigned char msg[200], stat[10]; 00517 #ifdef NEEDTRACE 00518 SQLINTEGER enable = 1; 00519 char *tracefile = "/tmp/odbc.trace"; 00520 #endif 00521 ast_mutex_lock(&obj->lock); 00522 00523 res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con); 00524 00525 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00526 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res); 00527 ast_mutex_unlock(&obj->lock); 00528 return ODBC_FAIL; 00529 } 00530 SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); 00531 SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) 10, 0); 00532 #ifdef NEEDTRACE 00533 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); 00534 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); 00535 #endif 00536 00537 if (obj->up) { 00538 odbc_obj_disconnect(obj); 00539 ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name); 00540 } else { 00541 ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name); 00542 } 00543 00544 res = SQLConnect(obj->con, 00545 (SQLCHAR *) obj->parent->dsn, SQL_NTS, 00546 (SQLCHAR *) obj->parent->username, SQL_NTS, 00547 (SQLCHAR *) obj->parent->password, SQL_NTS); 00548 00549 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00550 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); 00551 ast_mutex_unlock(&obj->lock); 00552 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg); 00553 return ODBC_FAIL; 00554 } else { 00555 ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn); 00556 obj->up = 1; 00557 obj->last_used = ast_tvnow(); 00558 } 00559 00560 ast_mutex_unlock(&obj->lock); 00561 return ODBC_SUCCESS; 00562 }
static odbc_status odbc_obj_disconnect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 482 of file res_odbc.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::con, odbc_obj::lock, LOG_DEBUG, LOG_WARNING, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.
Referenced by ast_odbc_prepare_and_execute(), ast_odbc_sanity_check(), ast_odbc_smart_execute(), and odbc_obj_connect().
00483 { 00484 int res; 00485 SQLINTEGER err; 00486 short int mlen; 00487 unsigned char msg[200], stat[10]; 00488 00489 ast_mutex_lock(&obj->lock); 00490 00491 res = SQLDisconnect(obj->con); 00492 00493 if (res == ODBC_SUCCESS) { 00494 ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn); 00495 } else { 00496 ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn); 00497 } 00498 00499 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == ODBC_SUCCESS)) { 00500 ast_log(LOG_DEBUG, "Database handle deallocated\n"); 00501 } else { 00502 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); 00503 ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg); 00504 } 00505 00506 obj->up = 0; 00507 ast_mutex_unlock(&obj->lock); 00508 return ODBC_SUCCESS; 00509 }
static int odbc_register_class | ( | struct odbc_class * | class, | |
int | connect | |||
) | [static] |
Definition at line 367 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(), and LOG_WARNING.
00368 { 00369 struct odbc_obj *obj; 00370 if (class) { 00371 AST_LIST_LOCK(&odbc_list); 00372 AST_LIST_INSERT_HEAD(&odbc_list, class, list); 00373 AST_LIST_UNLOCK(&odbc_list); 00374 00375 if (connect) { 00376 /* Request and release builds a connection */ 00377 obj = ast_odbc_request_obj(class->name, 0); 00378 if (obj) 00379 ast_odbc_release_obj(obj); 00380 } 00381 00382 return 0; 00383 } else { 00384 ast_log(LOG_WARNING, "Attempted to register a NULL class?\n"); 00385 return -1; 00386 } 00387 }
static int odbc_show_command | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 324 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.
00325 { 00326 struct odbc_class *class; 00327 struct odbc_obj *current; 00328 00329 AST_LIST_LOCK(&odbc_list); 00330 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00331 if ((argc == 2) || (argc == 3 && !strcmp(argv[2], "all")) || (!strcmp(argv[2], class->name))) { 00332 int count = 0; 00333 ast_cli(fd, "Name: %s\nDSN: %s\n", class->name, class->dsn); 00334 00335 if (class->haspool) { 00336 ast_cli(fd, "Pooled: yes\nLimit: %d\nConnections in use: %d\n", class->limit, class->count); 00337 00338 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00339 ast_cli(fd, " Connection %d: %s\n", ++count, current->used ? "in use" : current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected"); 00340 } 00341 } else { 00342 /* Should only ever be one of these */ 00343 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00344 ast_cli(fd, "Pooled: no\nConnected: %s\n", current->up && ast_odbc_sanity_check(current) ? "yes" : "no"); 00345 } 00346 } 00347 00348 ast_cli(fd, "\n"); 00349 } 00350 } 00351 AST_LIST_UNLOCK(&odbc_list); 00352 00353 return 0; 00354 }
static int reload | ( | void | ) | [static] |
Definition at line 564 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, setenv(), and ast_variable::value.
00565 { 00566 static char *cfg = "res_odbc.conf"; 00567 struct ast_config *config; 00568 struct ast_variable *v; 00569 char *cat, *dsn, *username, *password; 00570 int enabled, pooling, limit, bse; 00571 unsigned int idlecheck; 00572 int connect = 0, res = 0; 00573 00574 struct odbc_class *new, *class; 00575 struct odbc_obj *current; 00576 00577 /* First, mark all to be purged */ 00578 AST_LIST_LOCK(&odbc_list); 00579 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00580 class->delme = 1; 00581 } 00582 00583 config = ast_config_load(cfg); 00584 if (config) { 00585 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00586 if (!strcasecmp(cat, "ENV")) { 00587 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00588 setenv(v->name, v->value, 1); 00589 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00590 } 00591 } else { 00592 /* Reset all to defaults for each class of odbc connections */ 00593 dsn = username = password = NULL; 00594 enabled = 1; 00595 connect = idlecheck = 0; 00596 pooling = 0; 00597 limit = 0; 00598 bse = 1; 00599 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00600 if (!strcasecmp(v->name, "pooling")) { 00601 pooling = 1; 00602 } else if (!strcasecmp(v->name, "limit")) { 00603 sscanf(v->value, "%d", &limit); 00604 if (ast_true(v->value) && !limit) { 00605 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); 00606 limit = 1023; 00607 } else if (ast_false(v->value)) { 00608 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); 00609 enabled = 0; 00610 break; 00611 } 00612 } else if (!strcasecmp(v->name, "idlecheck")) { 00613 sscanf(v->value, "%ud", &idlecheck); 00614 } else if (!strcasecmp(v->name, "enabled")) { 00615 enabled = ast_true(v->value); 00616 } else if (!strcasecmp(v->name, "pre-connect")) { 00617 connect = ast_true(v->value); 00618 } else if (!strcasecmp(v->name, "dsn")) { 00619 dsn = v->value; 00620 } else if (!strcasecmp(v->name, "username")) { 00621 username = v->value; 00622 } else if (!strcasecmp(v->name, "password")) { 00623 password = v->value; 00624 } else if (!strcasecmp(v->name, "backslash_is_escape")) { 00625 bse = ast_true(v->value); 00626 } 00627 } 00628 00629 if (enabled && !ast_strlen_zero(dsn)) { 00630 /* First, check the list to see if it already exists */ 00631 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00632 if (!strcmp(class->name, cat)) { 00633 class->delme = 0; 00634 break; 00635 } 00636 } 00637 00638 if (class) { 00639 new = class; 00640 } else { 00641 new = ast_calloc(1, sizeof(*new)); 00642 } 00643 00644 if (!new) { 00645 res = -1; 00646 break; 00647 } 00648 00649 if (cat) 00650 ast_copy_string(new->name, cat, sizeof(new->name)); 00651 if (dsn) 00652 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00653 if (username) 00654 ast_copy_string(new->username, username, sizeof(new->username)); 00655 if (password) 00656 ast_copy_string(new->password, password, sizeof(new->password)); 00657 00658 if (!class) { 00659 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00660 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00661 00662 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00663 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00664 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00665 AST_LIST_UNLOCK(&odbc_list); 00666 return res; 00667 } 00668 } 00669 00670 if (pooling) { 00671 new->haspool = pooling; 00672 if (limit) { 00673 new->limit = limit; 00674 } else { 00675 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00676 new->limit = 5; 00677 } 00678 } 00679 00680 new->backslash_is_escape = bse; 00681 new->idlecheck = idlecheck; 00682 00683 if (class) { 00684 ast_log(LOG_NOTICE, "Refreshing ODBC class '%s' dsn->[%s]\n", cat, dsn); 00685 } else { 00686 odbc_register_class(new, connect); 00687 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00688 } 00689 } 00690 } 00691 } 00692 ast_config_destroy(config); 00693 } 00694 00695 /* Purge classes that we know can go away (pooled with 0, only) */ 00696 AST_LIST_TRAVERSE_SAFE_BEGIN(&odbc_list, class, list) { 00697 if (class->delme && class->haspool && class->count == 0) { 00698 AST_LIST_TRAVERSE_SAFE_BEGIN(&(class->odbc_obj), current, list) { 00699 AST_LIST_REMOVE_CURRENT(&(class->odbc_obj), list); 00700 odbc_obj_disconnect(current); 00701 ast_mutex_destroy(¤t->lock); 00702 free(current); 00703 } 00704 AST_LIST_TRAVERSE_SAFE_END; 00705 00706 AST_LIST_REMOVE_CURRENT(&odbc_list, list); 00707 free(class); 00708 } 00709 } 00710 AST_LIST_TRAVERSE_SAFE_END; 00711 AST_LIST_UNLOCK(&odbc_list); 00712 00713 return 0; 00714 }
static int unload_module | ( | void | ) | [static] |
struct ast_cli_entry cli_odbc[] [static] |
Initial value:
{ { { "odbc", "show", NULL }, odbc_show_command, "List ODBC DSN(s)", show_usage }, }
Definition at line 361 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 356 of file res_odbc.c.