#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/config.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_direct_execute (struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data) |
Executes an non prepared statement and returns the resulting statement handle. | |
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 char * | handle_cli_odbc_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
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 | reload (void) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .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 = "068e67f60f50dd9ee86464c05884a49d" , .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 [] |
Anthony Minessale II <anthmct@yahoo.com>
Definition in file res_odbc.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 817 of file res_odbc.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 817 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 445 of file res_odbc.c.
References odbc_class::backslash_is_escape, and odbc_obj::parent.
Referenced by odbc_log(), realtime_multi_odbc(), and realtime_odbc().
00446 { 00447 return obj->parent->backslash_is_escape; 00448 }
SQLHSTMT ast_odbc_direct_execute | ( | struct odbc_obj * | obj, | |
SQLHSTMT(*)(struct odbc_obj *obj, void *data) | exec_cb, | |||
void * | data | |||
) |
Executes an non prepared statement and returns the resulting statement handle.
obj | The ODBC object | |
exec_cb | A function callback, which, when called, should return a statement handle with result columns bound. | |
data | A parameter to be passed to the exec_cb parameter function, indicating which statement handle is to be prepared. |
a | statement handle | |
NULL | on error |
Definition at line 76 of file res_odbc.c.
References ast_log(), LOG_WARNING, odbc_obj_connect(), and odbc_obj_disconnect().
Referenced by acf_odbc_read(), and acf_odbc_write().
00077 { 00078 int attempt; 00079 SQLHSTMT stmt; 00080 00081 for (attempt = 0; attempt < 2; attempt++) { 00082 stmt = exec_cb(obj, data); 00083 00084 if (stmt) { 00085 break; 00086 } else { 00087 obj->up = 0; 00088 ast_log(LOG_WARNING, "SQL Exec Direct failed. Attempting a reconnect...\n"); 00089 00090 odbc_obj_disconnect(obj); 00091 odbc_obj_connect(obj); 00092 } 00093 } 00094 00095 return stmt; 00096 }
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. |
a | statement handle | |
NULL | on error |
Definition at line 98 of file res_odbc.c.
References ast_log(), ast_odbc_sanity_check(), ast_tvnow(), LOG_WARNING, and prepare_cb().
Referenced by config_odbc(), destroy_odbc(), odbc_log(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().
00099 { 00100 int res = 0, i, attempt; 00101 SQLINTEGER nativeerror=0, numfields=0; 00102 SQLSMALLINT diagbytes=0; 00103 unsigned char state[10], diagnostic[256]; 00104 SQLHSTMT stmt; 00105 00106 for (attempt = 0; attempt < 2; attempt++) { 00107 /* This prepare callback may do more than just prepare -- it may also 00108 * bind parameters, bind results, etc. The real key, here, is that 00109 * when we disconnect, all handles become invalid for most databases. 00110 * We must therefore redo everything when we establish a new 00111 * connection. */ 00112 stmt = prepare_cb(obj, data); 00113 00114 if (stmt) { 00115 res = SQLExecute(stmt); 00116 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00117 if (res == SQL_ERROR) { 00118 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00119 for (i = 0; i < numfields; i++) { 00120 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00121 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00122 if (i > 10) { 00123 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00124 break; 00125 } 00126 } 00127 } 00128 00129 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); 00130 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00131 stmt = NULL; 00132 00133 obj->up = 0; 00134 /* 00135 * While this isn't the best way to try to correct an error, this won't automatically 00136 * fail when the statement handle invalidates. 00137 */ 00138 ast_odbc_sanity_check(obj); 00139 continue; 00140 } else 00141 obj->last_used = ast_tvnow(); 00142 break; 00143 } else if (attempt == 0) 00144 ast_odbc_sanity_check(obj); 00145 } 00146 00147 return stmt; 00148 }
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 438 of file res_odbc.c.
References odbc_obj::used.
Referenced by config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().
00439 { 00440 /* For pooled connections, this frees the connection to be 00441 * reused. For non-pooled connections, it does nothing. */ 00442 obj->used = 0; 00443 }
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. |
ODBC | object | |
NULL | if there is no connection available with the requested name. |
Definition at line 450 of file res_odbc.c.
References ast_calloc, ast_free, 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_mutex_lock(), ast_mutex_unlock(), ast_odbc_sanity_check(), ast_tvdiff_sec(), ast_tvnow(), odbc_class::idlecheck, odbc_obj::last_used, odbc_class::list, odbc_obj::lock, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), odbc_obj::parent, and odbc_obj::used.
Referenced by acf_odbc_read(), acf_odbc_write(), config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().
00451 { 00452 struct odbc_obj *obj = NULL; 00453 struct odbc_class *class; 00454 00455 AST_LIST_LOCK(&odbc_list); 00456 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00457 if (!strcmp(class->name, name)) 00458 break; 00459 } 00460 AST_LIST_UNLOCK(&odbc_list); 00461 00462 if (!class) 00463 return NULL; 00464 00465 AST_LIST_LOCK(&class->odbc_obj); 00466 if (class->haspool) { 00467 /* Recycle connections before building another */ 00468 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00469 if (! obj->used) { 00470 ast_mutex_lock(&obj->lock); 00471 obj->used = 1; 00472 ast_mutex_unlock(&obj->lock); 00473 break; 00474 } 00475 } 00476 00477 if (!obj && (class->count < class->limit)) { 00478 class->count++; 00479 obj = ast_calloc(1, sizeof(*obj)); 00480 if (!obj) { 00481 AST_LIST_UNLOCK(&class->odbc_obj); 00482 return NULL; 00483 } 00484 ast_mutex_init(&obj->lock); 00485 obj->parent = class; 00486 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00487 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00488 ast_mutex_destroy(&obj->lock); 00489 ast_free(obj); 00490 obj = NULL; 00491 class->count--; 00492 } else { 00493 obj->used = 1; 00494 AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list); 00495 } 00496 } 00497 } else { 00498 /* Non-pooled connection: multiple modules can use the same connection. */ 00499 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00500 /* Non-pooled connection: if there is an entry, return it */ 00501 break; 00502 } 00503 00504 if (!obj) { 00505 /* No entry: build one */ 00506 obj = ast_calloc(1, sizeof(*obj)); 00507 if (!obj) { 00508 AST_LIST_UNLOCK(&class->odbc_obj); 00509 return NULL; 00510 } 00511 ast_mutex_init(&obj->lock); 00512 obj->parent = class; 00513 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00514 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00515 ast_mutex_destroy(&obj->lock); 00516 ast_free(obj); 00517 obj = NULL; 00518 } else { 00519 AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list); 00520 } 00521 } 00522 } 00523 AST_LIST_UNLOCK(&class->odbc_obj); 00524 00525 if (obj && check) { 00526 ast_odbc_sanity_check(obj); 00527 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) 00528 odbc_obj_connect(obj); 00529 00530 return obj; 00531 }
int ast_odbc_sanity_check | ( | struct odbc_obj * | obj | ) |
Checks an ODBC object to ensure it is still connected.
obj | The ODBC object |
0 | if connected | |
-1 | otherwise. |
Definition at line 193 of file res_odbc.c.
References ast_log(), ast_strlen_zero(), odbc_obj::con, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), odbc_obj::parent, odbc_class::sanitysql, and odbc_obj::up.
Referenced by ast_odbc_prepare_and_execute(), ast_odbc_request_obj(), and handle_cli_odbc_show().
00194 { 00195 char *test_sql = "select 1"; 00196 SQLHSTMT stmt; 00197 int res = 0; 00198 00199 if (!ast_strlen_zero(obj->parent->sanitysql)) 00200 test_sql = obj->parent->sanitysql; 00201 00202 if (obj->up) { 00203 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00204 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00205 obj->up = 0; 00206 } else { 00207 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00208 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00209 obj->up = 0; 00210 } else { 00211 res = SQLExecute(stmt); 00212 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00213 obj->up = 0; 00214 } 00215 } 00216 } 00217 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00218 } 00219 00220 if (!obj->up) { /* Try to reconnect! */ 00221 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00222 odbc_obj_disconnect(obj); 00223 odbc_obj_connect(obj); 00224 } 00225 return obj->up; 00226 }
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 |
0 | on success | |
-1 | on failure |
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 150 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.
00151 { 00152 int res = 0, i; 00153 SQLINTEGER nativeerror=0, numfields=0; 00154 SQLSMALLINT diagbytes=0; 00155 unsigned char state[10], diagnostic[256]; 00156 00157 res = SQLExecute(stmt); 00158 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00159 if (res == SQL_ERROR) { 00160 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00161 for (i = 0; i < numfields; i++) { 00162 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00163 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00164 if (i > 10) { 00165 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00166 break; 00167 } 00168 } 00169 } 00170 #if 0 00171 /* This is a really bad method of trying to correct a dead connection. It 00172 * only ever really worked with MySQL. It will not work with any other 00173 * database, since most databases prepare their statements on the server, 00174 * and if you disconnect, you invalidate the statement handle. Hence, if 00175 * you disconnect, you're going to fail anyway, whether you try to execute 00176 * a second time or not. 00177 */ 00178 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); 00179 ast_mutex_lock(&obj->lock); 00180 obj->up = 0; 00181 ast_mutex_unlock(&obj->lock); 00182 odbc_obj_disconnect(obj); 00183 odbc_obj_connect(obj); 00184 res = SQLExecute(stmt); 00185 #endif 00186 } else 00187 obj->last_used = ast_tvnow(); 00188 00189 return res; 00190 }
static char* handle_cli_odbc_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 348 of file res_odbc.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_odbc_sanity_check(), ast_strdup, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, odbc_obj::lock, ast_cli_args::n, ast_cli_args::pos, odbc_obj::up, ast_cli_entry::usage, odbc_obj::used, and ast_cli_args::word.
00349 { 00350 struct odbc_class *class; 00351 struct odbc_obj *current; 00352 int length = 0; 00353 int which = 0; 00354 char *ret = NULL; 00355 00356 switch (cmd) { 00357 case CLI_INIT: 00358 e->command = "odbc show"; 00359 e->usage = 00360 "Usage: odbc show [class]\n" 00361 " List settings of a particular ODBC class or,\n" 00362 " if not specified, all classes.\n"; 00363 return NULL; 00364 case CLI_GENERATE: 00365 if (a->pos != 2) 00366 return NULL; 00367 length = strlen(a->word); 00368 AST_LIST_LOCK(&odbc_list); 00369 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00370 if (!strncasecmp(a->word, class->name, length) && ++which > a->n) { 00371 ret = ast_strdup(class->name); 00372 break; 00373 } 00374 } 00375 if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) { 00376 ret = ast_strdup("all"); 00377 } 00378 AST_LIST_UNLOCK(&odbc_list); 00379 return ret; 00380 } 00381 00382 ast_cli(a->fd, "\nODBC DSN Settings\n"); 00383 ast_cli(a->fd, "-----------------\n\n"); 00384 AST_LIST_LOCK(&odbc_list); 00385 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00386 if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) { 00387 int count = 0; 00388 ast_cli(a->fd, " Name: %s\n DSN: %s\n", class->name, class->dsn); 00389 00390 if (class->haspool) { 00391 ast_cli(a->fd, " Pooled: Yes\n Limit: %d\n Connections in use: %d\n", class->limit, class->count); 00392 00393 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00394 ast_mutex_lock(¤t->lock); 00395 ast_cli(a->fd, " - Connection %d: %s\n", ++count, current->used ? "in use" : current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected"); 00396 ast_mutex_unlock(¤t->lock); 00397 } 00398 } else { 00399 /* Should only ever be one of these */ 00400 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00401 ast_cli(a->fd, " Pooled: No\n Connected: %s\n", current->up && ast_odbc_sanity_check(current) ? "Yes" : "No"); 00402 } 00403 } 00404 ast_cli(a->fd, "\n"); 00405 } 00406 } 00407 AST_LIST_UNLOCK(&odbc_list); 00408 00409 return CLI_SUCCESS; 00410 }
static int load_module | ( | void | ) | [static] |
Definition at line 804 of file res_odbc.c.
References ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_DECLINE, cli_odbc, load_odbc_config(), and LOG_NOTICE.
00805 { 00806 if (load_odbc_config() == -1) 00807 return AST_MODULE_LOAD_DECLINE; 00808 ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry)); 00809 ast_log(LOG_NOTICE, "res_odbc loaded.\n"); 00810 return 0; 00811 }
static int load_odbc_config | ( | void | ) | [static] |
Definition at line 228 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::sanitysql, setenv(), odbc_class::username, and ast_variable::value.
Referenced by load_module().
00229 { 00230 static char *cfg = "res_odbc.conf"; 00231 struct ast_config *config; 00232 struct ast_variable *v; 00233 char *cat; 00234 const char *dsn, *username, *password, *sanitysql; 00235 int enabled, pooling, limit, bse; 00236 unsigned int idlecheck; 00237 int connect = 0, res = 0; 00238 struct ast_flags config_flags = { 0 }; 00239 00240 struct odbc_class *new; 00241 00242 config = ast_config_load(cfg, config_flags); 00243 if (!config) { 00244 ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n"); 00245 return -1; 00246 } 00247 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00248 if (!strcasecmp(cat, "ENV")) { 00249 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00250 setenv(v->name, v->value, 1); 00251 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00252 } 00253 } else { 00254 /* Reset all to defaults for each class of odbc connections */ 00255 dsn = username = password = sanitysql = NULL; 00256 enabled = 1; 00257 connect = idlecheck = 0; 00258 pooling = 0; 00259 limit = 0; 00260 bse = 1; 00261 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00262 if (!strcasecmp(v->name, "pooling")) { 00263 if (ast_true(v->value)) 00264 pooling = 1; 00265 } else if (!strncasecmp(v->name, "share", 5)) { 00266 /* "shareconnections" is a little clearer in meaning than "pooling" */ 00267 if (ast_false(v->value)) 00268 pooling = 1; 00269 } else if (!strcasecmp(v->name, "limit")) { 00270 sscanf(v->value, "%d", &limit); 00271 if (ast_true(v->value) && !limit) { 00272 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); 00273 limit = 1023; 00274 } else if (ast_false(v->value)) { 00275 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); 00276 enabled = 0; 00277 break; 00278 } 00279 } else if (!strcasecmp(v->name, "idlecheck")) { 00280 sscanf(v->value, "%d", &idlecheck); 00281 } else if (!strcasecmp(v->name, "enabled")) { 00282 enabled = ast_true(v->value); 00283 } else if (!strcasecmp(v->name, "pre-connect")) { 00284 connect = ast_true(v->value); 00285 } else if (!strcasecmp(v->name, "dsn")) { 00286 dsn = v->value; 00287 } else if (!strcasecmp(v->name, "username")) { 00288 username = v->value; 00289 } else if (!strcasecmp(v->name, "password")) { 00290 password = v->value; 00291 } else if (!strcasecmp(v->name, "sanitysql")) { 00292 sanitysql = v->value; 00293 } else if (!strcasecmp(v->name, "backslash_is_escape")) { 00294 bse = ast_true(v->value); 00295 } 00296 } 00297 00298 if (enabled && !ast_strlen_zero(dsn)) { 00299 new = ast_calloc(1, sizeof(*new)); 00300 00301 if (!new) { 00302 res = -1; 00303 break; 00304 } 00305 00306 if (cat) 00307 ast_copy_string(new->name, cat, sizeof(new->name)); 00308 if (dsn) 00309 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00310 if (username) 00311 new->username = ast_strdup(username); 00312 if (password) 00313 new->password = ast_strdup(password); 00314 if (sanitysql) 00315 ast_copy_string(new->sanitysql, sanitysql, sizeof(new->sanitysql)); 00316 00317 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00318 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00319 00320 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00321 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00322 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00323 return res; 00324 } 00325 00326 if (pooling) { 00327 new->haspool = pooling; 00328 if (limit) { 00329 new->limit = limit; 00330 } else { 00331 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00332 new->limit = 5; 00333 } 00334 } 00335 00336 new->backslash_is_escape = bse ? 1 : 0; 00337 new->idlecheck = idlecheck; 00338 00339 odbc_register_class(new, connect); 00340 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00341 } 00342 } 00343 } 00344 ast_config_destroy(config); 00345 return res; 00346 }
static odbc_status odbc_obj_connect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 562 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, msg, 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_direct_execute(), ast_odbc_request_obj(), ast_odbc_sanity_check(), and ast_odbc_smart_execute().
00563 { 00564 int res; 00565 SQLINTEGER err; 00566 short int mlen; 00567 unsigned char msg[200], stat[10]; 00568 #ifdef NEEDTRACE 00569 SQLINTEGER enable = 1; 00570 char *tracefile = "/tmp/odbc.trace"; 00571 #endif 00572 ast_mutex_lock(&obj->lock); 00573 00574 res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con); 00575 00576 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00577 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res); 00578 ast_mutex_unlock(&obj->lock); 00579 return ODBC_FAIL; 00580 } 00581 SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); 00582 SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) 10, 0); 00583 #ifdef NEEDTRACE 00584 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); 00585 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); 00586 #endif 00587 00588 if (obj->up) { 00589 odbc_obj_disconnect(obj); 00590 ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name); 00591 } else { 00592 ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name); 00593 } 00594 00595 res = SQLConnect(obj->con, 00596 (SQLCHAR *) obj->parent->dsn, SQL_NTS, 00597 (SQLCHAR *) obj->parent->username, SQL_NTS, 00598 (SQLCHAR *) obj->parent->password, SQL_NTS); 00599 00600 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00601 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); 00602 ast_mutex_unlock(&obj->lock); 00603 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg); 00604 return ODBC_FAIL; 00605 } else { 00606 ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn); 00607 obj->up = 1; 00608 obj->last_used = ast_tvnow(); 00609 } 00610 00611 ast_mutex_unlock(&obj->lock); 00612 return ODBC_SUCCESS; 00613 }
static odbc_status odbc_obj_disconnect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 533 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, msg, odbc_class::name, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.
Referenced by ast_odbc_direct_execute(), ast_odbc_sanity_check(), ast_odbc_smart_execute(), and odbc_obj_connect().
00534 { 00535 int res; 00536 SQLINTEGER err; 00537 short int mlen; 00538 unsigned char msg[200], stat[10]; 00539 00540 ast_mutex_lock(&obj->lock); 00541 00542 res = SQLDisconnect(obj->con); 00543 00544 if (res == ODBC_SUCCESS) { 00545 ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn); 00546 } else { 00547 ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn); 00548 } 00549 00550 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == ODBC_SUCCESS)) { 00551 ast_log(LOG_DEBUG, "Database handle deallocated\n"); 00552 } else { 00553 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); 00554 ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg); 00555 } 00556 00557 obj->up = 0; 00558 ast_mutex_unlock(&obj->lock); 00559 return ODBC_SUCCESS; 00560 }
static int odbc_register_class | ( | struct odbc_class * | class, | |
int | connect | |||
) | [static] |
Definition at line 416 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.
00417 { 00418 struct odbc_obj *obj; 00419 if (class) { 00420 AST_LIST_LOCK(&odbc_list); 00421 AST_LIST_INSERT_HEAD(&odbc_list, class, list); 00422 AST_LIST_UNLOCK(&odbc_list); 00423 00424 if (connect) { 00425 /* Request and release builds a connection */ 00426 obj = ast_odbc_request_obj(class->name, 0); 00427 if (obj) 00428 ast_odbc_release_obj(obj); 00429 } 00430 00431 return 0; 00432 } else { 00433 ast_log(LOG_WARNING, "Attempted to register a NULL class?\n"); 00434 return -1; 00435 } 00436 }
static int reload | ( | void | ) | [static] |
Definition at line 615 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, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, enabled, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, setenv(), and ast_variable::value.
00616 { 00617 static char *cfg = "res_odbc.conf"; 00618 struct ast_config *config; 00619 struct ast_variable *v; 00620 char *cat; 00621 const char *dsn, *username, *password, *sanitysql; 00622 int enabled, pooling, limit, bse; 00623 unsigned int idlecheck; 00624 int connect = 0, res = 0; 00625 struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED }; 00626 00627 struct odbc_class *new, *class; 00628 struct odbc_obj *current; 00629 00630 /* First, mark all to be purged */ 00631 AST_LIST_LOCK(&odbc_list); 00632 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00633 class->delme = 1; 00634 } 00635 00636 config = ast_config_load(cfg, config_flags); 00637 if (config != NULL && config != CONFIG_STATUS_FILEUNCHANGED) { 00638 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00639 if (!strcasecmp(cat, "ENV")) { 00640 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00641 setenv(v->name, v->value, 1); 00642 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00643 } 00644 } else { 00645 char *freeme = NULL; 00646 /* Reset all to defaults for each class of odbc connections */ 00647 dsn = username = password = sanitysql = NULL; 00648 enabled = 1; 00649 connect = idlecheck = 0; 00650 pooling = 0; 00651 limit = 0; 00652 bse = 1; 00653 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00654 if (!strcasecmp(v->name, "pooling")) { 00655 if (ast_true(v->value)) 00656 pooling = 1; 00657 } else if (!strncasecmp(v->name, "share", 5)) { 00658 /* "shareconnections" is a little clearer in meaning than "pooling" */ 00659 if (ast_false(v->value)) 00660 pooling = 1; 00661 } else if (!strcasecmp(v->name, "limit")) { 00662 sscanf(v->value, "%d", &limit); 00663 if (ast_true(v->value) && !limit) { 00664 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); 00665 limit = 1023; 00666 } else if (ast_false(v->value)) { 00667 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); 00668 enabled = 0; 00669 break; 00670 } 00671 } else if (!strcasecmp(v->name, "idlecheck")) { 00672 sscanf(v->value, "%ud", &idlecheck); 00673 } else if (!strcasecmp(v->name, "enabled")) { 00674 enabled = ast_true(v->value); 00675 } else if (!strcasecmp(v->name, "pre-connect")) { 00676 connect = ast_true(v->value); 00677 } else if (!strcasecmp(v->name, "dsn")) { 00678 dsn = v->value; 00679 } else if (!strcasecmp(v->name, "username")) { 00680 username = v->value; 00681 } else if (!strcasecmp(v->name, "password")) { 00682 password = v->value; 00683 } else if (!strcasecmp(v->name, "sanitysql")) { 00684 sanitysql = v->value; 00685 } else if (!strcasecmp(v->name, "backslash_is_escape")) { 00686 bse = ast_true(v->value); 00687 } 00688 } 00689 00690 if (enabled && !ast_strlen_zero(dsn)) { 00691 /* First, check the list to see if it already exists */ 00692 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00693 if (!strcmp(class->name, cat)) { 00694 class->delme = 0; 00695 break; 00696 } 00697 } 00698 00699 if (class) { 00700 new = class; 00701 } else { 00702 new = ast_calloc(1, sizeof(*new)); 00703 } 00704 00705 if (!new) { 00706 res = -1; 00707 break; 00708 } 00709 00710 if (cat) 00711 ast_copy_string(new->name, cat, sizeof(new->name)); 00712 if (dsn) 00713 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00714 00715 /* Safely replace username */ 00716 if (class && class->username) 00717 freeme = class->username; 00718 if (username) 00719 new->username = ast_strdup(username); 00720 if (freeme) { 00721 ast_free(freeme); 00722 freeme = NULL; 00723 } 00724 00725 /* Safely replace password */ 00726 if (class && class->password) 00727 freeme = class->password; 00728 if (password) 00729 new->password = ast_strdup(password); 00730 if (freeme) { 00731 ast_free(freeme); 00732 freeme = NULL; 00733 } 00734 00735 if (sanitysql) 00736 ast_copy_string(new->sanitysql, sanitysql, sizeof(new->sanitysql)); 00737 00738 if (!class) { 00739 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00740 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00741 00742 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00743 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00744 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00745 AST_LIST_UNLOCK(&odbc_list); 00746 return res; 00747 } 00748 } 00749 00750 if (pooling) { 00751 new->haspool = pooling; 00752 if (limit) { 00753 new->limit = limit; 00754 } else { 00755 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00756 new->limit = 5; 00757 } 00758 } 00759 00760 new->backslash_is_escape = bse; 00761 new->idlecheck = idlecheck; 00762 00763 if (class) { 00764 ast_log(LOG_NOTICE, "Refreshing ODBC class '%s' dsn->[%s]\n", cat, dsn); 00765 } else { 00766 odbc_register_class(new, connect); 00767 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00768 } 00769 } 00770 } 00771 } 00772 ast_config_destroy(config); 00773 } 00774 00775 /* Purge classes that we know can go away (pooled with 0, only) */ 00776 AST_LIST_TRAVERSE_SAFE_BEGIN(&odbc_list, class, list) { 00777 if (class->delme && class->haspool && class->count == 0) { 00778 while ((current = AST_LIST_REMOVE_HEAD(&class->odbc_obj, list))) { 00779 odbc_obj_disconnect(current); 00780 ast_mutex_destroy(¤t->lock); 00781 ast_free(current); 00782 } 00783 00784 AST_LIST_REMOVE_CURRENT(list); 00785 if (class->username) 00786 ast_free(class->username); 00787 if (class->password) 00788 ast_free(class->password); 00789 ast_free(class); 00790 } 00791 } 00792 AST_LIST_TRAVERSE_SAFE_END; 00793 AST_LIST_UNLOCK(&odbc_list); 00794 00795 return 0; 00796 }
static int unload_module | ( | void | ) | [static] |
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 817 of file res_odbc.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 817 of file res_odbc.c.
struct ast_cli_entry cli_odbc[] [static] |
Initial value:
{ { .handler = handle_cli_odbc_show , .summary = "List ODBC DSN(s)" ,__VA_ARGS__ } }
Definition at line 412 of file res_odbc.c.
Referenced by load_module().