[Asterisk-cvs] asterisk-addons cdr_addon_mysql.c,1.9,1.10

kpfleming kpfleming
Sun Sep 25 16:44:16 CDT 2005


Update of /usr/cvsroot/asterisk-addons
In directory mongoose.digium.com:/tmp/cvs-serv14589

Modified Files:
	cdr_addon_mysql.c 
Log Message:
various enhancements to cdr_addon_mysql (issue #4953)


Index: cdr_addon_mysql.c
===================================================================
RCS file: /usr/cvsroot/asterisk-addons/cdr_addon_mysql.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- cdr_addon_mysql.c	23 Jun 2005 17:40:37 -0000	1.9
+++ cdr_addon_mysql.c	25 Sep 2005 20:41:14 -0000	1.10
@@ -8,6 +8,12 @@
  * Modified August 2003
  * Tilghman Lesher <asterisk__cdr__cdr_mysql__200308 at the-tilghman.com>
  *
+ * Modified August 6, 2005
+ * Joseph Benden <joe at thrallingpenguin.com>
+ * 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
+ *
  * This program is free software, distributed under the terms of
  * the GNU General Public License.
  *
@@ -32,6 +38,10 @@
 #include <mysql.h>
 #include <errmsg.h>
 
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+
 #define DATE_FORMAT "%Y-%m-%d %T"
 
 static char *desc = "MySQL CDR Backend";
@@ -45,6 +55,7 @@
 static int records = 0;
 static int totalrecords = 0;
 static int userfield = 0;
+static unsigned int timeout = 0;
 
 AST_MUTEX_DEFINE_STATIC(mysql_lock);
 
@@ -104,23 +115,34 @@
 	struct localuser *u;
 	char *userfielddata = NULL;
 	char sqlcmd[2048], timestr[128];
+	char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL;
+	int retries = 5;
+#ifdef MYSQL_LOGUNIQUEID
+	char *uniqueid = NULL;
+#endif
 
 	ast_mutex_lock(&mysql_lock);
 
-	memset(sqlcmd,0,2048);
+	memset(sqlcmd, 0, 2048);
 
-	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);
 
+db_reconnect:
 	if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) {
 		/* Attempt to connect */
 		mysql_init(&mysql);
+		/* 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));
+		}
 		if (mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) {
 			connected = 1;
 			connect_time = time(NULL);
 			records = 0;
 		} else {
-			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;
 		}
 	} else {
 		/* Long connection - ping the server */
@@ -130,77 +152,80 @@
 			records = 0;
 			switch (error) {
 				case CR_SERVER_GONE_ERROR:
-					ast_log(LOG_ERROR, "cdr_mysql: Server has gone away\n");
+				case CR_SERVER_LOST:
+					ast_log(LOG_ERROR, "cdr_mysql: Server has gone away. Attempting to reconnect.\n");
 					break;
 				default:
-					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));
 			}
 		}
-	}
+		retries--;
+		if (retries)
+			goto db_reconnect;
+		else
+			ast_log(LOG_ERROR, "cdr_mysql: Retried to connect fives times, giving up.\n");
 
-	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));
 #ifdef MYSQL_LOGUNIQUEID
-		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));
 #endif
+	if (userfield && ((userfielddata = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL))
+		mysql_escape_string(userfielddata, cdr->userfield, strlen(cdr->userfield));
 
-		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 */
 #ifdef MYSQL_LOGUNIQUEID
-		if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid)) {
+	if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid)) {
 #else
-		if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata)) {
+	if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata)) {
 #endif
-			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;
+	}
 
-		ast_log(LOG_DEBUG,"cdr_mysql: inserting a CDR record.\n");
+	ast_log(LOG_DEBUG, "cdr_mysql: inserting a CDR record.\n");
 
-		if (userfield && userfielddata)
-		{
+	if (userfield && userfielddata) {
 #ifdef MYSQL_LOGUNIQUEID
-			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);
+		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);
 #else
-			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);
-#endif  
-		}
-		else
-		{
+		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);
+#endif
+	} else {
 #ifdef MYSQL_LOGUNIQUEID
-			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);
+		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);
 #else
-			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);
-#endif  
-		}
-		
-		ast_log(LOG_DEBUG,"cdr_mysql: SQL command as follows:  %s\n",sqlcmd);
+		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);
+#endif
+	}
 	
