Mon May 14 04:52:37 2007

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 dependency graph for res_odbc.c:

Go to the source code of this file.

Data Structures

struct  odbc_class

Functions

 AST_LIST_HEAD_STATIC (odbc_list, odbc_class)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"ODBC Resource",.load=load_module,.unload=unload_module,.reload=reload,)
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_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

AST_LIST_HEAD_STATIC ( odbc_list  ,
odbc_class   
)

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_GLOBAL_SYMBOLS  ,
"ODBC Resource"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

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 78 of file res_odbc.c.

References ast_log(), LOG_WARNING, odbc_obj_connect(), and odbc_obj_disconnect().

Referenced by acf_odbc_read(), acf_odbc_write(), and config_odbc().

00079 {
00080    int res = 0, i, attempt;
00081    SQLINTEGER nativeerror=0, numfields=0;
00082    SQLSMALLINT diagbytes=0;
00083    unsigned char state[10], diagnostic[256];
00084    SQLHSTMT stmt;
00085 
00086    for (attempt = 0; attempt < 2; attempt++) {
00087       /* This prepare callback may do more than just prepare -- it may also
00088        * bind parameters, bind results, etc.  The real key, here, is that
00089        * when we disconnect, all handles become invalid for most databases.
00090        * We must therefore redo everything when we establish a new
00091        * connection. */
00092       stmt = prepare_cb(obj, data);
00093 
00094       if (stmt) {
00095          res = SQLExecute(stmt);
00096          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00097             if (res == SQL_ERROR) {
00098                SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00099                for (i = 0; i < numfields; i++) {
00100                   SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00101                   ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00102                   if (i > 10) {
00103                      ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00104                      break;
00105                   }
00106                }
00107             }
00108 
00109             ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
00110             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00111             stmt = NULL;
00112 
00113             obj->up = 0;
00114             /*
00115              * While this isn't the best way to try to correct an error, this won't automatically
00116              * fail when the statement handle invalidates.
00117              */
00118             /* XXX Actually, it might, if we're using a non-pooled connection. Possible race here. XXX */
00119             odbc_obj_disconnect(obj);
00120             odbc_obj_connect(obj);
00121             continue;
00122          }
00123          break;
00124       } else {
00125          ast_log(LOG_WARNING, "SQL Prepare failed.  Attempting a reconnect...\n");
00126          odbc_obj_disconnect(obj);
00127          odbc_obj_connect(obj);
00128       }
00129    }
00130 
00131    return stmt;
00132 }

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 374 of file res_odbc.c.

References odbc_obj::used.

Referenced by config_odbc(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), and update_odbc().

00375 {
00376    /* For pooled connections, this frees the connection to be
00377     * reused.  For non-pooled connections, it does nothing. */
00378    obj->used = 0;
00379 }

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 381 of file res_odbc.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_odbc_sanity_check(), free, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), 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().

00382 {
00383    struct odbc_obj *obj = NULL;
00384    struct odbc_class *class;
00385 
00386    AST_LIST_LOCK(&odbc_list);
00387    AST_LIST_TRAVERSE(&odbc_list, class, list) {
00388       if (!strcmp(class->name, name))
00389          break;
00390    }
00391    AST_LIST_UNLOCK(&odbc_list);
00392 
00393    if (!class)
00394       return NULL;
00395 
00396    AST_LIST_LOCK(&class->odbc_obj);
00397    if (class->haspool) {
00398       /* Recycle connections before building another */
00399       AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) {
00400          if (! obj->used) {
00401             obj->used = 1;
00402             break;
00403          }
00404       }
00405 
00406       if (!obj && (class->count < class->limit)) {
00407          class->count++;
00408          obj = ast_calloc(1, sizeof(*obj));
00409          if (!obj) {
00410             AST_LIST_UNLOCK(&class->odbc_obj);
00411             return NULL;
00412          }
00413          ast_mutex_init(&obj->lock);
00414          obj->parent = class;
00415          odbc_obj_connect(obj);
00416          AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list);
00417       }
00418    } else {
00419       /* Non-pooled connection: multiple modules can use the same connection. */
00420       AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) {
00421          /* Non-pooled connection: if there is an entry, return it */
00422          break;
00423       }
00424 
00425       if (!obj) {
00426          /* No entry: build one */
00427          obj = ast_calloc(1, sizeof(*obj));
00428          if (!obj) {
00429             AST_LIST_UNLOCK(&class->odbc_obj);
00430             return NULL;
00431          }
00432          ast_mutex_init(&obj->lock);
00433          obj->parent = class;
00434          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00435             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00436             ast_mutex_destroy(&obj->lock);
00437             free(obj);
00438             obj = NULL;
00439          } else {
00440             AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list);
00441          }
00442       }
00443    }
00444    AST_LIST_UNLOCK(&class->odbc_obj);
00445 
00446    if (obj && check) {
00447       ast_odbc_sanity_check(obj);
00448    }
00449    return obj;
00450 }

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_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 134 of file res_odbc.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::lock, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), and odbc_obj::up.

