Sat Aug 6 00:40:04 2011

Asterisk developer's documentation


res_odbc.c File Reference

ODBC resource manager. More...

#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_objast_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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static const struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_odbc []
static char show_usage []


Detailed Description

ODBC resource manager.

Author:
Mark Spencer <markster@digium.com>

Anthony Minessale II <anthmct@yahoo.com>

Definition in file res_odbc.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 739 of file res_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 739 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.

Parameters:
obj The ODBC object
Returns:
Returns 1 if backslash is a native escape character, 0 if an ESCAPE clause is needed to support '\'

Definition at line 394 of file res_odbc.c.

References odbc_class::backslash_is_escape, and odbc_obj::parent.

Referenced by realtime_multi_odbc(), and realtime_odbc().

00395 {
00396    return obj->parent->backslash_is_escape;
00397 }

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.

Parameters:
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.
Returns:
Returns a statement handle or NULL on error.

Definition at line 82 of file res_odbc.c.

References ast_log(), ast_odbc_sanity_check(), ast_tvnow(), and LOG_WARNING.

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! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn);
00114             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00115             stmt = NULL;
00116 
00117             if (!ast_odbc_sanity_check(obj)) {
00118                break;
00119             }
00120             continue;
00121          } else
00122             obj->last_used = ast_tvnow();
00123          break;
00124       } else {
00125          ast_log(LOG_WARNING, "SQL Prepare failed.  Verifying connection to %s [%s]\n", obj->parent->name, obj->parent->dsn);
00126          ast_odbc_sanity_check(obj);
00127       }
00128    }
00129 
00130    return stmt;
00131 }

void ast_odbc_release_obj ( struct odbc_obj obj  ) 

Releases an ODBC object previously allocated by odbc_request_obj().

Parameters:
obj The ODBC object

Definition at line 387 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().

00388 {
00389    /* For pooled connections, this frees the connection to be
00390     * reused.  For non-pooled connections, it does nothing. */
00391    obj->used = 0;
00392 }

struct odbc_obj* ast_odbc_request_obj ( const char *  name,
int  check 
)

Retrieves a connected ODBC object.

Parameters:
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.
Returns:
Returns an ODBC object or NULL if there is no connection available with the requested name.
Connection classes may, in fact, contain multiple connection handles. If the connection is pooled, then each connection will be dedicated to the thread which requests it. Note that all connections should be released when the thread is done by calling odbc_release_obj(), below.

Definition at line 399 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().

00400 {
00401    struct odbc_obj *obj = NULL;
00402    struct odbc_class *class;
00403 
00404    AST_LIST_LOCK(&odbc_list);
00405    AST_LIST_TRAVERSE(&odbc_list, class, list) {
00406       if (!strcmp(class->name, name))
00407          break;
00408    }
00409    AST_LIST_UNLOCK(&odbc_list);
00410 
00411    if (!class)
00412       return NULL;
00413 
00414    AST_LIST_LOCK(&class->odbc_obj);
00415    if (class->haspool) {
00416       /* Recycle connections before building another */
00417       AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) {
00418          if (! obj->used) {
00419             obj->used = 1;
00420             break;
00421          }
00422       }
00423 
00424       if (!obj && (class->count < class->limit)) {
00425          class->count++;
00426          obj = ast_calloc(1, sizeof(*obj));
00427          if (!obj) {
00428             AST_LIST_UNLOCK(&class->odbc_obj);
00429             return NULL;
00430          }
00431          ast_mutex_init(&obj->lock);
00432          obj->parent = class;
00433          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00434             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00435             ast_mutex_destroy(&obj->lock);
00436             free(obj);
00437             obj = NULL;
00438             class->count--;
00439          } else {
00440             obj->used = 1;
00441             AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list);
00442          }
00443       }
00444    } else {
00445       /* Non-pooled connection: multiple modules can use the same connection. */
00446       AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) {
00447          /* Non-pooled connection: if there is an entry, return it */
00448          break;
00449       }
00450 
00451       if (!obj) {
00452          /* No entry: build one */
00453          obj = ast_calloc(1, sizeof(*obj));
00454          if (!obj) {
00455             AST_LIST_UNLOCK(&class->odbc_obj);
00456             return NULL;
00457          }
00458          ast_mutex_init(&obj->lock);
00459          obj->parent = class;
00460          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00461             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00462             ast_mutex_destroy(&obj->lock);
00463             free(obj);
00464             obj = NULL;
00465          } else {
00466             AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list);
00467          }
00468       }
00469    }
00470    AST_LIST_UNLOCK(&class->odbc_obj);
00471 
00472    if (obj && check) {
00473       ast_odbc_sanity_check(obj);
00474    } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_ms(ast_tvnow(), obj->last_used) / 1000 > obj->parent->idlecheck)
00475       odbc_obj_connect(obj);
00476 
00477    return obj;
00478 }

