674bc09e84d7ec4f4dc045391c56f51b2ba87e0c
[asterisk/asterisk.git] / res / res_odbc.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * res_odbc.c <ODBC resource manager>
9  * Copyright (C) 2004 - 2005 Anthony Minessale II <anthmct@yahoo.com>
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21
22 /*! \file
23  *
24  * \brief ODBC resource manager
25  * 
26  * \author Mark Spencer <markster@digium.com>
27  * \author Anthony Minessale II <anthmct@yahoo.com>
28  *
29  * \arg See also: \ref cdr_odbc
30  */
31
32 /*** MODULEINFO
33         <depend>unixodbc</depend>
34         <depend>ltdl</depend>
35  ***/
36
37 #include "asterisk.h"
38
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40
41 #include "asterisk/file.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/config.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/module.h"
46 #include "asterisk/cli.h"
47 #include "asterisk/lock.h"
48 #include "asterisk/res_odbc.h"
49 #include "asterisk/time.h"
50 #include "asterisk/astobj2.h"
51
52 struct odbc_class
53 {
54         AST_LIST_ENTRY(odbc_class) list;
55         char name[80];
56         char dsn[80];
57         char *username;
58         char *password;
59         char *sanitysql;
60         SQLHENV env;
61         unsigned int haspool:1;              /* Boolean - TDS databases need this */
62         unsigned int delme:1;                /* Purge the class */
63         unsigned int backslash_is_escape:1;  /* On this database, the backslash is a native escape sequence */
64         unsigned int limit;                  /* 1023 wasn't enough for some people */
65         unsigned int count;                  /* Running count of pooled connections */
66         unsigned int idlecheck;              /* Recheck the connection if it is idle for this long */
67         struct ao2_container *obj_container;
68 };
69
70 struct ao2_container *class_container;
71
72 static AST_RWLIST_HEAD_STATIC(odbc_tables, odbc_cache_tables);
73
74 static odbc_status odbc_obj_connect(struct odbc_obj *obj);
75 static odbc_status odbc_obj_disconnect(struct odbc_obj *obj);
76 static int odbc_register_class(struct odbc_class *class, int connect);
77
78 static void odbc_class_destructor(void *data)
79 {
80         struct odbc_class *class = data;
81         /* Due to refcounts, we can safely assume that any objects with a reference
82          * to us will prevent our destruction, so we don't need to worry about them.
83          */
84         if (class->username)
85                 ast_free(class->username);
86         if (class->password)
87                 ast_free(class->password);
88         if (class->sanitysql)
89                 ast_free(class->sanitysql);
90         ao2_ref(class->obj_container, -1);
91         SQLFreeHandle(SQL_HANDLE_ENV, class->env);
92 }
93
94 static int null_hash_fn(const void *obj, const int flags)
95 {
96         return 0;
97 }
98
99 static void odbc_obj_destructor(void *data)
100 {
101         struct odbc_obj *obj = data;
102         odbc_obj_disconnect(obj);
103         ast_mutex_destroy(&obj->lock);
104         ao2_ref(obj->parent, -1);
105 }
106
107 static void destroy_table_cache(struct odbc_cache_tables *table) {
108         struct odbc_cache_columns *col;
109         ast_debug(1, "Destroying table cache for %s\n", table->table);
110         AST_RWLIST_WRLOCK(&table->columns);
111         while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) {
112                 ast_free(col);
113         }
114         AST_RWLIST_UNLOCK(&table->columns);
115         AST_RWLIST_HEAD_DESTROY(&table->columns);
116         ast_free(table);
117 }
118
119 /*!
120  * \brief Find or create an entry describing the table specified.
121  * \param obj An active ODBC handle on which to query the table
122  * \param table Tablename to describe
123  * \retval A structure describing the table layout, or NULL, if the table is not found or another error occurs.
124  * When a structure is returned, the contained columns list will be
125  * rdlock'ed, to ensure that it will be retained in memory.
126  */
127 struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *tablename)
128 {
129         struct odbc_cache_tables *tableptr;
130         struct odbc_cache_columns *entry;
131         char columnname[80];
132         SQLLEN sqlptr;
133         SQLHSTMT stmt = NULL;
134         int res = 0, error = 0, try = 0;
135         struct odbc_obj *obj = ast_odbc_request_obj(database, 0);
136
137         AST_RWLIST_RDLOCK(&odbc_tables);
138         AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) {
139                 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
140                         break;
141                 }
142         }
143         if (tableptr) {
144                 AST_RWLIST_RDLOCK(&tableptr->columns);
145                 AST_RWLIST_UNLOCK(&odbc_tables);
146                 if (obj) {
147                         ast_odbc_release_obj(obj);
148                 }
149                 return tableptr;
150         }
151
152         if (!obj) {
153                 ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
154                 return NULL;
155         }
156
157         /* Table structure not already cached; build it now. */
158         do {
159 retry:
160                 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
161                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
162                         if (try == 0) {
163                                 try = 1;
164                                 ast_odbc_sanity_check(obj);
165                                 goto retry;
166                         }
167                         ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database);
168                         break;
169                 }
170
171                 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS);
172                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
173                         if (try == 0) {
174                                 try = 1;
175                                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
176                                 ast_odbc_sanity_check(obj);
177                                 goto retry;
178                         }
179                         ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database);
180                         break;
181                 }
182
183                 if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) {
184                         ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database);
185                         break;
186                 }
187
188                 tableptr->connection = (char *)tableptr + sizeof(*tableptr);
189                 tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1;
190                 strcpy(tableptr->connection, database); /* SAFE */
191                 strcpy(tableptr->table, tablename); /* SAFE */
192                 AST_RWLIST_HEAD_INIT(&(tableptr->columns));
193
194                 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
195                         SQLGetData(stmt,  4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
196
197                         if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) {
198                                 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database);
199                                 error = 1;
200                                 break;
201                         }
202                         entry->name = (char *)entry + sizeof(*entry);
203                         strcpy(entry->name, columnname);
204
205                         SQLGetData(stmt,  5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
206                         SQLGetData(stmt,  7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
207                         SQLGetData(stmt,  9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
208                         SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
209                         SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
210                         SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
211
212                         /* Specification states that the octenlen should be the maximum number of bytes
213                          * returned in a char or binary column, but it seems that some drivers just set
214                          * it to NULL. (Bad Postgres! No biscuit!) */
215                         if (entry->octetlen == 0) {
216                                 entry->octetlen = entry->size;
217                         }
218
219                         ast_verb(10, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix);
220                         /* Insert column info into column list */
221                         AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
222                 }
223                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
224
225                 AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
226                 AST_RWLIST_RDLOCK(&(tableptr->columns));
227         } while (0);
228
229         AST_RWLIST_UNLOCK(&odbc_tables);
230
231         if (error) {
232                 destroy_table_cache(tableptr);
233                 tableptr = NULL;
234         }
235         if (obj) {
236                 ast_odbc_release_obj(obj);
237         }
238         return tableptr;
239 }
240
241 struct odbc_cache_columns *ast_odbc_find_column(struct odbc_cache_tables *table, const char *colname)
242 {
243         struct odbc_cache_columns *col;
244         AST_RWLIST_TRAVERSE(&table->columns, col, list) {
245                 if (strcasecmp(col->name, colname) == 0) {
246                         return col;
247                 }
248         }
249         return NULL;
250 }
251
252 int ast_odbc_clear_cache(const char *database, const char *tablename)
253 {
254         struct odbc_cache_tables *tableptr;
255
256         AST_RWLIST_WRLOCK(&odbc_tables);
257         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
258                 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
259                         AST_LIST_REMOVE_CURRENT(list);
260                         destroy_table_cache(tableptr);
261                         break;
262                 }
263         }
264         AST_RWLIST_TRAVERSE_SAFE_END
265         AST_RWLIST_UNLOCK(&odbc_tables);
266         return tableptr ? 0 : -1;
267 }
268
269 SQLHSTMT ast_odbc_direct_execute(struct odbc_obj *obj, SQLHSTMT (*exec_cb)(struct odbc_obj *obj, void *data), void *data)
270 {
271         int attempt;
272         SQLHSTMT stmt;
273
274         for (attempt = 0; attempt < 2; attempt++) {
275                 stmt = exec_cb(obj, data);
276
277                 if (stmt) {
278                         break;
279                 } else {
280                         obj->up = 0;
281                         ast_log(LOG_WARNING, "SQL Exec Direct failed.  Attempting a reconnect...\n");
282
283                         odbc_obj_disconnect(obj);
284                         odbc_obj_connect(obj);
285                 }
286         }
287
288         return stmt;
289 }
290
291 SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT (*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
292 {
293         int res = 0, i, attempt;
294         SQLINTEGER nativeerror=0, numfields=0;
295         SQLSMALLINT diagbytes=0;
296         unsigned char state[10], diagnostic[256];
297         SQLHSTMT stmt;
298
299         for (attempt = 0; attempt < 2; attempt++) {
300                 /* This prepare callback may do more than just prepare -- it may also
301                  * bind parameters, bind results, etc.  The real key, here, is that
302                  * when we disconnect, all handles become invalid for most databases.
303                  * We must therefore redo everything when we establish a new
304                  * connection. */
305                 stmt = prepare_cb(obj, data);
306
307                 if (stmt) {
308                         res = SQLExecute(stmt);
309                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
310                                 if (res == SQL_ERROR) {
311                                         SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
312                                         for (i = 0; i < numfields; i++) {
313                                                 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
314                                                 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
315                                                 if (i > 10) {
316                                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
317                                                         break;
318                                                 }
319                                         }
320                                 }
321
322                                 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
323                                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
324                                 stmt = NULL;
325
326                                 obj->up = 0;
327                                 /*
328                                  * While this isn't the best way to try to correct an error, this won't automatically
329                                  * fail when the statement handle invalidates.
330                                  */
331                                 ast_odbc_sanity_check(obj);
332                                 continue;
333                         } else
334                                 obj->last_used = ast_tvnow();
335                         break;
336                 } else if (attempt == 0)
337                         ast_odbc_sanity_check(obj);
338         }
339
340         return stmt;
341 }
342
343 int ast_odbc_smart_execute(struct odbc_obj *obj, SQLHSTMT stmt) 
344 {
345         int res = 0, i;
346         SQLINTEGER nativeerror=0, numfields=0;
347         SQLSMALLINT diagbytes=0;
348         unsigned char state[10], diagnostic[256];
349
350         res = SQLExecute(stmt);
351         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
352                 if (res == SQL_ERROR) {
353                         SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
354                         for (i = 0; i < numfields; i++) {
355                                 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
356                                 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
357                                 if (i > 10) {
358                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
359                                         break;
360                                 }
361                         }
362                 }
363         } else
364                 obj->last_used = ast_tvnow();
365         
366         return res;
367 }
368
369
370 int ast_odbc_sanity_check(struct odbc_obj *obj) 
371 {
372         char *test_sql = "select 1";
373         SQLHSTMT stmt;
374         int res = 0;
375
376         if (!ast_strlen_zero(obj->parent->sanitysql))
377                 test_sql = obj->parent->sanitysql;
378
379         if (obj->up) {
380                 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
381                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
382                         obj->up = 0;
383                 } else {
384                         res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
385                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
386                                 obj->up = 0;
387                         } else {
388                                 res = SQLExecute(stmt);
389                                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
390                                         obj->up = 0;
391                                 }
392                         }
393                 }
394                 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
395         }
396
397         if (!obj->up) { /* Try to reconnect! */
398                 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
399                 odbc_obj_disconnect(obj);
400                 odbc_obj_connect(obj);
401         }
402         return obj->up;
403 }
404
405 static int load_odbc_config(void)
406 {
407         static char *cfg = "res_odbc.conf";
408         struct ast_config *config;
409         struct ast_variable *v;
410         char *cat;
411         const char *dsn, *username, *password, *sanitysql;
412         int enabled, pooling, limit, bse;
413         unsigned int idlecheck;
414         int connect = 0, res = 0;
415         struct ast_flags config_flags = { 0 };
416
417         struct odbc_class *new;
418
419         config = ast_config_load(cfg, config_flags);
420         if (!config) {
421                 ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
422                 return -1;
423         }
424         for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
425                 if (!strcasecmp(cat, "ENV")) {
426                         for (v = ast_variable_browse(config, cat); v; v = v->next) {
427                                 setenv(v->name, v->value, 1);
428                                 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
429                         }
430                 } else {
431                         /* Reset all to defaults for each class of odbc connections */
432                         dsn = username = password = sanitysql = NULL;
433                         enabled = 1;
434                         connect = idlecheck = 0;
435                         pooling = 0;
436                         limit = 0;
437                         bse = 1;
438                         for (v = ast_variable_browse(config, cat); v; v = v->next) {
439                                 if (!strcasecmp(v->name, "pooling")) {
440                                         if (ast_true(v->value))
441                                                 pooling = 1;
442                                 } else if (!strncasecmp(v->name, "share", 5)) {
443                                         /* "shareconnections" is a little clearer in meaning than "pooling" */
444                                         if (ast_false(v->value))
445                                                 pooling = 1;
446                                 } else if (!strcasecmp(v->name, "limit")) {
447                                         sscanf(v->value, "%d", &limit);
448                                         if (ast_true(v->value) && !limit) {
449                                                 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);
450                                                 limit = 1023;
451                                         } else if (ast_false(v->value)) {
452                                                 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'.  Disabling ODBC class '%s'.\n", v->value, cat);
453                                                 enabled = 0;
454                                                 break;
455                                         }
456                                 } else if (!strcasecmp(v->name, "idlecheck")) {
457                                         sscanf(v->value, "%d", &idlecheck);
458                                 } else if (!strcasecmp(v->name, "enabled")) {
459                                         enabled = ast_true(v->value);
460                                 } else if (!strcasecmp(v->name, "pre-connect")) {
461                                         connect = ast_true(v->value);
462                                 } else if (!strcasecmp(v->name, "dsn")) {
463                                         dsn = v->value;
464                                 } else if (!strcasecmp(v->name, "username")) {
465                                         username = v->value;
466                                 } else if (!strcasecmp(v->name, "password")) {
467                                         password = v->value;
468                                 } else if (!strcasecmp(v->name, "sanitysql")) {
469                                         sanitysql = v->value;
470                                 } else if (!strcasecmp(v->name, "backslash_is_escape")) {
471                                         bse = ast_true(v->value);
472                                 }
473                         }
474
475                         if (enabled && !ast_strlen_zero(dsn)) {
476                                 new = ao2_alloc(sizeof(*new), odbc_class_destructor);
477
478                                 if (!new) {
479                                         res = -1;
480                                         break;
481                                 }
482
483                                 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
484                                 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
485
486                                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
487                                         ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
488                                         ao2_ref(new, -1);
489                                         return res;
490                                 }
491
492                                 new->obj_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr);
493
494                                 if (pooling) {
495                                         new->haspool = pooling;
496                                         if (limit) {
497                                                 new->limit = limit;
498                                         } else {
499                                                 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless.  Changing limit from 0 to 5.\n");
500                                                 new->limit = 5;
501                                         }
502                                 }
503
504                                 new->backslash_is_escape = bse ? 1 : 0;
505                                 new->idlecheck = idlecheck;
506
507                                 if (cat)
508                                         ast_copy_string(new->name, cat, sizeof(new->name));
509                                 if (dsn)
510                                         ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
511                                 if (username && !(new->username = ast_strdup(username))) {
512                                         ao2_ref(new, -1);
513                                         break;
514                                 }
515                                 if (password && !(new->password = ast_strdup(password))) {
516                                         ao2_ref(new, -1);
517                                         break;
518                                 }
519                                 if (sanitysql && !(new->sanitysql = ast_strdup(sanitysql))) {
520                                         ao2_ref(new, -1);
521                                         break;
522                                 }
523
524                                 odbc_register_class(new, connect);
525                                 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
526                                 ao2_ref(new, -1);
527                                 new = NULL;
528                         }
529                 }
530         }
531         ast_config_destroy(config);
532         return res;
533 }
534
535 static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
536 {
537         struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
538         struct odbc_class *class;
539         struct odbc_obj *current;
540         int length = 0;
541         int which = 0;
542         char *ret = NULL;
543
544         switch (cmd) {
545         case CLI_INIT:
546                 e->command = "odbc show";
547                 e->usage =
548                                 "Usage: odbc show [class]\n"
549                                 "       List settings of a particular ODBC class or,\n"
550                                 "       if not specified, all classes.\n";
551                 return NULL;
552         case CLI_GENERATE:
553                 if (a->pos != 2)
554                         return NULL;
555                 length = strlen(a->word);
556                 while ((class = ao2_iterator_next(&aoi))) {
557                         if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
558                                 ret = ast_strdup(class->name);
559                                 ao2_ref(class, -1);
560                                 break;
561                         }
562                         ao2_ref(class, -1);
563                 }
564                 if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
565                         ret = ast_strdup("all");
566                 }
567                 return ret;
568         }
569
570         ast_cli(a->fd, "\nODBC DSN Settings\n");
571         ast_cli(a->fd,   "-----------------\n\n");
572         aoi = ao2_iterator_init(class_container, 0);
573         while ((class = ao2_iterator_next(&aoi))) {
574                 if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) {
575                         int count = 0;
576                         ast_cli(a->fd, "  Name:   %s\n  DSN:    %s\n", class->name, class->dsn);
577
578                         if (class->haspool) {
579                                 struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
580
581                                 ast_cli(a->fd, "  Pooled: Yes\n  Limit:  %d\n  Connections in use: %d\n", class->limit, class->count);
582
583                                 while ((current = ao2_iterator_next(&aoi2))) {
584                                         ast_mutex_lock(&current->lock);
585 #ifdef DEBUG_THREADS
586                                         ast_cli(a->fd, "    - Connection %d: %s (%s:%d %s)\n", ++count,
587                                                 current->used ? "in use" :
588                                                 current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected",
589                                                 current->file, current->lineno, current->function);
590 #else
591                                         ast_cli(a->fd, "    - Connection %d: %s\n", ++count,
592                                                 current->used ? "in use" :
593                                                 current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
594 #endif
595                                         ast_mutex_unlock(&current->lock);
596                                         ao2_ref(current, -1);
597                                 }
598                         } else {
599                                 /* Should only ever be one of these */
600                                 struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
601                                 while ((current = ao2_iterator_next(&aoi2))) {
602                                         ast_cli(a->fd, "  Pooled: No\n  Connected: %s\n", current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
603                                         ao2_ref(current, -1);
604                                 }
605                         }
606                         ast_cli(a->fd, "\n");
607                 }
608                 ao2_ref(class, -1);
609         }
610
611         return CLI_SUCCESS;
612 }
613
614 static struct ast_cli_entry cli_odbc[] = {
615         AST_CLI_DEFINE(handle_cli_odbc_show, "List ODBC DSN(s)")
616 };
617
618 static int odbc_register_class(struct odbc_class *class, int connect)
619 {
620         struct odbc_obj *obj;
621         if (class) {
622                 ao2_link(class_container, class);
623                 /* I still have a reference in the caller, so a deref is NOT missing here. */
624
625                 if (connect) {
626                         /* Request and release builds a connection */
627                         obj = ast_odbc_request_obj(class->name, 0);
628                         if (obj)
629                                 ast_odbc_release_obj(obj);
630                 }
631
632                 return 0;
633         } else {
634                 ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
635                 return -1;
636         }
637 }
638
639 void ast_odbc_release_obj(struct odbc_obj *obj)
640 {
641         /* For pooled connections, this frees the connection to be
642          * reused.  For non-pooled connections, it does nothing. */
643         obj->used = 0;
644 #ifdef DEBUG_THREADS
645         obj->file[0] = '\0';
646         obj->function[0] = '\0';
647         obj->lineno = 0;
648 #endif
649         ao2_ref(obj, -1);
650 }
651
652 int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
653 {
654         return obj->parent->backslash_is_escape;
655 }
656
657 #ifdef DEBUG_THREADS
658 struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno)
659 #else
660 struct odbc_obj *ast_odbc_request_obj(const char *name, int check)
661 #endif
662 {
663         struct odbc_obj *obj = NULL;
664         struct odbc_class *class;
665         struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
666
667         while ((class = ao2_iterator_next(&aoi))) {
668                 if (!strcmp(class->name, name) && !class->delme) {
669                         break;
670                 }
671                 ao2_ref(class, -1);
672         }
673
674         if (!class)
675                 return NULL;
676
677         if (class->haspool) {
678                 /* Recycle connections before building another */
679                 aoi = ao2_iterator_init(class->obj_container, 0);
680                 while ((obj = ao2_iterator_next(&aoi))) {
681                         if (! obj->used) {
682                                 ast_mutex_lock(&obj->lock);
683                                 obj->used = 1;
684                                 ast_mutex_unlock(&obj->lock);
685                                 break;
686                         }
687                         ao2_ref(obj, -1);
688                 }
689
690                 if (!obj && (class->count < class->limit)) {
691                         class->count++;
692                         obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
693                         if (!obj) {
694                                 ao2_ref(class, -1);
695                                 return NULL;
696                         }
697                         ast_mutex_init(&obj->lock);
698                         /* obj inherits the outstanding reference to class */
699                         obj->parent = class;
700                         if (odbc_obj_connect(obj) == ODBC_FAIL) {
701                                 ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
702                                 ao2_ref(obj, -1);
703                                 obj = NULL;
704                                 class->count--;
705                         } else {
706                                 obj->used = 1;
707                                 ao2_link(class->obj_container, obj);
708                         }
709                 }
710         } else {
711                 /* Non-pooled connection: multiple modules can use the same connection. */
712                 aoi = ao2_iterator_init(class->obj_container, 0);
713                 while ((obj = ao2_iterator_next(&aoi))) {
714                         /* Non-pooled connection: if there is an entry, return it */
715                         break;
716                 }
717
718                 if (!obj) {
719                         /* No entry: build one */
720                         obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
721                         if (!obj) {
722                                 ao2_ref(class, -1);
723                                 return NULL;
724                         }
725                         ast_mutex_init(&obj->lock);
726                         /* obj inherits the outstanding reference to class */
727                         obj->parent = class;
728                         if (odbc_obj_connect(obj) == ODBC_FAIL) {
729                                 ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
730                                 ao2_ref(obj, -1);
731                                 obj = NULL;
732                         } else {
733                                 ao2_link(class->obj_container, obj);
734                         }
735                 }
736         }
737
738         if (obj && check) {
739                 ast_odbc_sanity_check(obj);
740         } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck)
741                 odbc_obj_connect(obj);
742
743 #if DEBUG_THREADS
744         ast_copy_string(obj->file, file, sizeof(obj->file));
745         ast_copy_string(obj->function, function, sizeof(obj->function));
746         obj->lineno = lineno;
747 #endif
748
749         return obj;
750 }
751
752 static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
753 {
754         int res;
755         ast_mutex_lock(&obj->lock);
756
757         res = SQLDisconnect(obj->con);
758
759         if (res == ODBC_SUCCESS) {
760                 ast_log(LOG_WARNING, "res_odbc: disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
761         } else {
762                 ast_log(LOG_WARNING, "res_odbc: %s [%s] already disconnected\n",
763                 obj->parent->name, obj->parent->dsn);
764         }
765         obj->up = 0;
766         ast_mutex_unlock(&obj->lock);
767         return ODBC_SUCCESS;
768 }
769
770 static odbc_status odbc_obj_connect(struct odbc_obj *obj)
771 {
772         int res;
773         SQLINTEGER err;
774         short int mlen;
775         unsigned char msg[200], stat[10];
776 #ifdef NEEDTRACE
777         SQLINTEGER enable = 1;
778         char *tracefile = "/tmp/odbc.trace";
779 #endif
780         ast_mutex_lock(&obj->lock);
781
782         res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con);
783
784         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
785                 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
786                 ast_mutex_unlock(&obj->lock);
787                 return ODBC_FAIL;
788         }
789         SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
790         SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) 10, 0);
791 #ifdef NEEDTRACE
792         SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
793         SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
794 #endif
795
796         if (obj->up) {
797                 odbc_obj_disconnect(obj);
798                 ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name);
799         } else {
800                 ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
801         }
802
803         res = SQLConnect(obj->con,
804                    (SQLCHAR *) obj->parent->dsn, SQL_NTS,
805                    (SQLCHAR *) obj->parent->username, SQL_NTS,
806                    (SQLCHAR *) obj->parent->password, SQL_NTS);
807
808         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
809                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen);
810                 ast_mutex_unlock(&obj->lock);
811                 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
812                 return ODBC_FAIL;
813         } else {
814                 ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn);
815                 obj->up = 1;
816                 obj->last_used = ast_tvnow();
817         }
818
819         ast_mutex_unlock(&obj->lock);
820         return ODBC_SUCCESS;
821 }
822
823 static int reload(void)
824 {
825         struct odbc_cache_tables *table;
826         struct odbc_class *class;
827         struct odbc_obj *current;
828         struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
829
830         /* First, mark all to be purged */
831         while ((class = ao2_iterator_next(&aoi))) {
832                 class->delme = 1;
833                 ao2_ref(class, -1);
834         }
835
836         load_odbc_config();
837
838         /* Purge remaining classes */
839
840         /* Note on how this works; this is a case of circular references, so we
841          * explicitly do NOT want to use a callback here (or we wind up in
842          * recursive hell).
843          *
844          * 1. Iterate through all the classes.  Note that the classes will currently
845          * contain two classes of the same name, one of which is marked delme and
846          * will be purged when all remaining objects of the class are released, and
847          * the other, which was created above when we re-parsed the config file.
848          * 2. On each class, there is a reference held by the master container and
849          * a reference held by each connection object.  There are two cases for
850          * destruction of the class, noted below.  However, in all cases, all O-refs
851          * (references to objects) will first be freed, which will cause the C-refs
852          * (references to classes) to be decremented (but never to 0, because the
853          * class container still has a reference).
854          *    a) If the class has outstanding objects, the C-ref by the class
855          *    container will then be freed, which leaves only C-refs by any
856          *    outstanding objects.  When the final outstanding object is released
857          *    (O-refs held by applications and dialplan functions), it will in turn
858          *    free the final C-ref, causing class destruction.
859          *    b) If the class has no outstanding objects, when the class container
860          *    removes the final C-ref, the class will be destroyed.
861          */
862         aoi = ao2_iterator_init(class_container, 0);
863         while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */
864                 if (class->delme) {
865                         struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
866                         while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */
867                                 ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */
868                                 ao2_ref(current, -1); /* O-ref-- (by iterator) */
869                                 /* At this point, either
870                                  * a) there's an outstanding O-ref, or
871                                  * b) the object has already been destroyed.
872                                  */
873                         }
874                         ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
875                         /* At this point, either
876                          * a) there's an outstanding O-ref, which holds an outstanding C-ref, or
877                          * b) the last remaining C-ref is held by the iterator, which will be
878                          * destroyed in the next step.
879                          */
880                 }
881                 ao2_ref(class, -1); /* C-ref-- (by iterator) */
882         }
883
884         /* Empty the cache; it will get rebuilt the next time the tables are needed. */
885         AST_RWLIST_WRLOCK(&odbc_tables);
886         while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
887                 destroy_table_cache(table);
888         }
889         AST_RWLIST_UNLOCK(&odbc_tables);
890
891         return 0;
892 }
893
894 static int unload_module(void)
895 {
896         /* Prohibit unloading */
897         return -1;
898 }
899
900 static int load_module(void)
901 {
902         if (!(class_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr)))
903                 return AST_MODULE_LOAD_DECLINE;
904         if (load_odbc_config() == -1)
905                 return AST_MODULE_LOAD_DECLINE;
906         ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry));
907         ast_log(LOG_NOTICE, "res_odbc loaded.\n");
908         return 0;
909 }
910
911 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "ODBC resource",
912                 .load = load_module,
913                 .unload = unload_module,
914                 .reload = reload,
915                );