Referenced by realtime_multi_odbc(), realtime_odbc(), and update_odbc().

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

static int load_module ( void   )  [static]

Definition at line 673 of file res_odbc.c.

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

00674 {
00675    if(load_odbc_config() == -1)
00676       return AST_MODULE_LOAD_DECLINE;
00677    ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry));
00678    ast_log(LOG_NOTICE, "res_odbc loaded.\n");
00679    return 0;
00680 }

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

static odbc_status odbc_obj_connect ( struct odbc_obj obj  )  [static]

Definition at line 470 of file res_odbc.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::con, odbc_obj::lock, LOG_NOTICE, LOG_WARNING, ODBC_FAIL, odbc_obj_disconnect(), ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.

Referenced by ast_odbc_prepare_and_execute(), ast_odbc_request_obj(), ast_odbc_sanity_check(), and ast_odbc_smart_execute().

00471 {
00472    int res;
00473    SQLINTEGER err;
00474    short int mlen;
00475    unsigned char msg[200], stat[10];
00476 #ifdef NEEDTRACE
00477    SQLINTEGER enable = 1;
00478    char *tracefile = "/tmp/odbc.trace";
00479 #endif
00480    ast_mutex_lock(&obj->lock);
00481 
00482    res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con);
00483 
00484    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00485 
00486       ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
00487       SQLFreeHandle(SQL_HANDLE_ENV, obj->parent->env);
00488 
00489       ast_mutex_unlock(&obj->lock);
00490       return ODBC_FAIL;
00491    }
00492    SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
00493 #ifdef NEEDTRACE
00494    SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
00495    SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
00496 #endif
00497 
00498    if (obj->up) {
00499       odbc_obj_disconnect(obj);
00500       ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name);
00501    } else {
00502       ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
00503    }
00504 
00505    res = SQLConnect(obj->con,
00506          (SQLCHAR *) obj->parent->dsn, SQL_NTS,
00507          (SQLCHAR *) obj->parent->username, SQL_NTS,
00508          (SQLCHAR *) obj->parent->password, SQL_NTS);
00509 
00510    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00511       SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen);
00512       ast_mutex_unlock(&obj->lock);
00513       ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
00514       return ODBC_FAIL;
00515    } else {
00516       ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn);
00517       obj->up = 1;
00518    }
00519 
00520    ast_mutex_unlock(&obj->lock);
00521    return ODBC_SUCCESS;
00522 }

static odbc_status odbc_obj_disconnect ( struct odbc_obj obj  )  [static]

Definition at line 452 of file res_odbc.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::con, odbc_obj::lock, LOG_WARNING, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.

Referenced by ast_odbc_prepare_and_execute(), ast_odbc_sanity_check(), ast_odbc_smart_execute(), and odbc_obj_connect().