int ast_odbc_sanity_check ( struct odbc_obj obj  ) 

Checks an ODBC object to ensure it is still connected.

Parameters:
obj The ODBC object
Returns:
Returns 0 if connected, -1 otherwise.

Definition at line 176 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_prepare_and_execute(), ast_odbc_request_obj(), and odbc_show_command().

00177 {
00178    char *test_sql = "select 1";
00179    SQLHSTMT stmt;
00180    int res = 0;
00181 
00182    if (obj->up) {
00183       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00184       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00185          obj->up = 0;
00186       } else {
00187          res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
00188          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00189             obj->up = 0;
00190          } else {
00191             res = SQLExecute(stmt);
00192             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00193                obj->up = 0;
00194             }
00195          }
00196       }
00197       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00198    }
00199 
00200    if (!obj->up) { /* Try to reconnect! */
00201       ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
00202       odbc_obj_disconnect(obj);
00203       odbc_obj_connect(obj);
00204    }
00205    return obj->up;
00206 }

int ast_odbc_smart_execute ( struct odbc_obj obj,
SQLHSTMT  stmt 
)

Executes a prepared statement handle.

Parameters:
obj The non-NULL result of odbc_request_obj()
stmt The prepared statement handle
Returns:
Returns 0 on success or -1 on failure
This function was originally designed simply to execute a prepared statement handle and to retry if the initial execution failed. Unfortunately, it did this by disconnecting and reconnecting the database handle which on most databases causes the statement handle to become invalid. Therefore, this method has been deprecated in favor of odbc_prepare_and_execute() which allows the statement to be prepared multiple times, if necessary, in case of a loss of connection.

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 133 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.

00134 {
00135    int res = 0, i;
00136    SQLINTEGER nativeerror=0, numfields=0;
00137    SQLSMALLINT diagbytes=0;
00138    unsigned char state[10], diagnostic[256];
00139 
00140    res = SQLExecute(stmt);
00141    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00142       if (res == SQL_ERROR) {
00143          SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00144          for (i = 0; i < numfields; i++) {
00145             SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00146             ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00147             if (i > 10) {
00148                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00149                break;
00150             }
00151          }
00152       }
00153 #if 0
00154       /* This is a really bad method of trying to correct a dead connection.  It
00155        * only ever really worked with MySQL.  It will not work with any other
00156        * database, since most databases prepare their statements on the server,
00157        * and if you disconnect, you invalidate the statement handle.  Hence, if
00158        * you disconnect, you're going to fail anyway, whether you try to execute
00159        * a second time or not.
00160        */
00161       ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
00162       ast_mutex_lock(&obj->lock);
00163       obj->up = 0;
00164       ast_mutex_unlock(&obj->lock);
00165       odbc_obj_disconnect(obj);
00166       odbc_obj_connect(obj);
00167       res = SQLExecute(stmt);
00168 #endif
00169    } else
00170       obj->last_used = ast_tvnow();
00171    
00172    return res;
00173 }

static int load_module ( void   )  [static]

Definition at line 726 of file res_odbc.c.

References ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_DECLINE, cli_odbc, load_odbc_config(), and LOG_NOTICE.

00727 {
00728    if(load_odbc_config() == -1)
00729       return AST_MODULE_LOAD_DECLINE;
00730    ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry));
00731    ast_log(LOG_NOTICE, "res_odbc loaded.\n");
00732    return 0;
00733 }

static int load_odbc_config ( void   )  [static]

Definition at line 208 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().

