![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
res_odbc.c File Reference
Anthony Minessale II <anthmct@yahoo.com>
Definition in file res_odbc.c.
#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 dependency graph for res_odbc.c:

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,) | |
| 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 const char | show_usage [] |
|
||||||||||||
|
|
|
||||||||||||||||||||||||||||
|
|
|
||||||||||||||||
|
Prepares, executes, and returns the resulting statement handle.
Definition at line 79 of file res_odbc.c. References ast_log(), and LOG_WARNING. Referenced by config_odbc(). 00080 { 00081 int res = 0, i, attempt; 00082 SQLINTEGER nativeerror=0, numfields=0; 00083 SQLSMALLINT diagbytes=0; 00084 unsigned char state[10], diagnostic[256]; 00085 SQLHSTMT stmt; 00086 00087 for (attempt = 0; attempt < 2; attempt++) { 00088 /* This prepare callback may do more than just prepare -- it may also 00089 * bind parameters, bind results, etc. The real key, here, is that 00090 * when we disconnect, all handles become invalid for most databases. 00091 * We must therefore redo everything when we establish a new 00092 * connection. */ 00093 stmt = prepare_cb(obj, data); 00094 00095 if (stmt) { 00096 res = SQLExecute(stmt); 00097 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00098 if (res == SQL_ERROR) { 00099 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00100 for (i=0; i< numfields + 1; i++) { 00101 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00102 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00103 if (i > 10) { 00104 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00105 break; 00106 } 00107 } 00108 } 00109 00110 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); 00111 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00112 stmt = NULL; 00113 00114 obj->up = 0; 00115 /* 00116 * While this isn't the best way to try to correct an error, this won't automatically 00117 * fail when the statement handle invalidates. 00118 */ 00119 ast_odbc_sanity_check(obj); 00120 continue; 00121 } 00122 break; 00123 } else if (attempt == 0) 00124 ast_odbc_sanity_check(obj); 00125 } 00126 00127 return stmt; 00128 }
|
|
|
Releases an ODBC object previously allocated by odbc_request_obj().
Definition at line 377 of file res_odbc.c. References odbc_obj::used. Referenced by config_odbc(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), and update_odbc(). 00378 { 00379 /* For pooled connections, this frees the connection to be 00380 * reused. For non-pooled connections, it does nothing. */ 00381 obj->used = 0; 00382 }
|
|
||||||||||||
|
Retrieves a connected ODBC object.
Definition at line 384 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, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), and odbc_obj::used. Referenced by config_odbc(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), and update_odbc(). 00385 { 00386 struct odbc_obj *obj = NULL; 00387 struct odbc_class *class; 00388 00389 AST_LIST_LOCK(&odbc_list); 00390 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00391 if (!strcmp(class->name, name)) 00392 break; 00393 } 00394 AST_LIST_UNLOCK(&odbc_list); 00395 00396 if (!class) 00397 return NULL; 00398 00399 AST_LIST_LOCK(&class->odbc_obj); 00400 if (class->haspool) { 00401 /* Recycle connections before building another */ 00402 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00403 if (! obj->used) { 00404 obj->used = 1; 00405 break; 00406 } 00407 } 00408 00409 if (!obj && (class->count < class->limit)) { 00410 class->count++; 00411 obj = ast_calloc(1, sizeof(*obj)); 00412 if (!obj) { 00413 AST_LIST_UNLOCK(&class->odbc_obj); 00414 return NULL; 00415 } 00416 ast_mutex_init(&obj->lock); 00417 obj->parent = class; 00418 odbc_obj_connect(obj); 00419 AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list); 00420 } 00421 } else { 00422 /* Non-pooled connection: multiple modules can use the same connection. */ 00423 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00424 /* Non-pooled connection: if there is an entry, return it */ 00425 break; 00426 } 00427 00428 if (!obj) { 00429 /* No entry: build one */ 00430 obj = ast_calloc(1, sizeof(*obj)); 00431 if (!obj) { 00432 AST_LIST_UNLOCK(&class->odbc_obj); 00433 return NULL; 00434 } 00435 ast_mutex_init(&obj->lock); 00436 obj->parent = class; 00437 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00438 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00439 ast_mutex_destroy(&obj->lock); 00440 free(obj); 00441 obj = NULL; 00442 } else { 00443 AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list); 00444 } 00445 } 00446 } 00447 AST_LIST_UNLOCK(&class->odbc_obj); 00448 00449 if (obj && check) { 00450 ast_odbc_sanity_check(obj); 00451 } 00452 return obj; 00453 }
|
|
|
Checks an ODBC object to ensure it is still connected.
Definition at line 172 of file res_odbc.c. References ast_log(), odbc_obj::con, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), odbc_obj::parent, and odbc_obj::up. Referenced by ast_odbc_request_obj(), and odbc_show_command(). 00173 { 00174 char *test_sql = "select 1"; 00175 SQLHSTMT stmt; 00176 int res = 0; 00177 00178 if (obj->parent->sanitysql) 00179 test_sql = obj->parent->sanitysql; 00180 00181 if (obj->up) { 00182 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00183 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00184 obj->up = 0; 00185 } else { 00186 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00187 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00188 obj->up = 0; 00189 } else { 00190 res = SQLExecute(stmt); 00191 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00192 obj->up = 0; 00193 } 00194 } 00195 } 00196 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00197 } 00198 00199 if (!obj->up) { /* Try to reconnect! */ 00200 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00201 odbc_obj_disconnect(obj); 00202 odbc_obj_connect(obj); 00203 } 00204 return obj->up; 00205 }
|
|
||||||||||||
|
Executes a 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 130 of file res_odbc.c. References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::lock, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), and odbc_obj::up. Referenced by realtime_multi_odbc(), realtime_odbc(), and update_odbc(). 00131 { 00132 int res = 0, i; 00133 SQLINTEGER nativeerror=0, numfields=0; 00134 SQLSMALLINT diagbytes=0; 00135 unsigned char state[10], diagnostic[256]; 00136 00137 res = SQLExecute(stmt); 00138 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00139 if (res == SQL_ERROR) { 00140 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00141 for (i=0; i< numfields + 1; i++) { 00142 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00143 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00144 if (i > 10) { 00145 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00146 break; 00147 } 00148 } 00149 } 00150 #if 0 00151 /* This is a really bad method of trying to correct a dead connection. It 00152 * only ever really worked with MySQL. It will not work with any other 00153 * database, since most databases prepare their statements on the server, 00154 * and if you disconnect, you invalidate the statement handle. Hence, if 00155 * you disconnect, you're going to fail anyway, whether you try to execute 00156 * a second time or not. 00157 */ 00158 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); 00159 ast_mutex_lock(&obj->lock); 00160 obj->up = 0; 00161 ast_mutex_unlock(&obj->lock); 00162 odbc_obj_disconnect(obj); 00163 odbc_obj_connect(obj); 00164 res = SQLExecute(stmt); 00165 #endif 00166 } 00167 00168 return res; 00169 }
|
|
|
Definition at line 680 of file res_odbc.c. References ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_DECLINE, cli_odbc, load_odbc_config(), and LOG_NOTICE. 00681 { 00682 if(load_odbc_config() == -1) 00683 return AST_MODULE_LOAD_DECLINE; 00684 ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry)); 00685 ast_log(LOG_NOTICE, "res_odbc loaded.\n"); 00686 return 0; 00687 }
|
|
|
Definition at line 207 of file res_odbc.c. References ast_category_browse(), ast_config_load(), ast_log(), ast_variable_browse(), config, enabled, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, setenv(), and ast_variable::value. Referenced by load_module(). 00208 { 00209 static char *cfg = "res_odbc.conf"; 00210 struct ast_config *config; 00211 struct ast_variable *v; 00212 char *cat, *dsn, *username, *password, *sanitysql; 00213 int enabled, pooling, limit; 00214 int connect = 0, res = 0; 00215 00216 struct odbc_class *new; 00217 00218 config = ast_config_load(cfg); 00219 if (!config) { 00220 ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n"); 00221 return -1; 00222 } 00223 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00224 if (!strcasecmp(cat, "ENV")) { 00225 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00226 setenv(v->name, v->value, 1); 00227 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00228 } 00229 } else { 00230 /* Reset all to defaults for each class of odbc connections */ 00231 dsn = username = password = sanitysql = NULL; 00232 enabled = 1; 00233 connect = 0; 00234 pooling = 0; 00235 limit = 0; 00236 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00237 if (!strcasecmp(v->name, "pooling")) { 00238 if (ast_true(v->value)) 00239 pooling = 1; 00240 } else if (!strcasecmp(v->name, "limit")) { 00241 sscanf(v->value, "%d", &limit); 00242 if (ast_true(v->value) && !limit) { 00243 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); 00244 limit = 1023; 00245 } else if (ast_false(v->value)) { 00246 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); 00247 enabled = 0; 00248 break; 00249 } 00250 } else if (!strcasecmp(v->name, "enabled")) { 00251 enabled = ast_true(v->value); 00252 } else if (!strcasecmp(v->name, "pre-connect")) { 00253 connect = ast_true(v->value); 00254 } else if (!strcasecmp(v->name, "dsn")) { 00255 dsn = v->value; 00256 } else if (!strcasecmp(v->name, "username")) { 00257 username = v->value; 00258 } else if (!strcasecmp(v->name, "password")) { 00259 password = v->value; 00260 } else if (!strcasecmp(v->name, "sanitysql")) { 00261 sanitysql = v->value; 00262 } 00263 } 00264 00265 if (enabled && !ast_strlen_zero(dsn)) { 00266 new = ast_calloc(1, sizeof(*new)); 00267 00268 if (!new) { 00269 res = -1; 00270 break; 00271 } 00272 00273 if (cat) 00274 ast_copy_string(new->name, cat, sizeof(new->name)); 00275 if (dsn) 00276 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00277 if (username) 00278 ast_copy_string(new->username, username, sizeof(new->username)); 00279 if (password) 00280 ast_copy_string(new->password, password, sizeof(new->password)); 00281 if (sanitysql) 00282 ast_copy_string(new->sanitysql, sanitysql, sizeof(new->sanitysql)); 00283 00284 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00285 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00286 00287 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00288 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00289 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00290 return res; 00291 } 00292 00293 if (pooling) { 00294 new->haspool = pooling; 00295 if (limit) { 00296 new->limit = limit; 00297 } else { 00298 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00299 new->limit = 5; 00300 } 00301 } 00302 00303 odbc_register_class(new, connect); 00304 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00305 } 00306 } 00307 } 00308 ast_config_destroy(config); 00309 return res; 00310 }
|
|
|
Definition at line 473 of file res_odbc.c. References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::con, 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_request_obj(), ast_odbc_sanity_check(), and ast_odbc_smart_execute(). 00474 { 00475 int res; 00476 SQLINTEGER err; 00477 short int mlen; 00478 unsigned char msg[200], stat[10]; 00479 #ifdef NEEDTRACE 00480 SQLINTEGER enable = 1; 00481 char *tracefile = "/tmp/odbc.trace"; 00482 #endif 00483 ast_mutex_lock(&obj->lock); 00484 00485 res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con); 00486 00487 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00488 00489 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res); 00490 SQLFreeHandle(SQL_HANDLE_ENV, obj->parent->env); 00491 00492 ast_mutex_unlock(&obj->lock); 00493 return ODBC_FAIL; 00494 } 00495 SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); 00496 #ifdef NEEDTRACE 00497 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); 00498 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); 00499 #endif 00500 00501 if (obj->up) { 00502 odbc_obj_disconnect(obj); 00503 ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name); 00504 } else { 00505 ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name); 00506 } 00507 00508 res = SQLConnect(obj->con, 00509 (SQLCHAR *) obj->parent->dsn, SQL_NTS, 00510 (SQLCHAR *) obj->parent->username, SQL_NTS, 00511 (SQLCHAR *) obj->parent->password, SQL_NTS); 00512 00513 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00514 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); 00515 ast_mutex_unlock(&obj->lock); 00516 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg); 00517 return ODBC_FAIL; 00518 } else { 00519 ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn); 00520 obj->up = 1; 00521 } 00522 00523 ast_mutex_unlock(&obj->lock); 00524 return ODBC_SUCCESS; 00525 }
|
|
|
Definition at line 455 of file res_odbc.c. References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::con, odbc_obj::lock, LOG_WARNING, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up. Referenced by ast_odbc_sanity_check(), ast_odbc_smart_execute(), and odbc_obj_connect(). 00456 { 00457 int res; 00458 ast_mutex_lock(&obj->lock); 00459 00460 res = SQLDisconnect(obj->con); 00461 00462 if (res == ODBC_SUCCESS) { 00463 ast_log(LOG_WARNING, "res_odbc: disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn); 00464 } else { 00465 ast_log(LOG_WARNING, "res_odbc: %s [%s] already disconnected\n", 00466 obj->parent->name, obj->parent->dsn); 00467 } 00468 obj->up = 0; 00469 ast_mutex_unlock(&obj->lock); 00470 return ODBC_SUCCESS; 00471 }
|
|
||||||||||||
|
Definition at line 355 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. 00356 { 00357 struct odbc_obj *obj; 00358 if (class) { 00359 AST_LIST_LOCK(&odbc_list); 00360 AST_LIST_INSERT_HEAD(&odbc_list, class, list); 00361 AST_LIST_UNLOCK(&odbc_list); 00362 00363 if (connect) { 00364 /* Request and release builds a connection */ 00365 obj = ast_odbc_request_obj(class->name, 0); 00366 if (obj) 00367 ast_odbc_release_obj(obj); 00368 } 00369 00370 return 0; 00371 } else { 00372 ast_log(LOG_WARNING, "Attempted to register a NULL class?\n"); 00373 return -1; 00374 } 00375 }
|
|
||||||||||||||||
|
Definition at line 312 of file res_odbc.c. References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_odbc_sanity_check(), and odbc_obj::up. 00313 { 00314 struct odbc_class *class; 00315 struct odbc_obj *current; 00316 00317 AST_LIST_LOCK(&odbc_list); 00318 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00319 if ((argc == 2) || (argc == 3 && !strcmp(argv[2], "all")) || (!strcmp(argv[2], class->name))) { 00320 int count = 0; 00321 ast_cli(fd, "Name: %s\nDSN: %s\n", class->name, class->dsn); 00322 00323 if (class->haspool) { 00324 ast_cli(fd, "Pooled: yes\nLimit: %d\nConnections in use: %d\n", class->limit, class->count); 00325 00326 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00327 ast_cli(fd, " Connection %d: %s", ++count, current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected"); 00328 } 00329 } else { 00330 /* Should only ever be one of these */ 00331 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00332 ast_cli(fd, "Pooled: no\nConnected: %s\n", current->up && ast_odbc_sanity_check(current) ? "yes" : "no"); 00333 } 00334 } 00335 00336 ast_cli(fd, "\n"); 00337 } 00338 } 00339 AST_LIST_UNLOCK(&odbc_list); 00340 00341 return 0; 00342 }
|
|
|
Definition at line 527 of file res_odbc.c. References ast_category_browse(), ast_config_load(), 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. 00528 { 00529 static char *cfg = "res_odbc.conf"; 00530 struct ast_config *config; 00531 struct ast_variable *v; 00532 char *cat, *dsn, *username, *password, *sanitysql; 00533 int enabled, pooling, limit; 00534 int connect = 0, res = 0; 00535 00536 struct odbc_class *new, *class; 00537 struct odbc_obj *current; 00538 00539 /* First, mark all to be purged */ 00540 AST_LIST_LOCK(&odbc_list); 00541 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00542 class->delme = 1; 00543 } 00544 00545 config = ast_config_load(cfg); 00546 if (config) { 00547 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00548 if (!strcasecmp(cat, "ENV")) { 00549 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00550 setenv(v->name, v->value, 1); 00551 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00552 } 00553 } else { 00554 /* Reset all to defaults for each class of odbc connections */ 00555 dsn = username = password = sanitysql = NULL; 00556 enabled = 1; 00557 connect = 0; 00558 pooling = 0; 00559 limit = 0; 00560 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00561 if (!strcasecmp(v->name, "pooling")) { 00562 pooling = 1; 00563 } else if (!strcasecmp(v->name, "limit")) { 00564 sscanf(v->value, "%d", &limit); 00565 if (ast_true(v->value) && !limit) { 00566 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); 00567 limit = 1023; 00568 } else if (ast_false(v->value)) { 00569 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); 00570 enabled = 0; 00571 break; 00572 } 00573 } else if (!strcasecmp(v->name, "enabled")) { 00574 enabled = ast_true(v->value); 00575 } else if (!strcasecmp(v->name, "pre-connect")) { 00576 connect = ast_true(v->value); 00577 } else if (!strcasecmp(v->name, "dsn")) { 00578 dsn = v->value; 00579 } else if (!strcasecmp(v->name, "username")) { 00580 username = v->value; 00581 } else if (!strcasecmp(v->name, "password")) { 00582 password = v->value; 00583 } else if (!strcasecmp(v->name, "sanitysql")) { 00584 sanitysql = v->value; 00585 } 00586 } 00587 00588 if (enabled && !ast_strlen_zero(dsn)) { 00589 /* First, check the list to see if it already exists */ 00590 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00591 if (!strcmp(class->name, cat)) { 00592 class->delme = 0; 00593 break; 00594 } 00595 } 00596 00597 if (class) { 00598 new = class; 00599 } else { 00600 new = ast_calloc(1, sizeof(*new)); 00601 } 00602 00603 if (!new) { 00604 res = -1; 00605 break; 00606 } 00607 00608 if (cat) 00609 ast_copy_string(new->name, cat, sizeof(new->name)); 00610 if (dsn) 00611 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00612 if (username) 00613 ast_copy_string(new->username, username, sizeof(new->username)); 00614 if (password) 00615 ast_copy_string(new->password, password, sizeof(new->password)); 00616 if (sanitysql) 00617 ast_copy_string(new->sanitysql, sanitysql, sizeof(new->sanitysql)); 00618 00619 if (!class) { 00620 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00621 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00622 00623 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00624 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00625 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00626 AST_LIST_UNLOCK(&odbc_list); 00627 return res; 00628 } 00629 } 00630 00631 if (pooling) { 00632 new->haspool = pooling; 00633 if (limit) { 00634 new->limit = limit; 00635 } else { 00636 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00637 new->limit = 5; 00638 } 00639 } 00640 00641 if (class) { 00642 ast_log(LOG_NOTICE, "Refreshing ODBC class '%s' dsn->[%s]\n", cat, dsn); 00643 } else { 00644 odbc_register_class(new, connect); 00645 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00646 } 00647 } 00648 } 00649 } 00650 ast_config_destroy(config); 00651 } 00652 00653 /* Purge classes that we know can go away (pooled with 0, only) */ 00654 AST_LIST_TRAVERSE_SAFE_BEGIN(&odbc_list, class, list) { 00655 if (class->delme && class->haspool && class->count == 0) { 00656 AST_LIST_TRAVERSE_SAFE_BEGIN(&(class->odbc_obj), current, list) { 00657 AST_LIST_REMOVE_CURRENT(&(class->odbc_obj), list); 00658 odbc_obj_disconnect(current); 00659 ast_mutex_destroy(¤t->lock); 00660 free(current); 00661 } 00662 AST_LIST_TRAVERSE_SAFE_END; 00663 00664 AST_LIST_REMOVE_CURRENT(&odbc_list, list); 00665 free(class); 00666 } 00667 } 00668 AST_LIST_TRAVERSE_SAFE_END; 00669 AST_LIST_UNLOCK(&odbc_list); 00670 00671 return 0; 00672 }
|
|
|
Definition at line 674 of file res_odbc.c.
|
|
|
Initial value: {
{ { "odbc", "show", NULL },
odbc_show_command, "List ODBC DSN(s)",
show_usage },
}
Definition at line 349 of file res_odbc.c. Referenced by load_module(). |
|
|
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 344 of file res_odbc.c. |