Index: cdr_addon_mysql.c =================================================================== RCS file: /usr/cvsroot/asterisk-addons/cdr_addon_mysql.c,v retrieving revision 1.5 diff -r1.5 cdr_addon_mysql.c 10a11,16 > * Modified August 6, 2005 > * Joseph Benden > * Added mysql connection timeout parameter > * Added an automatic reconnect as to not lose a cdr record > * Cleaned up the original code to match the coding guidelines > * 24d29 < #include "asterisk.h" 35a41,44 > #include > #include > #include > 41,42c50,51 < static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *dbsock = NULL; < static int hostname_alloc = 0, dbname_alloc = 0, dbuser_alloc = 0, password_alloc = 0, dbsock_alloc = 0; --- > static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *dbsock = NULL, *dbtable = NULL; > static int hostname_alloc = 0, dbname_alloc = 0, dbuser_alloc = 0, password_alloc = 0, dbsock_alloc = 0, dbtable_alloc = 0; 48a58 > static unsigned int timeout = 0; 71a82,83 > if (dbtable && *dbtable) > snprintf(status2, 99, " using table %s", dbtable); 105a118,122 > char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL; > int retries; > #ifdef MYSQL_LOGUNIQUEID > char *uniqueid=NULL; > #endif 109c126 < memset(sqlcmd,0,2048); --- > memset(sqlcmd, 0, 2048); 111,112c128,129 < localtime_r(&cdr->start.tv_sec,&tm); < strftime(timestr,128,DATE_FORMAT,&tm); --- > localtime_r(&cdr->start.tv_sec, &tm); > strftime(timestr, 128, DATE_FORMAT, &tm); 114c131,133 < if ((!connected) && (hostname || dbsock) && dbuser && password && dbname) { --- > retries = 5; > db_reconnect: > if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) { 116a136,139 > /* Add option to quickly timeout the connection */ > if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) { > ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); > } 122c145,146 < ast_log(LOG_ERROR, "cdr_mysql: cannot connect to database server %s. Call will not be logged\n", hostname); --- > ast_log(LOG_ERROR, "cdr_mysql: cannot connect to database server %s.\n", hostname); > connected = 0; 132c156,157 < ast_log(LOG_ERROR, "cdr_mysql: Server has gone away\n"); --- > case CR_SERVER_LOST: > ast_log(LOG_WARNING, "cdr_mysql: Server has gone away. Attempting to reconnect.\n"); 135c160 < ast_log(LOG_ERROR, "cdr_mysql: Unknown connection error\n"); --- > ast_log(LOG_ERROR, "cdr_mysql: Unknown connection error: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); 136a162,166 > retries--; > if (retries) > goto db_reconnect; > else > ast_log(LOG_ERROR, "cdr_mysql: Retried to connect fives times, giving up.\n"); 140,158c170,190 < if (connected) { < char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL; < #ifdef MYSQL_LOGUNIQUEID < char *uniqueid=NULL; < #endif < < /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */ < if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL) < mysql_real_escape_string(&mysql, clid, cdr->clid, strlen(cdr->clid)); < if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL) < mysql_real_escape_string(&mysql, dcontext, cdr->dcontext, strlen(cdr->dcontext)); < if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL) < mysql_real_escape_string(&mysql, channel, cdr->channel, strlen(cdr->channel)); < if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL) < mysql_real_escape_string(&mysql, dstchannel, cdr->dstchannel, strlen(cdr->dstchannel)); < if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL) < mysql_real_escape_string(&mysql, lastapp, cdr->lastapp, strlen(cdr->lastapp)); < if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL) < mysql_real_escape_string(&mysql, lastdata, cdr->lastdata, strlen(cdr->lastdata)); --- > /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */ > > /* WARNING: This code previously used mysql_real_escape_string, but the use of said function > requires an active connection to a database. If we are not connected, then this function > cannot be used. This is a problem since we need to store off the SQL statement into our > spool file for later restoration. > > So the question is, what's the best way to handle this? This works for now. > */ > if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL) > mysql_escape_string(clid, cdr->clid, strlen(cdr->clid)); > if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL) > mysql_escape_string(dcontext, cdr->dcontext, strlen(cdr->dcontext)); > if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL) > mysql_escape_string(channel, cdr->channel, strlen(cdr->channel)); > if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL) > mysql_escape_string(dstchannel, cdr->dstchannel, strlen(cdr->dstchannel)); > if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL) > mysql_escape_string(lastapp, cdr->lastapp, strlen(cdr->lastapp)); > if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL) > mysql_escape_string(lastdata, cdr->lastdata, strlen(cdr->lastdata)); 160,161c192,193 < if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL) < mysql_real_escape_string(&mysql, uniqueid, cdr->uniqueid, strlen(cdr->uniqueid)); --- > if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL) > mysql_escape_string(uniqueid, cdr->uniqueid, strlen(cdr->uniqueid)); 162a195,196 > if (userfield && ((userfielddata = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL)) > mysql_escape_string(userfielddata, cdr->userfield, strlen(cdr->userfield)); 164,167c198 < if (userfield && ((userfielddata = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL)) < mysql_real_escape_string(&mysql, userfielddata, cdr->userfield, strlen(cdr->userfield)); < < /* Check for all alloca failures above at once */ --- > /* Check for all alloca failures above at once */ 169c200 < if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid)) { --- > if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid)) { 171c202 < if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata)) { --- > if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata)) { 173,176c204,207 < ast_log(LOG_ERROR, "cdr_mysql: Out of memory error (insert fails)\n"); < ast_mutex_unlock(&mysql_lock); < return -1; < } --- > ast_log(LOG_ERROR, "cdr_mysql: Out of memory error (insert fails)\n"); > ast_mutex_unlock(&mysql_lock); > return -1; > } 178c209 < ast_log(LOG_DEBUG,"cdr_mysql: inserting a CDR record.\n"); --- > ast_log(LOG_DEBUG, "cdr_mysql: inserting a CDR record.\n"); 180,181c211 < if (userfield && userfielddata) < { --- > if (userfield && userfielddata) { 183c213 < sprintf(sqlcmd,"INSERT INTO cdr (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')",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); --- > 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); 185c215 < sprintf(sqlcmd,"INSERT INTO cdr (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')",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); --- > 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); 187,189c217 < } < else < { --- > } else { 191c219 < sprintf(sqlcmd,"INSERT INTO cdr (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')",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); --- > 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); 193c221 < sprintf(sqlcmd,"INSERT INTO cdr (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')",timestr,clid,cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata,cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode); --- > 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); 195c223 < } --- > } 197c225 < ast_log(LOG_DEBUG,"cdr_mysql: SQL command as follows: %s\n",sqlcmd); --- > ast_log(LOG_DEBUG, "cdr_mysql: SQL command as follows: %s\n", sqlcmd); 198a227 > if (connected) { 200,202c229,230 < ast_log(LOG_ERROR,"Failed to insert into database."); < ast_mutex_unlock(&mysql_lock); < return -1; --- > ast_log(LOG_ERROR, "mysql_cdr: Failed to insert into database: (%d) %s", mysql_errno(&mysql), mysql_error(&mysql)); > connected = 0; 244a273,277 > if (dbtable && dbtable_alloc) { > free(dbtable); > dbtable = NULL; > dbtable_alloc = 0; > } 261a295,297 > #if (ASTERISK_VERSION_NUM > 10199) > cfg = ast_config_load(config); > #else 262a299 > #endif 274c311 < tmp = ast_variable_retrieve(cfg,"global","hostname"); --- > tmp = ast_variable_retrieve(cfg, "global", "hostname"); 279c316 < strcpy(hostname,tmp); --- > strcpy(hostname, tmp); 281c318 < ast_log(LOG_ERROR,"Out of memory error.\n"); --- > ast_log(LOG_ERROR, "Out of memory error.\n"); 285c322 < ast_log(LOG_WARNING,"MySQL server hostname not specified. Assuming localhost\n"); --- > ast_log(LOG_WARNING, "MySQL server hostname not specified. Assuming localhost\n"); 289c326 < tmp = ast_variable_retrieve(cfg,"global","dbname"); --- > tmp = ast_variable_retrieve(cfg, "global", "dbname"); 294c331 < strcpy(dbname,tmp); --- > strcpy(dbname, tmp); 296c333 < ast_log(LOG_ERROR,"Out of memory error.\n"); --- > ast_log(LOG_ERROR, "Out of memory error.\n"); 300c337 < ast_log(LOG_WARNING,"MySQL database not specified. Assuming asteriskcdrdb\n"); --- > ast_log(LOG_WARNING, "MySQL database not specified. Assuming asteriskcdrdb\n"); 304c341 < tmp = ast_variable_retrieve(cfg,"global","user"); --- > tmp = ast_variable_retrieve(cfg, "global", "user"); 309c346 < strcpy(dbuser,tmp); --- > strcpy(dbuser, tmp); 311c348 < ast_log(LOG_ERROR,"Out of memory error.\n"); --- > ast_log(LOG_ERROR, "Out of memory error.\n"); 315c352 < ast_log(LOG_WARNING,"MySQL database user not specified. Assuming root\n"); --- > ast_log(LOG_WARNING, "MySQL database user not specified. Assuming root\n"); 319c356 < tmp = ast_variable_retrieve(cfg,"global","sock"); --- > tmp = ast_variable_retrieve(cfg, "global", "sock"); 324c361 < strcpy(dbsock,tmp); --- > strcpy(dbsock, tmp); 326c363 < ast_log(LOG_ERROR,"Out of memory error.\n"); --- > ast_log(LOG_ERROR, "Out of memory error.\n"); 330c367 < ast_log(LOG_WARNING,"MySQL database sock file not specified. Using default\n"); --- > ast_log(LOG_WARNING, "MySQL database sock file not specified. Using default\n"); 334c371,386 < tmp = ast_variable_retrieve(cfg,"global","password"); --- > tmp = ast_variable_retrieve(cfg, "global", "table"); > if (tmp) { > dbtable = malloc(strlen(tmp) + 1); > if (dbtable != NULL) { > dbtable_alloc = 1; > strcpy(dbtable, tmp); > } else { > ast_log(LOG_ERROR, "Out of memory error.\n"); > return -1; > } > } else { > ast_log(LOG_NOTICE, "MySQL database table not specified. Assuming \"cdr\"\n"); > dbtable = "cdr"; > } > > tmp = ast_variable_retrieve(cfg, "global", "password"); 339c391 < strcpy(password,tmp); --- > strcpy(password, tmp); 341c393 < ast_log(LOG_ERROR,"Out of memory error.\n"); --- > ast_log(LOG_ERROR, "Out of memory error.\n"); 345c397 < ast_log(LOG_WARNING,"MySQL database password not specified. Assuming blank\n"); --- > ast_log(LOG_WARNING, "MySQL database password not specified. Assuming blank\n"); 349c401 < tmp = ast_variable_retrieve(cfg,"global","port"); --- > tmp = ast_variable_retrieve(cfg, "global", "port"); 351,352c403,404 < if (sscanf(tmp,"%d",&dbport) < 1) { < ast_log(LOG_WARNING,"Invalid MySQL port number. Using default\n"); --- > if (sscanf(tmp,"%d", &dbport) < 1) { > ast_log(LOG_WARNING, "Invalid MySQL port number. Using default\n"); 355a408,415 > > tmp = ast_variable_retrieve(cfg, "global", "timeout"); > if (tmp) { > if (sscanf(tmp,"%d", &timeout) < 1) { > ast_log(LOG_WARNING, "Invalid MySQL timeout number. Using default\n"); > timeout = 0; > } > } 357c417 < tmp = ast_variable_retrieve(cfg,"global","userfield"); --- > tmp = ast_variable_retrieve(cfg, "global", "userfield"); 359,360c419,420 < if (sscanf(tmp,"%d",&userfield) < 1) { < ast_log(LOG_WARNING,"Invalid MySQL configurtation file\n"); --- > if (sscanf(tmp, "%d", &userfield) < 1) { > ast_log(LOG_WARNING, "Invalid MySQL configurtation file\n"); 364c424,427 < --- > > #if (ASTERISK_VERSION_NUM > 10199) > ast_config_destroy(cfg); > #else 365a429 > #endif 367,368c431,433 < ast_log(LOG_DEBUG,"cdr_mysql: got hostname of %s\n",hostname); < ast_log(LOG_DEBUG,"cdr_mysql: got port of %d\n",dbport); --- > ast_log(LOG_DEBUG, "cdr_mysql: got hostname of %s\n", hostname); > ast_log(LOG_DEBUG, "cdr_mysql: got port of %d\n", dbport); > ast_log(LOG_DEBUG, "cdr_mysql: got a timeout of %d\n", timeout); 370,374c435,439 < ast_log(LOG_DEBUG,"cdr_mysql: got sock file of %s\n",dbsock); < ast_log(LOG_DEBUG,"cdr_mysql: got user of %s\n",dbuser); < ast_log(LOG_DEBUG,"cdr_mysql: got dbname of %s\n",dbname); < ast_log(LOG_DEBUG,"cdr_mysql: got password of %s\n",password); < --- > ast_log(LOG_DEBUG, "cdr_mysql: got sock file of %s\n", dbsock); > ast_log(LOG_DEBUG, "cdr_mysql: got user of %s\n", dbuser); > ast_log(LOG_DEBUG, "cdr_mysql: got dbname of %s\n", dbname); > ast_log(LOG_DEBUG, "cdr_mysql: got password of %s\n", password); > 376a442,445 > if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) { > ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); > } > 382c451 < ast_log(LOG_DEBUG,"Successfully connected to MySQL database.\n"); --- > ast_log(LOG_DEBUG, "Successfully connected to MySQL database.\n"); 409a479,481 > int ret; > > ast_mutex_lock(&mysql_lock); 411c483,486 < return my_load_module(); --- > ret = my_load_module(); > ast_mutex_unlock(&mysql_lock); > > return ret;