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