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