00209 {
00210    static char *cfg = "res_odbc.conf";
00211    struct ast_config *config;
00212    struct ast_variable *v;
00213    char *cat, *dsn, *username, *password;
00214    int enabled, pooling, limit, bse;
00215    unsigned int idlecheck;
00216    int connect = 0, res = 0;
00217 
00218    struct odbc_class *new;
00219 
00220    config = ast_config_load(cfg);
00221    if (!config) {
00222       ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
00223       return -1;
00224    }
00225    for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
00226       if (!strcasecmp(cat, "ENV")) {
00227          for (v = ast_variable_browse(config, cat); v; v = v->next) {
00228             setenv(v->name, v->value, 1);
00229             ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
00230          }
00231       } else {
00232          /* Reset all to defaults for each class of odbc connections */
00233          dsn = username = password = NULL;
00234          enabled = 1;
00235          connect = idlecheck = 0;
00236          pooling = 0;
00237          limit = 0;
00238          bse = 1;
00239          for (v = ast_variable_browse(config, cat); v; v = v->next) {
00240             if (!strcasecmp(v->name, "pooling")) {
00241                if (ast_true(v->value))
00242                   pooling = 1;
00243             } else if (!strcasecmp(v->name, "limit")) {
00244                sscanf(v->value, "%4d", &limit);
00245                if (ast_true(v->value) && !limit) {
00246                   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);
00247                   limit = 1023;
00248                } else if (ast_false(v->value)) {
00249                   /* Limit=no probably means "no limit", which is the maximum */
00250                   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);
00251                   limit = 1023;
00252                   break;
00253                } else if (limit > 1023) {
00254                   ast_log(LOG_WARNING, "Maximum limit in 1.4 is 1023.  Setting limit to 1023 for ODBC class '%s'.\n", cat);
00255                   limit = 1023;
00256                }
00257             } else if (!strcasecmp(v->name, "idlecheck")) {
00258                sscanf(v->value, "%30u", &idlecheck);
00259             } else if (!strcasecmp(v->name, "enabled")) {
00260                enabled = ast_true(v->value);
00261             } else if (!strcasecmp(v->name, "pre-connect")) {
00262                connect = ast_true(v->value);
00263             } else if (!strcasecmp(v->name, "dsn")) {
00264                dsn = v->value;
00265             } else if (!strcasecmp(v->name, "username")) {
00266                username = v->value;
00267             } else if (!strcasecmp(v->name, "password")) {
00268                password = v->value;
00269             } else if (!strcasecmp(v->name, "backslash_is_escape")) {
00270                bse = ast_true(v->value);
00271             }
00272          }
00273 
00274          if (enabled && !ast_strlen_zero(dsn)) {
00275             new = ast_calloc(1, sizeof(*new));
00276 
00277             if (!new) {
00278                res = -1;
00279                break;
00280             }
00281 
00282             if (cat)
00283                ast_copy_string(new->name, cat, sizeof(new->name));
00284             if (dsn)
00285                ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
00286             if (username)
00287                ast_copy_string(new->username, username, sizeof(new->username));
00288             if (password)
00289                ast_copy_string(new->password, password, sizeof(new->password));
00290 
00291             SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
00292             res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
00293 
00294             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00295                ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
00296                SQLFreeHandle(SQL_HANDLE_ENV, new->env);
00297                return res;
00298             }
00299 
00300             if (pooling) {
00301                new->haspool = pooling;
00302                if (limit) {
00303                   new->limit = limit;
00304                } else {
00305                   ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless.  Changing limit from 0 to 5.\n");
00306                   new->limit = 5;
00307                }
00308             }
00309 
00310             new->backslash_is_escape = bse ? 1 : 0;
00311             new->idlecheck = idlecheck;
00312 
00313             odbc_register_class(new, connect);
00314             ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
00315          }
00316       }
00317    }
00318    ast_config_destroy(config);
00319    return res;
00320 }

static odbc_status odbc_obj_connect ( struct odbc_obj obj  )  [static]

Definition at line 515 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_request_obj(), ast_odbc_sanity_check(), and ast_odbc_smart_execute().

00516 {
00517    int res;
00518    SQLINTEGER err;
00519    short int mlen;
00520    unsigned char msg[200], stat[10];
00521 #ifdef NEEDTRACE
00522    SQLINTEGER enable = 1;
00523    char *tracefile = "/tmp/odbc.trace";
00524 #endif
00525    ast_mutex_lock(&obj->lock);
00526 
00527    if (obj->up) {
00528       odbc_obj_disconnect(obj);
00529       ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name);
00530    } else {
00531       ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
00532    }
00533 
00534    res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con);
00535 
00536    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00537       ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
00538       ast_mutex_unlock(&obj->lock);
00539       return ODBC_FAIL;
00540    }
00541    SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
00542    SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) 10, 0);
00543 #ifdef NEEDTRACE
00544    SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
00545    SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
00546 #endif
00547 
00548    res = SQLConnect(obj->con,
00549          (SQLCHAR *) obj->parent->dsn, SQL_NTS,
00550          (SQLCHAR *) obj->parent->username, SQL_NTS,
00551          (SQLCHAR *) obj->parent->password, SQL_NTS);
00552 
00553    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00554       SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen);
00555       ast_mutex_unlock(&obj->lock);
00556       ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
00557       return ODBC_FAIL;
00558    } else {
00559       ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn);
00560       obj->up = 1;
00561       obj->last_used = ast_tvnow();
00562    }
00563 
00564    ast_mutex_unlock(&obj->lock);
00565    return ODBC_SUCCESS;
00566 }

