Merged revisions 291038 via svnmerge from
[asterisk/asterisk.git] / cdr / cdr_sqlite.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2004 - 2005, Holger Schurig
5  *
6  *
7  * Ideas taken from other cdr_*.c files
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19
20 /*!
21  * \file
22  * \brief Store CDR records in a SQLite database.
23  *
24  * \author Holger Schurig <hs4233@mail.mn-solutions.de>
25  * \extref SQLite http://www.sqlite.org/
26  *
27  * See also
28  * \arg \ref Config_cdr
29  * \arg http://www.sqlite.org/
30  *
31  * Creates the database and table on-the-fly
32  * \ingroup cdr_drivers
33  *
34  * \note This module has been marked deprecated in favor for cdr_sqlite3_custom
35  */
36
37 /*** MODULEINFO
38         <depend>sqlite</depend>
39  ***/
40
41 #include "asterisk.h"
42
43 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
44
45 #include <sqlite.h>
46
47 #include "asterisk/channel.h"
48 #include "asterisk/module.h"
49 #include "asterisk/utils.h"
50 #include "asterisk/paths.h"
51
52 #define LOG_UNIQUEID    0
53 #define LOG_USERFIELD   0
54 #define LOG_HRTIME      0
55
56 /* When you change the DATE_FORMAT, be sure to change the CHAR(19) below to something else */
57 #define DATE_FORMAT "%Y-%m-%d %T"
58
59 static const char name[] = "sqlite";
60 static sqlite* db = NULL;
61
62 AST_MUTEX_DEFINE_STATIC(sqlite_lock);
63
64 /*! \brief SQL table format */
65 static const char sql_create_table[] = "CREATE TABLE cdr ("
66 "       AcctId          INTEGER PRIMARY KEY,"
67 "       clid            VARCHAR(80),"
68 "       src             VARCHAR(80),"
69 "       dst             VARCHAR(80),"
70 "       dcontext        VARCHAR(80),"
71 "       channel         VARCHAR(80),"
72 "       dstchannel      VARCHAR(80),"
73 "       lastapp         VARCHAR(80),"
74 "       lastdata        VARCHAR(80),"
75 "       start           CHAR(19),"
76 "       answer          CHAR(19),"
77 "       end             CHAR(19),"
78 #if LOG_HRTIME
79 "       duration        FLOAT,"
80 "       billsec         FLOAT,"
81 #else
82 "       duration        INTEGER,"
83 "       billsec         INTEGER,"
84 #endif
85 "       disposition     INTEGER,"
86 "       amaflags        INTEGER,"
87 "       accountcode     VARCHAR(20)"
88 #if LOG_UNIQUEID
89 "       ,uniqueid       VARCHAR(32)"
90 #endif
91 #if LOG_USERFIELD
92 "       ,userfield      VARCHAR(255)"
93 #endif
94 ");";
95
96 static void format_date(char *buffer, size_t length, struct timeval *when)
97 {
98         struct ast_tm tm;
99
100         ast_localtime(when, &tm, NULL);
101         ast_strftime(buffer, length, DATE_FORMAT, &tm);
102 }
103
104 static int sqlite_log(struct ast_cdr *cdr)
105 {
106         int res = 0;
107         char *zErr = 0;
108         char startstr[80], answerstr[80], endstr[80];
109         int count;
110 #if LOG_HRTIME
111         double hrbillsec = 0.0;
112         double hrduration;
113 #endif
114
115         ast_mutex_lock(&sqlite_lock);
116
117         format_date(startstr, sizeof(startstr), &cdr->start);
118         format_date(answerstr, sizeof(answerstr), &cdr->answer);
119         format_date(endstr, sizeof(endstr), &cdr->end);
120
121 #if LOG_HRTIME
122         if (!ast_tvzero(cdr->answer)) {
123                 hrbillsec = (double) ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0;
124         }
125         hrduration = (double) ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0;
126 #endif
127
128         for(count=0; count<5; count++) {
129                 res = sqlite_exec_printf(db,
130                         "INSERT INTO cdr ("
131                                 "clid,src,dst,dcontext,"
132                                 "channel,dstchannel,lastapp,lastdata, "
133                                 "start,answer,end,"
134                                 "duration,billsec,disposition,amaflags, "
135                                 "accountcode"
136 #                               if LOG_UNIQUEID
137                                 ",uniqueid"
138 #                               endif
139 #                               if LOG_USERFIELD
140                                 ",userfield"
141 #                               endif
142                         ") VALUES ("
143                                 "'%q', '%q', '%q', '%q', "
144                                 "'%q', '%q', '%q', '%q', "
145                                 "'%q', '%q', '%q', "
146 #if LOG_HRTIME
147                                 "%f, %f, %d, %d, "
148 #else
149                                 "%d, %d, %d, %d, "
150 #endif
151                                 "'%q'"
152 #                               if LOG_UNIQUEID
153                                 ",'%q'"
154 #                               endif
155 #                               if LOG_USERFIELD
156                                 ",'%q'"
157 #                               endif
158                         ")", NULL, NULL, &zErr,
159                                 cdr->clid, cdr->src, cdr->dst, cdr->dcontext,
160                                 cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata,
161                                 startstr, answerstr, endstr,
162 #if LOG_HRTIME
163                                 hrduration, hrbillsec, cdr->disposition, cdr->amaflags,
164 #else
165                                 cdr->duration, cdr->billsec, cdr->disposition, cdr->amaflags,
166 #endif
167                                 cdr->accountcode
168 #                               if LOG_UNIQUEID
169                                 ,cdr->uniqueid
170 #                               endif
171 #                               if LOG_USERFIELD
172                                 ,cdr->userfield
173 #                               endif
174                         );
175                 if (res != SQLITE_BUSY && res != SQLITE_LOCKED)
176                         break;
177                 usleep(200);
178         }
179
180         if (zErr) {
181                 ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr);
182                 ast_free(zErr);
183         }
184
185         ast_mutex_unlock(&sqlite_lock);
186         return res;
187 }
188
189 static int unload_module(void)
190 {
191         if (db)
192                 sqlite_close(db);
193         ast_cdr_unregister(name);
194         return 0;
195 }
196
197 static int load_module(void)
198 {
199         char *zErr;
200         char fn[PATH_MAX];
201         int res;
202
203         ast_log(LOG_WARNING, "This module has been marked deprecated in favor of "
204                 "using cdr_sqlite3_custom. (May be removed after Asterisk 1.6)\n");
205
206         /* is the database there? */
207         snprintf(fn, sizeof(fn), "%s/cdr.db", ast_config_AST_LOG_DIR);
208         db = sqlite_open(fn, AST_FILE_MODE, &zErr);
209         if (!db) {
210                 ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr);
211                 ast_free(zErr);
212                 return AST_MODULE_LOAD_DECLINE;
213         }
214
215         /* is the table there? */
216         res = sqlite_exec(db, "SELECT COUNT(AcctId) FROM cdr;", NULL, NULL, NULL);
217         if (res) {
218                 res = sqlite_exec(db, sql_create_table, NULL, NULL, &zErr);
219                 if (res) {
220                         ast_log(LOG_ERROR, "cdr_sqlite: Unable to create table 'cdr': %s\n", zErr);
221                         ast_free(zErr);
222                         goto err;
223                 }
224
225                 /* TODO: here we should probably create an index */
226         }
227
228         res = ast_cdr_register(name, ast_module_info->description, sqlite_log);
229         if (res) {
230                 ast_log(LOG_ERROR, "Unable to register SQLite CDR handling\n");
231                 return AST_MODULE_LOAD_DECLINE;
232         }
233         return AST_MODULE_LOAD_SUCCESS;
234
235 err:
236         if (db)
237                 sqlite_close(db);
238         return AST_MODULE_LOAD_DECLINE;
239 }
240
241 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SQLite CDR Backend",
242         .load = load_module,
243         .unload = unload_module,
244         .load_pri = AST_MODPRI_CDR_DRIVER,
245 );