source:
freewrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch@
428f140
| Last change on this file since 428f140 was 475ad56, checked in by , 20 years ago | |
|---|---|
|
|
| File size: 16.9 KB | |
-
configs/cdr_mysql.conf.sample
diff -ruN asterisk-1.2.0-old/configs/cdr_mysql.conf.sample asterisk-1.2.0-new/configs/cdr_mysql.conf.sample
old new 1 ; 2 ; Note - if the database server is hosted on the same machine as the 3 ; asterisk server, you can achieve a local Unix socket connection by 4 ; setting hostname=localhost 5 ; 6 ; port and sock are both optional parameters. If hostname is specified 7 ; and is not "localhost", then cdr_mysql will attempt to connect to the 8 ; port specified or use the default port. If hostname is not specified 9 ; or if hostname is "localhost", then cdr_mysql will attempt to connect 10 ; to the socket file specified by sock or otherwise use the default socket 11 ; file. 12 ; 13 ;[global] 14 ;hostname=database.host.name 15 ;dbname=asteriskcdrdb 16 ;table=cdr 17 ;password=password 18 ;user=asteriskcdruser 19 ;port=3306 20 ;sock=/tmp/mysql.sock 21 ;userfield=1 -
cdr/cdr_mysql.c
diff -ruN asterisk-1.2.0-old/cdr/cdr_mysql.c asterisk-1.2.0-new/cdr/cdr_mysql.c
old new 1 /* 2 * Asterisk -- A telephony toolkit for Linux. 3 * 4 * MySQL CDR logger 5 * 6 * James Sharp <jsharp@psychoses.org> 7 * 8 * Modified August 2003 9 * Tilghman Lesher <asterisk__cdr__cdr_mysql__200308@the-tilghman.com> 10 * 11 * Modified August 6, 2005 12 * Joseph Benden <joe@thrallingpenguin.com> 13 * Added mysql connection timeout parameter 14 * Added an automatic reconnect as to not lose a cdr record 15 * Cleaned up the original code to match the coding guidelines 16 * 17 * This program is free software, distributed under the terms of 18 * the GNU General Public License. 19 * 20 */ 21 22 #include <sys/types.h> 23 24 #include <stdio.h> 25 #include <string.h> 26 27 #include <stdlib.h> 28 #include <unistd.h> 29 #include <time.h> 30 31 #include <mysql.h> 32 #include <errmsg.h> 33 34 #include <sys/stat.h> 35 #include <sys/types.h> 36 #include <errno.h> 37 38 #include <asterisk/config.h> 39 #include <asterisk/options.h> 40 #include <asterisk/channel.h> 41 #include <asterisk/cdr.h> 42 #include <asterisk/module.h> 43 #include <asterisk/logger.h> 44 #include <asterisk/cli.h> 45 46 #define DATE_FORMAT "%Y-%m-%d %T" 47 48 static char *desc = "MySQL CDR Backend"; 49 static char *name = "mysql"; 50 static char *config = "cdr_mysql.conf"; 51 static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *dbsock = NULL, *dbtable = NULL; 52 static int hostname_alloc = 0, dbname_alloc = 0, dbuser_alloc = 0, password_alloc = 0, dbsock_alloc = 0, dbtable_alloc = 0; 53 static int dbport = 0; 54 static int connected = 0; 55 static time_t connect_time = 0; 56 static int records = 0; 57 static int totalrecords = 0; 58 static int userfield = 0; 59 static unsigned int timeout = 0; 60 61 AST_MUTEX_DEFINE_STATIC(mysql_lock); 62 63 static MYSQL mysql; 64 65 static char cdr_mysql_status_help[] = 66 "Usage: cdr mysql status\n" 67 " Shows current connection status for cdr_mysql\n"; 68 69 static int handle_cdr_mysql_status(int fd, int argc, char *argv[]) 70 { 71 if (connected) { 72 char status[256], status2[100] = ""; 73 int ctime = time(NULL) - connect_time; 74 if (dbport) 75 snprintf(status, 255, "Connected to %s@%s, port %d", dbname, hostname, dbport); 76 else if (dbsock) 77 snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock); 78 else 79 snprintf(status, 255, "Connected to %s@%s", dbname, hostname); 80 81 if (dbuser && *dbuser) 82 snprintf(status2, 99, " with username %s", dbuser); 83 if (dbtable && *dbtable) 84 snprintf(status2, 99, " using table %s", dbtable); 85 if (ctime > 31536000) { 86 ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60); 87 } else if (ctime > 86400) { 88 ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60); 89 } else if (ctime > 3600) { 90 ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60); 91 } else if (ctime > 60) { 92 ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60); 93 } else { 94 ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime); 95 } 96 if (records == totalrecords) 97 ast_cli(fd, " Wrote %d records since last restart.\n", totalrecords); 98 else 99 ast_cli(fd, " Wrote %d records since last restart and %d records since last reconnect.\n", totalrecords, records); 100 return RESULT_SUCCESS; 101 } else { 102 ast_cli(fd, "Not currently connected to a MySQL server.\n"); 103 return RESULT_FAILURE; 104 } 105 } 106 107 static struct ast_cli_entry cdr_mysql_status_cli = 108 { { "cdr", "mysql", "status", NULL }, 109 handle_cdr_mysql_status, "Show connection status of cdr_mysql", 110 cdr_mysql_status_help, NULL }; 111 112 static int mysql_log(struct ast_cdr *cdr) 113 { 114 struct tm tm; 115 struct timeval tv; 116 struct localuser *u; 117 char *userfielddata = NULL; 118 char sqlcmd[2048], timestr[128]; 119 char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL; 120 int retries = 5; 121 #ifdef MYSQL_LOGUNIQUEID 122 char *uniqueid = NULL; 123 #endif 124 125 ast_mutex_lock(&mysql_lock); 126 127 memset(sqlcmd, 0, 2048); 128 129 localtime_r(&cdr->start.tv_sec, &tm); 130 strftime(timestr, 128, DATE_FORMAT, &tm); 131 132 db_reconnect: 133 if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) { 134 /* Attempt to connect */ 135 mysql_init(&mysql); 136 /* Add option to quickly timeout the connection */ 137 if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) { 138 ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); 139 } 140 if (mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) { 141 connected = 1; 142 connect_time = time(NULL); 143 records = 0; 144 } else { 145 ast_log(LOG_ERROR, "cdr_mysql: cannot connect to database server %s.\n", hostname); 146 connected = 0; 147 } 148 } else { 149 /* Long connection - ping the server */ 150 int error; 151 if ((error = mysql_ping(&mysql))) { 152 connected = 0; 153 records = 0; 154 switch (error) { 155 case CR_SERVER_GONE_ERROR: 156 case CR_SERVER_LOST: 157 ast_log(LOG_ERROR, "cdr_mysql: Server has gone away. Attempting to reconnect.\n"); 158 break; 159 default: 160 ast_log(LOG_ERROR, "cdr_mysql: Unknown connection error: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); 161 } 162 retries--; 163 if (retries) 164 goto db_reconnect; 165 else 166 ast_log(LOG_ERROR, "cdr_mysql: Retried to connect fives times, giving up.\n"); 167 } 168 } 169 170 /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */ 171 /* WARNING: This code previously used mysql_real_escape_string, but the use of said function 172 requires an active connection to a database. If we are not connected, then this function 173 cannot be used. This is a problem since we need to store off the SQL statement into our 174 spool file for later restoration. 175 So the question is, what's the best way to handle this? This works for now. 176 */ 177 if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL) 178 mysql_escape_string(clid, cdr->clid, strlen(cdr->clid)); 179 if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL) 180 mysql_escape_string(dcontext, cdr->dcontext, strlen(cdr->dcontext)); 181 if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL) 182 mysql_escape_string(channel, cdr->channel, strlen(cdr->channel)); 183 if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL) 184 mysql_escape_string(dstchannel, cdr->dstchannel, strlen(cdr->dstchannel)); 185 if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL) 186 mysql_escape_string(lastapp, cdr->lastapp, strlen(cdr->lastapp)); 187 if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL) 188 mysql_escape_string(lastdata, cdr->lastdata, strlen(cdr->lastdata)); 189 #ifdef MYSQL_LOGUNIQUEID 190 if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL) 191 mysql_escape_string(uniqueid, cdr->uniqueid, strlen(cdr->uniqueid)); 192 #endif 193 if (userfield && ((userfielddata = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL)) 194 mysql_escape_string(userfielddata, cdr->userfield, strlen(cdr->userfield)); 195 196 /* Check for all alloca failures above at once */ 197 #ifdef MYSQL_LOGUNIQUEID 198 if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid)) { 199 #else 200 if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata)) { 201 #endif 202 ast_log(LOG_ERROR, "cdr_mysql: Out of memory error (insert fails)\n"); 203 ast_mutex_unlock(&mysql_lock); 204 return -1; 205 } 206 207 ast_log(LOG_DEBUG, "cdr_mysql: inserting a CDR record.\n"); 208 209 if (userfield && userfielddata) { 210 #ifdef MYSQL_LOGUNIQUEID 211 sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s','%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext, channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode, uniqueid, userfielddata); 212 #else 213 sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,userfield) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode, userfielddata); 214 #endif 215 } else { 216 #ifdef MYSQL_LOGUNIQUEID 217 sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode, uniqueid); 218 #else 219 sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext, channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode); 220 #endif 221 } 222 223 ast_log(LOG_DEBUG, "cdr_mysql: SQL command as follows: %s\n", sqlcmd); 224 225 if (connected) { 226 if (mysql_real_query(&mysql, sqlcmd, strlen(sqlcmd))) { 227 ast_log(LOG_ERROR, "mysql_cdr: Failed to insert into database: (%d) %s", mysql_errno(&mysql), mysql_error(&mysql)); 228 connected = 0; 229 } else { 230 records++; 231 totalrecords++; 232 } 233 } 234 ast_mutex_unlock(&mysql_lock); 235 return 0; 236 } 237 238 char *description(void) 239 { 240 return desc; 241 } 242 243 static int my_unload_module(void) 244 { 245 ast_cli_unregister(&cdr_mysql_status_cli); 246 if (connected) { 247 mysql_close(&mysql); 248 connected = 0; 249 records = 0; 250 } 251 if (hostname && hostname_alloc) { 252 free(hostname); 253 hostname = NULL; 254 hostname_alloc = 0; 255 } 256 if (dbname && dbname_alloc) { 257 free(dbname); 258 dbname = NULL; 259 dbname_alloc = 0; 260 } 261 if (dbuser && dbuser_alloc) { 262 free(dbuser); 263 dbuser = NULL; 264 dbuser_alloc = 0; 265 } 266 if (dbsock && dbsock_alloc) { 267 free(dbsock); 268 dbsock = NULL; 269 dbsock_alloc = 0; 270 } 271 if (dbtable && dbtable_alloc) { 272 free(dbtable); 273 dbtable = NULL; 274 dbtable_alloc = 0; 275 } 276 if (password && password_alloc) { 277 free(password); 278 password = NULL; 279 password_alloc = 0; 280 } 281 dbport = 0; 282 ast_cdr_unregister(name); 283 return 0; 284 } 285 286 static int my_load_module(void) 287 { 288 int res; 289 struct ast_config *cfg; 290 struct ast_variable *var; 291 char *tmp; 292 293 cfg = ast_config_load(config); 294 if (!cfg) { 295 ast_log(LOG_WARNING, "Unable to load config for mysql CDR's: %s\n", config); 296 return 0; 297 } 298 299 var = ast_variable_browse(cfg, "global"); 300 if (!var) { 301 /* nothing configured */ 302 return 0; 303 } 304 305 tmp = ast_variable_retrieve(cfg, "global", "hostname"); 306 if (tmp) { 307 hostname = malloc(strlen(tmp) + 1); 308 if (hostname != NULL) { 309 hostname_alloc = 1; 310 strcpy(hostname, tmp); 311 } else { 312 ast_log(LOG_ERROR, "Out of memory error.\n"); 313 return -1; 314 } 315 } else { 316 ast_log(LOG_WARNING, "MySQL server hostname not specified. Assuming localhost\n"); 317 hostname = "localhost"; 318 } 319 320 tmp = ast_variable_retrieve(cfg, "global", "dbname"); 321 if (tmp) { 322 dbname = malloc(strlen(tmp) + 1); 323 if (dbname != NULL) { 324 dbname_alloc = 1; 325 strcpy(dbname, tmp); 326 } else { 327 ast_log(LOG_ERROR, "Out of memory error.\n"); 328 return -1; 329 } 330 } else { 331 ast_log(LOG_WARNING, "MySQL database not specified. Assuming asteriskcdrdb\n"); 332 dbname = "asteriskcdrdb"; 333 } 334 335 tmp = ast_variable_retrieve(cfg, "global", "user"); 336 if (tmp) { 337 dbuser = malloc(strlen(tmp) + 1); 338 if (dbuser != NULL) { 339 dbuser_alloc = 1; 340 strcpy(dbuser, tmp); 341 } else { 342 ast_log(LOG_ERROR, "Out of memory error.\n"); 343 return -1; 344 } 345 } else { 346 ast_log(LOG_WARNING, "MySQL database user not specified. Assuming root\n"); 347 dbuser = "root"; 348 } 349 350 tmp = ast_variable_retrieve(cfg, "global", "sock"); 351 if (tmp) { 352 dbsock = malloc(strlen(tmp) + 1); 353 if (dbsock != NULL) { 354 dbsock_alloc = 1; 355 strcpy(dbsock, tmp); 356 } else { 357 ast_log(LOG_ERROR, "Out of memory error.\n"); 358 return -1; 359 } 360 } else { 361 ast_log(LOG_WARNING, "MySQL database sock file not specified. Using default\n"); 362 dbsock = NULL; 363 } 364 365 tmp = ast_variable_retrieve(cfg, "global", "table"); 366 if (tmp) { 367 dbtable = malloc(strlen(tmp) + 1); 368 if (dbtable != NULL) { 369 dbtable_alloc = 1; 370 strcpy(dbtable, tmp); 371 } else { 372 ast_log(LOG_ERROR, "Out of memory error.\n"); 373 return -1; 374 } 375 } else { 376 ast_log(LOG_NOTICE, "MySQL database table not specified. Assuming \"cdr\"\n"); 377 dbtable = "cdr"; 378 } 379 380 tmp = ast_variable_retrieve(cfg, "global", "password"); 381 if (tmp) { 382 password = malloc(strlen(tmp) + 1); 383 if (password != NULL) { 384 password_alloc = 1; 385 strcpy(password, tmp); 386 } else { 387 ast_log(LOG_ERROR, "Out of memory error.\n"); 388 return -1; 389 } 390 } else { 391 ast_log(LOG_WARNING, "MySQL database password not specified. Assuming blank\n"); 392 password = ""; 393 } 394 395 tmp = ast_variable_retrieve(cfg, "global", "port"); 396 if (tmp) { 397 if (sscanf(tmp, "%d", &dbport) < 1) { 398 ast_log(LOG_WARNING, "Invalid MySQL port number. Using default\n"); 399 dbport = 0; 400 } 401 } 402 403 tmp = ast_variable_retrieve(cfg, "global", "timeout"); 404 if (tmp) { 405 if (sscanf(tmp,"%d", &timeout) < 1) { 406 ast_log(LOG_WARNING, "Invalid MySQL timeout number. Using default\n"); 407 timeout = 0; 408 } 409 } 410 411 tmp = ast_variable_retrieve(cfg, "global", "userfield"); 412 if (tmp) { 413 if (sscanf(tmp, "%d", &userfield) < 1) { 414 ast_log(LOG_WARNING, "Invalid MySQL configurtation file\n"); 415 userfield = 0; 416 } 417 } 418 419 ast_config_destroy(cfg); 420 421 ast_log(LOG_DEBUG, "cdr_mysql: got hostname of %s\n", hostname); 422 ast_log(LOG_DEBUG, "cdr_mysql: got port of %d\n", dbport); 423 ast_log(LOG_DEBUG, "cdr_mysql: got a timeout of %d\n", timeout); 424 if (dbsock) 425 ast_log(LOG_DEBUG, "cdr_mysql: got sock file of %s\n", dbsock); 426 ast_log(LOG_DEBUG, "cdr_mysql: got user of %s\n", dbuser); 427 ast_log(LOG_DEBUG, "cdr_mysql: got dbname of %s\n", dbname); 428 ast_log(LOG_DEBUG, "cdr_mysql: got password of %s\n", password); 429 430 mysql_init(&mysql); 431 432 if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) { 433 ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); 434 } 435 436 if (!mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) { 437 ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", dbname, hostname); 438 connected = 0; 439 records = 0; 440 } else { 441 ast_log(LOG_DEBUG, "Successfully connected to MySQL database.\n"); 442 connected = 1; 443 records = 0; 444 connect_time = time(NULL); 445 } 446 447 res = ast_cdr_register(name, desc, mysql_log); 448 if (res) { 449 ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n"); 450 } else { 451 res = ast_cli_register(&cdr_mysql_status_cli); 452 } 453 454 return res; 455 } 456 457 int load_module(void) 458 { 459 return my_load_module(); 460 } 461 462 int unload_module(void) 463 { 464 return my_unload_module(); 465 } 466 467 int reload(void) 468 { 469 int ret; 470 471 ast_mutex_lock(&mysql_lock); 472 my_unload_module(); 473 ret = my_load_module(); 474 ast_mutex_unlock(&mysql_lock); 475 476 return ret; 477 } 478 479 int usecount(void) 480 { 481 /* Simplistic use count */ 482 if (ast_mutex_trylock(&mysql_lock)) { 483 return 1; 484 } else { 485 ast_mutex_unlock(&mysql_lock); 486 return 0; 487 } 488 } 489 490 char *key() 491 { 492 return ASTERISK_GPL_KEY; 493 }
Note:
See TracBrowser
for help on using the repository browser.
