Thu Oct 8 00:59:49 2009

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 = "6989f2ec67f8497e38c12890500c525b" , .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 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.

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

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_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().

Parameters:
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.

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

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

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.

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 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, "%4d", &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, "%30u", &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, "%4d", &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, "%30u", &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(&current->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]

Definition at line 726 of file res_odbc.c.

00727 {
00728    /* Prohibit unloading */
00729    return -1;
00730 }


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 = "6989f2ec67f8497e38c12890500c525b" , .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.


Generated on Thu Oct 8 00:59:50 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7