static odbc_status odbc_obj_disconnect ( struct odbc_obj obj  )  [static]

Definition at line 480 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_sanity_check(), ast_odbc_smart_execute(), and odbc_obj_connect().

00481 {
00482    int res;
00483    SQLINTEGER err;
00484    short int mlen;
00485    unsigned char msg[200], stat[10];
00486 
00487    /* Nothing to disconnect */
00488    if (!obj->con) {
00489       return ODBC_SUCCESS;
00490    }
00491 
00492    ast_mutex_lock(&obj->lock);
00493 
00494    res = SQLDisconnect(obj->con);
00495 
00496    if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
00497       ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
00498    } else {
00499       ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn);
00500    }
00501 
00502    if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == SQL_SUCCESS)) {
00503       obj->con = NULL;
00504       ast_log(LOG_DEBUG, "Database handle deallocated\n");
00505    } else {
00506       SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen);
00507       ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg);
00508    }
00509 
00510    obj->up = 0;
00511    ast_mutex_unlock(&obj->lock);
00512    return ODBC_SUCCESS;
00513 }

static int odbc_register_class ( struct odbc_class class,
int  connect 
) [static]

Definition at line 365 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.

00366 {
00367    struct odbc_obj *obj;
00368    if (class) {
00369       AST_LIST_LOCK(&odbc_list);
00370       AST_LIST_INSERT_HEAD(&odbc_list, class, list);
00371       AST_LIST_UNLOCK(&odbc_list);
00372 
00373       if (connect) {
00374          /* Request and release builds a connection */
00375          obj = ast_odbc_request_obj(class->name, 0);
00376          if (obj)
00377             ast_odbc_release_obj(obj);
00378       }
00379 
00380       return 0;
00381    } else {
00382       ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
00383       return -1;
00384    }
00385 }

static int odbc_show_command ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 322 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.

00323 {
00324    struct odbc_class *class;
00325    struct odbc_obj *current;
00326 
00327    AST_LIST_LOCK(&odbc_list);
00328    AST_LIST_TRAVERSE(&odbc_list, class, list) {
00329       if ((argc == 2) || (argc == 3 && !strcmp(argv[2], "all")) || (!strcmp(argv[2], class->name))) {
00330          int count = 0;
00331          ast_cli(fd, "Name: %s\nDSN: %s\n", class->name, class->dsn);
00332 
00333          if (class->haspool) {
00334             ast_cli(fd, "Pooled: yes\nLimit: %d\nConnections in use: %d\n", class->limit, class->count);
00335 
00336             AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) {
00337                ast_cli(fd, "  Connection %d: %s\n", ++count, current->used ? "in use" : current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
00338             }
00339          } else {
00340             /* Should only ever be one of these */
00341             AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) {
00342                ast_cli(fd, "Pooled: no\nConnected: %s\n", current->up && ast_odbc_sanity_check(current) ? "yes" : "no");
00343             }
00344          }
00345 
00346             ast_cli(fd, "\n");
00347       }
00348    }
00349    AST_LIST_UNLOCK(&odbc_list);
00350 
00351    return 0;
00352 }

static int reload ( void   )  [static]

Definition at line 568 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.