-		if (mysql_real_query(&mysql,sqlcmd,strlen(sqlcmd))) {
-			ast_log(LOG_ERROR,"Failed to insert into database.");
-			ast_mutex_unlock(&mysql_lock);
-			return -1;
+	ast_log(LOG_DEBUG, "cdr_mysql: SQL command as follows: %s\n", sqlcmd);
+	
+	if (connected) {
+		if (mysql_real_query(&mysql, sqlcmd, strlen(sqlcmd))) {
+			ast_log(LOG_ERROR, "mysql_cdr: Failed to insert into database: (%d) %s", mysql_errno(&mysql), mysql_error(&mysql));
+			connected = 0;
 		} else {
 			records++;
 			totalrecords++;
@@ -277,130 +302,143 @@
 		return 0;
 	}
 
-	tmp = ast_variable_retrieve(cfg,"global","hostname");
+	tmp = ast_variable_retrieve(cfg, "global", "hostname");
 	if (tmp) {
 		hostname = malloc(strlen(tmp) + 1);
 		if (hostname != NULL) {
 			hostname_alloc = 1;
-			strcpy(hostname,tmp);
+			strcpy(hostname, tmp);
 		} else {
-			ast_log(LOG_ERROR,"Out of memory error.\n");
+			ast_log(LOG_ERROR, "Out of memory error.\n");
 			return -1;
 		}
 	} else {
-		ast_log(LOG_WARNING,"MySQL server hostname not specified.  Assuming localhost\n");
+		ast_log(LOG_WARNING, "MySQL server hostname not specified.  Assuming localhost\n");
 		hostname = "localhost";
 	}
 
-	tmp = ast_variable_retrieve(cfg,"global","dbname");
+	tmp = ast_variable_retrieve(cfg, "global", "dbname");
 	if (tmp) {
 		dbname = malloc(strlen(tmp) + 1);
 		if (dbname != NULL) {
 			dbname_alloc = 1;
-			strcpy(dbname,tmp);
+			strcpy(dbname, tmp);
 		} else {
-			ast_log(LOG_ERROR,"Out of memory error.\n");
+			ast_log(LOG_ERROR, "Out of memory error.\n");
 			return -1;
 		}
 	} else {
-		ast_log(LOG_WARNING,"MySQL database not specified.  Assuming asteriskcdrdb\n");
+		ast_log(LOG_WARNING, "MySQL database not specified.  Assuming asteriskcdrdb\n");
 		dbname = "asteriskcdrdb";
 	}
 
-	tmp = ast_variable_retrieve(cfg,"global","user");
+	tmp = ast_variable_retrieve(cfg, "global", "user");
 	if (tmp) {
 		dbuser = malloc(strlen(tmp) + 1);
 		if (dbuser != NULL) {
 			dbuser_alloc = 1;
-			strcpy(dbuser,tmp);
+			strcpy(dbuser, tmp);
 		} else {
-			ast_log(LOG_ERROR,"Out of memory error.\n");
+			ast_log(LOG_ERROR, "Out of memory error.\n");
 			return -1;
 		}
 	} else {
-		ast_log(LOG_WARNING,"MySQL database user not specified.  Assuming root\n");
+		ast_log(LOG_WARNING, "MySQL database user not specified.  Assuming root\n");
 		dbuser = "root";
 	}
 
-	tmp = ast_variable_retrieve(cfg,"global","sock");
+	tmp = ast_variable_retrieve(cfg, "global", "sock");
 	if (tmp) {
 		dbsock = malloc(strlen(tmp) + 1);
 		if (dbsock != NULL) {
 			dbsock_alloc = 1;
-			strcpy(dbsock,tmp);
+			strcpy(dbsock, tmp);
 		} else {
-			ast_log(LOG_ERROR,"Out of memory error.\n");
+			ast_log(LOG_ERROR, "Out of memory error.\n");
 			return -1;
 		}
 	} else {
-		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");
 		dbsock = NULL;
 	}
 
-	tmp = ast_variable_retrieve(cfg,"global","table");
+	tmp = ast_variable_retrieve(cfg, "global", "table");
 	if (tmp) {
 		dbtable = malloc(strlen(tmp) + 1);
 		if (dbtable != NULL) {
 			dbtable_alloc = 1;
-			strcpy(dbtable,tmp);
+			strcpy(dbtable, tmp);
 		} else {
-			ast_log(LOG_ERROR,"Out of memory error.\n");
+			ast_log(LOG_ERROR, "Out of memory error.\n");
 			return -1;
 		}
 	} else {
-		ast_log(LOG_NOTICE,"MySQL database table not specified.  Assuming \"cdr\"\n");
+		ast_log(LOG_NOTICE, "MySQL database table not specified.  Assuming \"cdr\"\n");
 		dbtable = "cdr";
 	}
 
-	tmp = ast_variable_retrieve(cfg,"global","password");
+	tmp = ast_variable_retrieve(cfg, "global", "password");
 	if (tmp) {
 		password = malloc(strlen(tmp) + 1);
 		if (password != NULL) {
 			password_alloc = 1;
-			strcpy(password,tmp);
+			strcpy(password, tmp);
 		} else {
-			ast_log(LOG_ERROR,"Out of memory error.\n");
+			ast_log(LOG_ERROR, "Out of memory error.\n");
 			return -1;
 		}
 	} else {
-		ast_log(LOG_WARNING,"MySQL database password not specified.  Assuming blank\n");
+		ast_log(LOG_WARNING, "MySQL database password not specified.  Assuming blank\n");
 		password = "";
 	}
 
-	tmp = ast_variable_retrieve(cfg,"global","port");
+	tmp = ast_variable_retrieve(cfg, "global", "port");
 	if (tmp) {
-		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");
 			dbport = 0;
 		}
 	}
+
+	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;
+		}
+	}
 	
-	tmp = ast_variable_retrieve(cfg,"global","userfield");
+	tmp = ast_variable_retrieve(cfg, "global", "userfield");
 	if (tmp) {
-		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");
 			userfield = 0;
 		}
 	}
 	
 	ast_config_destroy(cfg);
 
-	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);
 	if (dbsock)
-		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);
 
 	mysql_init(&mysql);
 
+	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));
+	}
+
 	if (!mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) {
 		ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", dbname, hostname);
 		connected = 0;
 		records = 0;
 	} else {
-		ast_log(LOG_DEBUG,"Successfully connected to MySQL database.\n");
+		ast_log(LOG_DEBUG, "Successfully connected to MySQL database.\n");
 		connected = 1;
 		records = 0;
 		connect_time = time(NULL);




More information about the svn-commits mailing list