00453 {
00454    int res;
00455    ast_mutex_lock(&obj->lock);
00456 
00457    res = SQLDisconnect(obj->con);
00458 
00459    if (res == ODBC_SUCCESS) {
00460       ast_log(LOG_WARNING, "res_odbc: disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
00461    } else {
00462       ast_log(LOG_WARNING, "res_odbc: %s [%s] already disconnected\n",
00463       obj->parent->name, obj->parent->dsn);
00464    }
00465    obj->up = 0;
00466    ast_mutex_unlock(&obj->lock);
00467    return ODBC_SUCCESS;
00468 }

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

Definition at line 352 of file res_odbc.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_odbc_release_obj(), ast_odbc_request_obj(), and LOG_WARNING.

00353 {
00354    struct odbc_obj *obj;
00355    if (class) {
00356       AST_LIST_LOCK(&odbc_list);
00357       AST_LIST_INSERT_HEAD(&odbc_list, class, list);
00358       AST_LIST_UNLOCK(&odbc_list);
00359 
00360       if (connect) {
00361          /* Request and release builds a connection */
00362          obj = ast_odbc_request_obj(class->name, 0);
00363          if (obj)
00364             ast_odbc_release_obj(obj);
00365       }
00366 
00367       return 0;
00368    } else {
00369       ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
00370       return -1;
00371    }
00372 }

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

Definition at line 309 of file res_odbc.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_odbc_sanity_check(), and odbc_obj::up.

00310 {
00311    struct odbc_class *class;
00312    struct odbc_obj *current;
00313 
00314    AST_LIST_LOCK(&odbc_list);
00315    AST_LIST_TRAVERSE(&odbc_list, class, list) {
00316       if ((argc == 2) || (argc == 3 && !strcmp(argv[2], "all")) || (!strcmp(argv[2], class->name))) {
00317          int count = 0;
00318          ast_cli(fd, "Name: %s\nDSN: %s\n", class->name, class->dsn);
00319 
00320          if (class->haspool) {
00321             ast_cli(fd, "Pooled: yes\nLimit: %d\nConnections in use: %d\n", class->limit, class->count);
00322 
00323             AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) {
00324                ast_cli(fd, "  Connection %d: %s", ++count, current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
00325             }
00326          } else {
00327             /* Should only ever be one of these */
00328             AST_LIST_TRAVERSE(&(class->odbc_obj), current, list) {
00329                ast_cli(fd, "Pooled: no\nConnected: %s\n", current->up && ast_odbc_sanity_check(current) ? "yes" : "no");
00330             }
00331          }
00332 
00333             ast_cli(fd, "\n");
00334       }
00335    }
00336    AST_LIST_UNLOCK(&odbc_list);
00337 
00338    return 0;
00339 }

static int reload ( void   )  [static]

Definition at line 524 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, setenv(), and ast_variable::value.

00525 {
00526    static char *cfg = "res_odbc.conf";
00527    struct ast_config *config;
00528    struct ast_variable *v;
00529    char *cat, *dsn, *username, *password;
00530    int enabled, pooling, limit;
00531    int connect = 0, res = 0;
00532 
00533    struct odbc_class *new, *class;
00534    struct odbc_obj *current;
00535 
00536    /* First, mark all to be purged */
00537    AST_LIST_LOCK(&odbc_list);
00538    AST_LIST_TRAVERSE(&odbc_list, class, list) {
00539       class->delme = 1;
00540    }
00541 
00542    config = ast_config_load(cfg);
00543    if (config) {
00544       for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
00545          if (!strcasecmp(cat, "ENV")) {
00546             for (v = ast_variable_browse(config, cat); v; v = v->next) {
00547                setenv(v->name, v->value, 1);
00548                ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
00549             }
00550          } else {
00551             /* Reset all to defaults for each class of odbc connections */
00552             dsn = username = password = NULL;
00553             enabled = 1;
00554             connect = 0;
00555             pooling = 0;
00556             limit = 0;
00557             for (v = ast_variable_browse(config, cat); v; v = v->next) {
00558                if (!strcasecmp(v->name, "pooling")) {
00559                   pooling = 1;
00560                } else if (!strcasecmp(v->name, "limit")) {
00561                   sscanf(v->value, "%d", &limit);
00562                   if (ast_true(v->value) && !limit) {
00563                      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);
00564                      limit = 1023;
00565                   } else if (ast_false(v->value)) {
00566                      ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'.  Disabling ODBC class '%s'.\n", v->value, cat);
00567                      enabled = 0;
00568                      break;
00569                   }
00570                } else if (!strcasecmp(v->name, "enabled")) {
00571                   enabled = ast_true(v->value);
00572                } else if (!strcasecmp(v->name, "pre-connect")) {
00573                   connect = ast_true(v->value);
00574                } else if (!strcasecmp(v->name, "dsn")) {
00575                   dsn = v->value;
00576                } else if (!strcasecmp(v->name, "username")) {
00577                   username = v->value;
00578                } else if (!strcasecmp(v->name, "password")) {
00579                   password = v->value;
00580                }
00581             }
00582 
00583             if (enabled && !ast_strlen_zero(dsn)) {
00584                /* First, check the list to see if it already exists */
00585                AST_LIST_TRAVERSE(&odbc_list, class, list) {
00586                   if (!strcmp(class->name, cat)) {
00587                      class->delme = 0;
00588                      break;
00589                   }
00590                }
00591 
00592                if (class) {
00593                   new = class;
00594                } else {
00595                   new = ast_calloc(1, sizeof(*new));
00596                }
00597 
00598                if (!new) {
00599                   res = -1;
00600                   break;
00601                }
00602 
00603                if (cat)
00604                   ast_copy_string(new->name, cat, sizeof(new->name));
00605                if (dsn)
00606                   ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
00607                if (username)
00608                   ast_copy_string(new->username, username, sizeof(new->username));
00609                if (password)
00610                   ast_copy_string(new->password, password, sizeof(new->password));
00611 
00612                if (!class) {
00613                   SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
00614                   res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
00615 
00616                   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00617                      ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
00618                      SQLFreeHandle(SQL_HANDLE_ENV, new->env);
00619                      AST_LIST_UNLOCK(&odbc_list);
00620                      return res;
00621                   }
00622                }
00623 
00624                if (pooling) {
00625                   new->haspool = pooling;
00626                   if (limit) {
00627                      new->limit = limit;
00628                   } else {
00629                      ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless.  Changing limit from 0 to 5.\n");
00630                      new->limit = 5;
00631                   }
00632                }
00633 
00634                if (class) {
00635                   ast_log(LOG_NOTICE, "Refreshing ODBC class '%s' dsn->[%s]\n", cat, dsn);
00636                } else {
00637                   odbc_register_class(new, connect);
00638                   ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
00639                }
00640             }
00641          }
00642       }
00643       ast_config_destroy(config);
00644    }
00645 
00646    /* Purge classes that we know can go away (pooled with 0, only) */
00647    AST_LIST_TRAVERSE_SAFE_BEGIN(&odbc_list, class, list) {
00648       if (class->delme && class->haspool && class->count == 0) {
00649          AST_LIST_TRAVERSE_SAFE_BEGIN(&(class->odbc_obj), current, list) {
00650             AST_LIST_REMOVE_CURRENT(&(class->odbc_obj), list);
00651             odbc_obj_disconnect(current);
00652             ast_mutex_destroy(&current->lock);
00653             free(current);
00654          }
00655          AST_LIST_TRAVERSE_SAFE_END;
00656 
00657          AST_LIST_REMOVE_CURRENT(&odbc_list, list);
00658          free(class);
00659       }
00660    }
00661    AST_LIST_TRAVERSE_SAFE_END;
00662    AST_LIST_UNLOCK(&odbc_list);
00663 
00664    return 0;
00665 }

static int unload_module ( void   )  [static]

Definition at line 667 of file res_odbc.c.

00668 {
00669    /* Prohibit unloading */
00670    return -1;
00671 }


Variable Documentation

struct ast_cli_entry cli_odbc[] [static]

Initial value:

 {
   { { "odbc", "show", NULL },
   odbc_show_command, "List ODBC DSN(s)",
   show_usage },
}

Definition at line 346 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 341 of file res_odbc.c.


Generated on Mon May 14 04:52:38 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1