#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/options.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/res_odbc.h"
#include "asterisk/time.h"
Go to the source code of this file.
Data Structures | |
struct | odbc_class |
struct | odbc_list |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
int | ast_odbc_backslash_is_escape (struct odbc_obj *obj) |
Checks if the database natively supports backslash as an escape character. | |
SQLHSTMT | ast_odbc_prepare_and_execute (struct odbc_obj *obj, SQLHSTMT(*prepare_cb)(struct odbc_obj *obj, void *data), void *data) |
Prepares, executes, and returns the resulting statement handle. | |
void | ast_odbc_release_obj (struct odbc_obj *obj) |
Releases an ODBC object previously allocated by odbc_request_obj(). | |
odbc_obj * | ast_odbc_request_obj (const char *name, int check) |
Retrieves a connected ODBC object. | |
int | ast_odbc_sanity_check (struct odbc_obj *obj) |
Checks an ODBC object to ensure it is still connected. | |
int | ast_odbc_smart_execute (struct odbc_obj *obj, SQLHSTMT stmt) |
Executes a prepared statement handle. | |
static int | load_module (void) |
static int | load_odbc_config (void) |
static odbc_status | odbc_obj_connect (struct odbc_obj *obj) |
static odbc_status | odbc_obj_disconnect (struct odbc_obj *obj) |
static int | odbc_register_class (struct odbc_class *class, int connect) |
static int | odbc_show_command (int fd, int argc, char **argv) |
static int | reload (void) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "ODBC Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, } |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_cli_entry | cli_odbc [] |
static char | show_usage [] |
Anthony Minessale II <anthmct@yahoo.com>
Definition in file res_odbc.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 745 of file res_odbc.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 745 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 400 of file res_odbc.c.
References odbc_class::backslash_is_escape, and odbc_obj::parent.
Referenced by realtime_multi_odbc(), and realtime_odbc().
00401 { 00402 return obj->parent->backslash_is_escape; 00403 }
SQLHSTMT ast_odbc_prepare_and_execute | ( | struct odbc_obj * | obj, | |
SQLHSTMT(*)(struct odbc_obj *obj, void *data) | prepare_cb, | |||
void * | data | |||
) |
Prepares, executes, and returns the resulting statement handle.
obj | The ODBC object | |
prepare_cb | A function callback, which, when called, should return a statement handle prepared, with any necessary parameters or result columns bound. | |
data | A parameter to be passed to the prepare_cb parameter function, indicating which statement handle is to be prepared. |
Definition at line 82 of file res_odbc.c.
References ast_log(), ast_tvnow(), 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 393 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().
00394 { 00395 /* For pooled connections, this frees the connection to be 00396 * reused. For non-pooled connections, it does nothing. */ 00397 obj->used = 0; 00398 }
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 405 of file res_odbc.c.
References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_odbc_sanity_check(), ast_tvdiff_ms(), ast_tvnow(), free, odbc_class::idlecheck, odbc_obj::last_used, odbc_class::list, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), odbc_obj::parent, and odbc_obj::used.
Referenced by acf_odbc_read(), acf_odbc_write(), config_odbc(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), and update_odbc().
00406 { 00407 struct odbc_obj *obj = NULL; 00408 struct odbc_class *class; 00409 00410 AST_LIST_LOCK(&odbc_list); 00411 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00412 if (!strcmp(class->name, name)) 00413 break; 00414 } 00415 AST_LIST_UNLOCK(&odbc_list); 00416 00417 if (!class) 00418 return NULL; 00419 00420 AST_LIST_LOCK(&class->odbc_obj); 00421 if (class->haspool) { 00422 /* Recycle connections before building another */ 00423 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00424 if (! obj->used) { 00425 obj->used = 1; 00426 break; 00427 } 00428 } 00429 00430 if (!obj && (class->count < class->limit)) { 00431 class->count++; 00432 obj = ast_calloc(1, sizeof(*obj)); 00433 if (!obj) { 00434 AST_LIST_UNLOCK(&class->odbc_obj); 00435 return NULL; 00436 } 00437 ast_mutex_init(&obj->lock); 00438 obj->parent = class; 00439 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00440 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00441 ast_mutex_destroy(&obj->lock); 00442 free(obj); 00443 obj = NULL; 00444 class->count--; 00445 } else { 00446 obj->used = 1; 00447 AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list); 00448 } 00449 } 00450 } else { 00451 /* Non-pooled connection: multiple modules can use the same connection. */ 00452 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00453 /* Non-pooled connection: if there is an entry, return it */ 00454 break; 00455 } 00456 00457 if (!obj) { 00458 /* No entry: build one */ 00459 obj = ast_calloc(1, sizeof(*obj)); 00460 if (!obj) { 00461 AST_LIST_UNLOCK(&class->odbc_obj); 00462 return NULL; 00463 } 00464 ast_mutex_init(&obj->lock); 00465 obj->parent = class; 00466 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00467 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00468 ast_mutex_destroy(&obj->lock); 00469 free(obj); 00470 obj = NULL; 00471 } else { 00472 AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list); 00473 } 00474 } 00475 } 00476 AST_LIST_UNLOCK(&class->odbc_obj); 00477 00478 if (obj && check) { 00479 ast_odbc_sanity_check(obj); 00480 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_ms(ast_tvnow(), obj->last_used) / 1000 > obj->parent->idlecheck) 00481 odbc_obj_connect(obj); 00482 00483 return obj; 00484 }
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(), ast_tvnow(), 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 732 of file res_odbc.c.
References ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_DECLINE, cli_odbc, load_odbc_config(), and LOG_NOTICE.
00733 { 00734 if(load_odbc_config() == -1) 00735 return AST_MODULE_LOAD_DECLINE; 00736 ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry)); 00737 ast_log(LOG_NOTICE, "res_odbc loaded.\n"); 00738 return 0; 00739 }
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, odbc_class::dsn, enabled, odbc_class::idlecheck, odbc_class::limit, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, odbc_class::password, odbc_class::username, and ast_variable::value.
Referenced by load_module().
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 /* Limit=no probably means "no limit", which is the maximum */ 00256 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); 00257 limit = 1023; 00258 break; 00259 } else if (limit > 1023) { 00260 ast_log(LOG_WARNING, "Maximum limit in 1.4 is 1023. Setting limit to 1023 for ODBC class '%s'.\n", cat); 00261 limit = 1023; 00262 } 00263 } else if (!strcasecmp(v->name, "idlecheck")) { 00264 sscanf(v->value, "%d", &idlecheck); 00265 } else if (!strcasecmp(v->name, "enabled")) { 00266 enabled = ast_true(v->value); 00267 } else if (!strcasecmp(v->name, "pre-connect")) { 00268 connect = ast_true(v->value); 00269 } else if (!strcasecmp(v->name, "dsn")) { 00270 dsn = v->value; 00271 } else if (!strcasecmp(v->name, "username")) { 00272 username = v->value; 00273 } else if (!strcasecmp(v->name, "password")) { 00274 password = v->value; 00275 } else if (!strcasecmp(v->name, "backslash_is_escape")) { 00276 bse = ast_true(v->value); 00277 } 00278 } 00279 00280 if (enabled && !ast_strlen_zero(dsn)) { 00281 new = ast_calloc(1, sizeof(*new)); 00282 00283 if (!new) { 00284 res = -1; 00285 break; 00286 } 00287 00288 if (cat) 00289 ast_copy_string(new->name, cat, sizeof(new->name)); 00290 if (dsn) 00291 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00292 if (username) 00293 ast_copy_string(new->username, username, sizeof(new->username)); 00294 if (password) 00295 ast_copy_string(new->password, password, sizeof(new->password)); 00296 00297 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00298 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00299 00300 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00301 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00302 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00303 return res; 00304 } 00305 00306 if (pooling) { 00307 new->haspool = pooling; 00308 if (limit) { 00309 new->limit = limit; 00310 } else { 00311 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00312 new->limit = 5; 00313 } 00314 } 00315 00316 new->backslash_is_escape = bse ? 1 : 0; 00317 new->idlecheck = idlecheck; 00318 00319 odbc_register_class(new, connect); 00320 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00321 } 00322 } 00323 } 00324 ast_config_destroy(config); 00325 return res; 00326 }
static odbc_status odbc_obj_connect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 521 of file res_odbc.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_tvnow(), odbc_obj::con, odbc_class::dsn, odbc_class::env, odbc_obj::last_used, odbc_obj::lock, LOG_NOTICE, LOG_WARNING, odbc_class::name, ODBC_FAIL, odbc_obj_disconnect(), ODBC_SUCCESS, odbc_obj::parent, odbc_class::password, odbc_obj::up, and odbc_class::username.
Referenced by ast_odbc_prepare_and_execute(), ast_odbc_request_obj(), ast_odbc_sanity_check(), and ast_odbc_smart_execute().
00522 { 00523 int res; 00524 SQLINTEGER err; 00525 short int mlen; 00526 unsigned char msg[200], stat[10]; 00527 #ifdef NEEDTRACE 00528 SQLINTEGER enable = 1; 00529 char *tracefile = "/tmp/odbc.trace"; 00530 #endif 00531 ast_mutex_lock(&obj->lock); 00532 00533 if (obj->up) { 00534 odbc_obj_disconnect(obj); 00535 ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name); 00536 } else { 00537 ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name); 00538 } 00539 00540 res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con); 00541 00542 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00543 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res); 00544 ast_mutex_unlock(&obj->lock); 00545 return ODBC_FAIL; 00546 } 00547 SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); 00548 SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) 10, 0); 00549 #ifdef NEEDTRACE 00550 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); 00551 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); 00552 #endif 00553 00554 res = SQLConnect(obj->con, 00555 (SQLCHAR *) obj->parent->dsn, SQL_NTS, 00556 (SQLCHAR *) obj->parent->username, SQL_NTS, 00557 (SQLCHAR *) obj->parent->password, SQL_NTS); 00558 00559 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00560 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); 00561 ast_mutex_unlock(&obj->lock); 00562 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg); 00563 return ODBC_FAIL; 00564 } else { 00565 ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn); 00566 obj->up = 1; 00567 obj->last_used = ast_tvnow(); 00568 } 00569 00570 ast_mutex_unlock(&obj->lock); 00571 return ODBC_SUCCESS; 00572 }
static odbc_status odbc_obj_disconnect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 486 of file res_odbc.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::con, odbc_class::dsn, odbc_obj::lock, LOG_DEBUG, LOG_WARNING, odbc_class::name, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.
Referenced by ast_odbc_prepare_and_execute(), ast_odbc_sanity_check(), ast_odbc_smart_execute(), and odbc_obj_connect().
00487 { 00488 int res; 00489 SQLINTEGER err; 00490 short int mlen; 00491 unsigned char msg[200], stat[10]; 00492 00493 /* Nothing to disconnect */ 00494 if (!obj->con) { 00495 return ODBC_SUCCESS; 00496 } 00497 00498 ast_mutex_lock(&obj->lock); 00499 00500 res = SQLDisconnect(obj->con); 00501 00502 if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) { 00503 ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn); 00504 } else { 00505 ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn); 00506 } 00507 00508 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == SQL_SUCCESS)) { 00509 obj->con = NULL; 00510 ast_log(LOG_DEBUG, "Database handle deallocated\n"); 00511 } else { 00512 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); 00513 ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg); 00514 } 00515 00516 obj->up = 0; 00517 ast_mutex_unlock(&obj->lock); 00518 return ODBC_SUCCESS; 00519 }
static int odbc_register_class | ( | struct odbc_class * | class, | |
int | connect | |||
) | [static] |
Definition at line 371 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.
00372 { 00373 struct odbc_obj *obj; 00374 if (class) { 00375 AST_LIST_LOCK(&odbc_list); 00376 AST_LIST_INSERT_HEAD(&odbc_list, class, list); 00377 AST_LIST_UNLOCK(&odbc_list); 00378 00379 if (connect) { 00380 /* Request and release builds a connection */ 00381 obj = ast_odbc_request_obj(class->name, 0); 00382 if (obj) 00383 ast_odbc_release_obj(obj); 00384 } 00385 00386 return 0; 00387 } else { 00388 ast_log(LOG_WARNING, "Attempted to register a NULL class?\n"); 00389 return -1; 00390 } 00391 }
static int odbc_show_command | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 328 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.
00329 { 00330 struct odbc_class *class; 00331 struct odbc_obj *current; 00332 00333 AST_LIST_LOCK(&odbc_list); 00334 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00335 if ((argc == 2) || (argc == 3 && !strcmp(argv[2], "all")) || (!strcmp(argv[2], class->name))) { 00336 int count = 0; 00337 ast_cli(fd, "Name: %s\nDSN: %s\n", class->name, class->dsn); 00338 00339 if (class->haspool) { 00340 ast_cli(fd, "Pooled: yes\nLimit: %d\nConnections in use: %d\n", class->limit, class->count); 00341 00342 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00343 ast_cli(fd, " Connection %d: %s\n", ++count, current->used ? "in use" : current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected"); 00344 } 00345 } else { 00346 /* Should only ever be one of these */ 00347 AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) { 00348 ast_cli(fd, "Pooled: no\nConnected: %s\n", current->up && ast_odbc_sanity_check(current) ? "yes" : "no"); 00349 } 00350 } 00351 00352 ast_cli(fd, "\n"); 00353 } 00354 } 00355 AST_LIST_UNLOCK(&odbc_list); 00356 00357 return 0; 00358 }
static int reload | ( | void | ) | [static] |
Definition at line 574 of file res_odbc.c.
References ast_category_browse(), ast_config_load(), ast_false(), AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_log(), ast_true(), ast_variable_browse(), config, enabled, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, and ast_variable::value.
00575 { 00576 static char *cfg = "res_odbc.conf"; 00577 struct ast_config *config; 00578 struct ast_variable *v; 00579 char *cat, *dsn, *username, *password; 00580 int enabled, pooling, limit, bse; 00581 unsigned int idlecheck; 00582 int connect = 0, res = 0; 00583 00584 struct odbc_class *new, *class; 00585 struct odbc_obj *current; 00586 00587 /* First, mark all to be purged */ 00588 AST_LIST_LOCK(&odbc_list); 00589 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00590 class->delme = 1; 00591 } 00592 00593 config = ast_config_load(cfg); 00594 if (config) { 00595 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00596 if (!strcasecmp(cat, "ENV")) { 00597 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00598 setenv(v->name, v->value, 1); 00599 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00600 } 00601 } else { 00602 /* Reset all to defaults for each class of odbc connections */ 00603 dsn = username = password = NULL; 00604 enabled = 1; 00605 connect = idlecheck = 0; 00606 pooling = 0; 00607 limit = 0; 00608 bse = 1; 00609 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00610 if (!strcasecmp(v->name, "pooling")) { 00611 pooling = 1; 00612 } else if (!strcasecmp(v->name, "limit")) { 00613 sscanf(v->value, "%d", &limit); 00614 if (ast_true(v->value) && !limit) { 00615 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); 00616 limit = 1023; 00617 } else if (ast_false(v->value)) { 00618 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); 00619 enabled = 0; 00620 break; 00621 } 00622 } else if (!strcasecmp(v->name, "idlecheck")) { 00623 sscanf(v->value, "%ud", &idlecheck); 00624 } else if (!strcasecmp(v->name, "enabled")) { 00625 enabled = ast_true(v->value); 00626 } else if (!strcasecmp(v->name, "pre-connect")) { 00627 connect = ast_true(v->value); 00628 } else if (!strcasecmp(v->name, "dsn")) { 00629 dsn = v->value; 00630 } else if (!strcasecmp(v->name, "username")) { 00631 username = v->value; 00632 } else if (!strcasecmp(v->name, "password")) { 00633 password = v->value; 00634 } else if (!strcasecmp(v->name, "backslash_is_escape")) { 00635 bse = ast_true(v->value); 00636 } 00637 } 00638 00639 if (enabled && !ast_strlen_zero(dsn)) { 00640 /* First, check the list to see if it already exists */ 00641 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00642 if (!strcmp(class->name, cat)) { 00643 class->delme = 0; 00644 break; 00645 } 00646 } 00647 00648 if (class) { 00649 new = class; 00650 } else { 00651 new = ast_calloc(1, sizeof(*new)); 00652 } 00653 00654 if (!new) { 00655 res = -1; 00656 break; 00657 } 00658 00659 if (cat) 00660 ast_copy_string(new->name, cat, sizeof(new->name)); 00661 if (dsn) 00662 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00663 if (username) 00664 ast_copy_string(new->username, username, sizeof(new->username)); 00665 if (password) 00666 ast_copy_string(new->password, password, sizeof(new->password)); 00667 00668 if (!class) { 00669 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00670 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00671 00672 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00673 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00674 SQLFreeHandle(SQL_HANDLE_ENV, new->env); 00675 AST_LIST_UNLOCK(&odbc_list); 00676 return res; 00677 } 00678 } 00679 00680 if (pooling) { 00681 new->haspool = pooling; 00682 if (limit) { 00683 new->limit = limit; 00684 } else { 00685 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00686 new->limit = 5; 00687 } 00688 } 00689 00690 new->backslash_is_escape = bse; 00691 new->idlecheck = idlecheck; 00692 00693 if (class) { 00694 ast_log(LOG_NOTICE, "Refreshing ODBC class '%s' dsn->[%s]\n", cat, dsn); 00695 } else { 00696 odbc_register_class(new, connect); 00697 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00698 } 00699 } 00700 } 00701 } 00702 ast_config_destroy(config); 00703 } 00704 00705 /* Purge classes that we know can go away (pooled with 0, only) */ 00706 AST_LIST_TRAVERSE_SAFE_BEGIN(&odbc_list, class, list) { 00707 if (class->delme && class->haspool && class->count == 0) { 00708 AST_LIST_TRAVERSE_SAFE_BEGIN(&(class->odbc_obj), current, list) { 00709 AST_LIST_REMOVE_CURRENT(&(class->odbc_obj), list); 00710 odbc_obj_disconnect(current); 00711 ast_mutex_destroy(¤t->lock); 00712 free(current); 00713 } 00714 AST_LIST_TRAVERSE_SAFE_END; 00715 00716 AST_LIST_REMOVE_CURRENT(&odbc_list, list); 00717 free(class); 00718 } 00719 } 00720 AST_LIST_TRAVERSE_SAFE_END; 00721 AST_LIST_UNLOCK(&odbc_list); 00722 00723 return 0; 00724 }
static int unload_module | ( | void | ) | [static] |
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "ODBC Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 745 of file res_odbc.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 745 of file res_odbc.c.
struct ast_cli_entry cli_odbc[] [static] |
Initial value:
{ { { "odbc", "show", NULL }, odbc_show_command, "List ODBC DSN(s)", show_usage }, }
Definition at line 365 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 360 of file res_odbc.c.