00569 {
00570    static char *cfg = "res_odbc.conf";
00571    struct ast_config *config;
00572    struct ast_variable *v;
00573    char *cat, *dsn, *username, *password;
00574    int enabled, pooling, limit, bse;
00575    unsigned int idlecheck;
00576    int connect = 0, res = 0;
00577 
00578    struct odbc_class *new, *class;
00579    struct odbc_obj *current;
00580 
00581    /* First, mark all to be purged */
00582    AST_LIST_LOCK(&odbc_list);
00583    AST_LIST_TRAVERSE(&odbc_list, class, list) {
00584       class->delme = 1;
00585    }
00586 
00587    config = ast_config_load(cfg);
00588    if (config) {
00589       for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
00590          if (!strcasecmp(cat, "ENV")) {
00591             for (v = ast_variable_browse(config, cat); v; v = v->next) {
00592                setenv(v->name, v->value, 1);
00593                ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
00594             }
00595          } else {
00596             /* Reset all to defaults for each class of odbc connections */
00597             dsn = username = password = NULL;
00598             enabled = 1;
00599             connect = idlecheck = 0;
00600             pooling = 0;
00601             limit = 0;
00602             bse = 1;
00603             for (v = ast_variable_browse(config, cat); v; v = v->next) {
00604                if (!strcasecmp(v->name, "pooling")) {
00605                   pooling = 1;
00606                } else if (!strcasecmp(v->name, "limit")) {
00607                   sscanf(v->value, "%4d", &limit);
00608                   if (ast_true(v->value) && !limit) {
00609                      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);
00610                      limit = 1023;
00611                   } else if (ast_false(v->value)) {
00612                      ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'.  Disabling ODBC class '%s'.\n", v->value, cat);
00613                      enabled = 0;
00614                      break;
00615                   }
00616                } else if (!strcasecmp(v->name, "idlecheck")) {
00617                   sscanf(v->value, "%30u", &idlecheck);
00618                } else if (!strcasecmp(v->name, "enabled")) {
00619                   enabled = ast_true(v->value);
00620                } else if (!strcasecmp(v->name, "pre-connect")) {
00621                   connect = ast_true(v->value);
00622                } else if (!strcasecmp(v->name, "dsn")) {
00623                   dsn = v->value;
00624                } else if (!strcasecmp(v->name, "username")) {
00625                   username = v->value;
00626                } else if (!strcasecmp(v->name, "password")) {
00627                   password = v->value;
00628                } else if (!strcasecmp(v->name, "backslash_is_escape")) {
00629                   bse = ast_true(v->value);
00630                }
00631             }
00632 
00633             if (enabled && !ast_strlen_zero(dsn)) {
00634                /* First, check the list to see if it already exists */
00635                AST_LIST_TRAVERSE(&odbc_list, class, list) {
00636                   if (!strcmp(class->name, cat)) {
00637                      class->delme = 0;
00638                      break;
00639                   }
00640                }
00641 
00642                if (class) {
00643                   new = class;
00644                } else {
00645                   new = ast_calloc(1, sizeof(*new));
00646                }
00647 
00648                if (!new) {
00649                   res = -1;
00650                   break;
00651                }
00652 
00653                if (cat)
00654                   ast_copy_string(new->name, cat, sizeof(new->name));
00655                if (dsn)
00656                   ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
00657                if (username)
00658                   ast_copy_string(new->username, username, sizeof(new->username));
00659                if (password)
00660                   ast_copy_string(new->password, password, sizeof(new->password));
00661 
00662                if (!class) {
00663                   SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
00664                   res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
00665 
00666                   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00667                      ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
00668                      SQLFreeHandle(SQL_HANDLE_ENV, new->env);
00669                      AST_LIST_UNLOCK(&odbc_list);
00670                      return res;
00671                   }
00672                }
00673 
00674                if (pooling) {
00675                   new->haspool = pooling;
00676                   if (limit) {
00677                      new->limit = limit;
00678                   } else {
00679                      ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless.  Changing limit from 0 to 5.\n");
00680                      new->limit = 5;
00681                   }
00682                }
00683 
00684                new->backslash_is_escape = bse;
00685                new->idlecheck = idlecheck;
00686 
00687                if (class) {
00688                   ast_log(LOG_NOTICE, "Refreshing ODBC class '%s' dsn->[%s]\n", cat, dsn);
00689                } else {
00690                   odbc_register_class(new, connect);
00691                   ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
00692                }
00693             }
00694          }
00695       }
00696       ast_config_destroy(config);
00697    }
00698 
00699    /* Purge classes that we know can go away (pooled with 0, only) */
00700    AST_LIST_TRAVERSE_SAFE_BEGIN(&odbc_list, class, list) {
00701       if (class->delme && class->haspool && class->count == 0) {
00702          AST_LIST_TRAVERSE_SAFE_BEGIN(&(class->odbc_obj), current, list) {
00703             AST_LIST_REMOVE_CURRENT(&(class->odbc_obj), list);
00704             odbc_obj_disconnect(current);
00705             ast_mutex_destroy(&current->lock);
00706             free(current);
00707          }
00708          AST_LIST_TRAVERSE_SAFE_END;
00709 
00710          AST_LIST_REMOVE_CURRENT(&odbc_list, list);
00711          free(class);
00712       }
00713    }
00714    AST_LIST_TRAVERSE_SAFE_END;
00715    AST_LIST_UNLOCK(&odbc_list);
00716 
00717    return 0;
00718 }

static int unload_module ( void   )  [static]

Definition at line 720 of file res_odbc.c.

00721 {
00722    /* Prohibit unloading */
00723    return -1;
00724 }


Variable Documentation

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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 739 of file res_odbc.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 739 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 359 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 354 of file res_odbc.c.


Generated on Sat Aug 6 00:40:04 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7