[svn-commits] tilghman: trunk r362 - /trunk/res_config_mysql.c

svn-commits at lists.digium.com svn-commits at lists.digium.com
Tue Apr 10 16:07:02 MST 2007


Author: tilghman
Date: Tue Apr 10 18:07:02 2007
New Revision: 362

URL: http://svn.digium.com/view/asterisk-addons?view=rev&rev=362
Log:
Issue 5881 - Allow use of separate server connections for read and write operations

Modified:
    trunk/res_config_mysql.c

Modified: trunk/res_config_mysql.c
URL: http://svn.digium.com/view/asterisk-addons/trunk/res_config_mysql.c?view=diff&rev=362&r1=361&r2=362
==============================================================================
--- trunk/res_config_mysql.c (original)
+++ trunk/res_config_mysql.c Tue Apr 10 18:07:02 2007
@@ -58,21 +58,27 @@
 
 #define AST_MODULE "res_config_mysql"
 
-AST_MUTEX_DEFINE_STATIC(mysql_lock);
 #define RES_CONFIG_MYSQL_CONF "res_mysql.conf"
-MYSQL         mysql;
-static char   dbhost[50];
-static char   dbuser[50];
-static char   dbpass[50];
-static char   dbname[50];
-static char   dbsock[50];
-static int    dbport;
-static int    connected;
-static time_t connect_time;
+#define	READHANDLE	0
+#define	WRITEHANDLE	1
+
+static struct mysql_conn {
+	ast_mutex_t	lock;
+	MYSQL       handle;
+	char        host[50];
+	char        name[50];
+	char        user[50];
+	char        pass[50];
+	char        sock[50];
+	int         port;
+	int         connected;
+	time_t      connect_time;
+} dbread, dbwrite;
 
 static int parse_config(void);
-static int mysql_reconnect(const char *database);
+static int mysql_reconnect(struct mysql_conn *conn);
 static int realtime_mysql_status(int fd, int argc, char **argv);
+static int load_mysql_config(struct ast_config *config, const char *category, struct mysql_conn *conn);
 
 static char cli_realtime_mysql_status_usage[] =
 "Usage: realtime mysql status\n"
@@ -110,9 +116,9 @@
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&mysql_lock);
-	if (!mysql_reconnect(database)) {
-		ast_mutex_unlock(&mysql_lock);
+	ast_mutex_lock(&dbread.lock);
+	if (!mysql_reconnect(&dbread)) {
+		ast_mutex_unlock(&dbread.lock);
 		return NULL;
 	}
 
@@ -126,7 +132,7 @@
 
 	if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
 		valsz = (sizeof(buf) - 1) / 2;
-	mysql_real_escape_string(&mysql, buf, newval, valsz);
+	mysql_real_escape_string(&dbread.handle, buf, newval, valsz);
 	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, buf);
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
@@ -136,7 +142,7 @@
 			op = "";
 		if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
 			valsz = (sizeof(buf) - 1) / 2;
-		mysql_real_escape_string(&mysql, buf, newval, valsz);
+		mysql_real_escape_string(&dbread.handle, buf, newval, valsz);
 		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, buf);
 	}
 	va_end(ap);
@@ -144,23 +150,21 @@
 	ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
 
 	/* Execution. */
-	if (mysql_real_query(&mysql, sql, strlen(sql))) {
+	if (mysql_real_query(&dbread.handle, sql, strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
 		ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
-		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
-		ast_mutex_unlock(&mysql_lock);
-		return NULL;
-	}
-
-	if ((result = mysql_store_result(&mysql))) {
+		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbread.handle));
+		ast_mutex_unlock(&dbread.lock);
+		return NULL;
+	}
+
+	if ((result = mysql_store_result(&dbread.handle))) {
 		numFields = mysql_num_fields(result);
 		fields = mysql_fetch_fields(result);
 
 		while ((row = mysql_fetch_row(result))) {
 			for (i = 0; i < numFields; i++) {
-				stringp = row[i];
-				while (stringp) {
-					chunk = strsep(&stringp, ";");
+				for (stringp = ast_strdupa(row[i]), chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
 					if (chunk && !ast_strlen_zero(ast_strip(chunk))) {
 						if (prev) {
 							prev->next = ast_variable_new(fields[i].name, chunk);
@@ -174,11 +178,11 @@
 				}
 			}
 		}
-	} else {                                
+	} else {
 		ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
 	}
 
-	ast_mutex_unlock(&mysql_lock);
+	ast_mutex_unlock(&dbread.lock);
 	mysql_free_result(result);
 
 	return var;
@@ -198,7 +202,7 @@
 	char *op;
 	const char *newparam, *newval;
 	struct ast_realloca ra;
-	struct ast_variable *var=NULL;
+	struct ast_variable *var = NULL;
 	struct ast_config *cfg = NULL;
 	struct ast_category *cat = NULL;
 
@@ -231,27 +235,31 @@
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&mysql_lock);
-	if (!mysql_reconnect(database)) {
-		ast_mutex_unlock(&mysql_lock);
+	ast_mutex_lock(&dbread.lock);
+	if (!mysql_reconnect(&dbread)) {
+		ast_mutex_unlock(&dbread.lock);
+		ast_config_destroy(cfg);
 		return NULL;
 	}
 
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if(!strchr(newparam, ' ')) op = " ="; else op = "";
+	if (!strchr(newparam, ' '))
+		op = " =";
+	else
+		op = "";
 
 	if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
 		valsz = (sizeof(buf) - 1) / 2;
-	mysql_real_escape_string(&mysql, buf, newval, valsz);
+	mysql_real_escape_string(&dbread.handle, buf, newval, valsz);
 	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, buf);
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		if (!strchr(newparam, ' ')) op = " ="; else op = "";
-		if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
+		if ((valsz = strlen(newval)) * 2 + 1 > sizeof(buf))
 			valsz = (sizeof(buf) - 1) / 2;
-		mysql_real_escape_string(&mysql, buf, newval, valsz);
+		mysql_real_escape_string(&dbread.handle, buf, newval, valsz);
 		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, buf);
 	}
 
@@ -264,16 +272,16 @@
 	ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
 
 	/* Execution. */
-	if (mysql_real_query(&mysql, sql, strlen(sql))) {
+	if (mysql_real_query(&dbread.handle, sql, strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
 		ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
-		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
-		ast_mutex_unlock(&mysql_lock);
+		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbread.handle));
+		ast_mutex_unlock(&dbread.lock);
 		ast_config_destroy(cfg);
 		return NULL;
 	}
 
-	if ((result = mysql_store_result(&mysql))) {
+	if ((result = mysql_store_result(&dbread.handle))) {
 		numFields = mysql_num_fields(result);
 		fields = mysql_fetch_fields(result);
 
@@ -285,9 +293,7 @@
 				continue;
 			}
 			for (i = 0; i < numFields; i++) {
-				stringp = row[i];
-				while (stringp) {
-					chunk = strsep(&stringp, ";");
+				for (stringp = ast_strdupa(row[i]), chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
 					if (chunk && !ast_strlen_zero(ast_strip(chunk))) {
 						if (initfield && !strcmp(initfield, fields[i].name)) {
 							ast_category_rename(cat, chunk);
@@ -303,7 +309,7 @@
 		ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
 	}
 
-	ast_mutex_unlock(&mysql_lock);
+	ast_mutex_unlock(&dbread.lock);
 	mysql_free_result(result);
 
 	return cfg;
@@ -319,7 +325,7 @@
 
 	if (!table) {
 		ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
-               return -1;
+		return -1;
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
@@ -331,45 +337,45 @@
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&mysql_lock);
-	if (!mysql_reconnect(database)) {
-		ast_mutex_unlock(&mysql_lock);
+	ast_mutex_lock(&dbwrite.lock);
+	if (!mysql_reconnect(&dbwrite)) {
+		ast_mutex_unlock(&dbwrite.lock);
 		return -1;
 	}
 
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if ((valsz = strlen (newval)) * 1 + 1 > sizeof(buf))
+	if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
 		valsz = (sizeof(buf) - 1) / 2;
-	mysql_real_escape_string(&mysql, buf, newval, valsz);
+	mysql_real_escape_string(&dbwrite.handle, buf, newval, valsz);
 	snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, buf);
 	while((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
 			valsz = (sizeof(buf) - 1) / 2;
-		mysql_real_escape_string(&mysql, buf, newval, valsz);
+		mysql_real_escape_string(&dbwrite.handle, buf, newval, valsz);
 		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam, buf);
 	}
 	va_end(ap);
-	if ((valsz = strlen (lookup)) * 1 + 1 > sizeof(buf))
+	if ((valsz = strlen (lookup)) * 2 + 1 > sizeof(buf))
 		valsz = (sizeof(buf) - 1) / 2;
-	mysql_real_escape_string(&mysql, buf, lookup, valsz);
+	mysql_real_escape_string(&dbwrite.handle, buf, lookup, valsz);
 	snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield, buf);
 
 	ast_log(LOG_DEBUG,"MySQL RealTime: Update SQL: %s\n", sql);
 
 	/* Execution. */
-	if (mysql_real_query(&mysql, sql, strlen(sql))) {
+	if (mysql_real_query(&dbwrite.handle, sql, strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
 		ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
-		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
-		ast_mutex_unlock(&mysql_lock);
-		return -1;
-	}
-
-	numrows = mysql_affected_rows(&mysql);
-	ast_mutex_unlock(&mysql_lock);
+		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbwrite.handle));
+		ast_mutex_unlock(&dbwrite.lock);
+		return -1;
+	}
+
+	numrows = mysql_affected_rows(&dbwrite.handle);
+	ast_mutex_unlock(&dbwrite.lock);
 
 	ast_log(LOG_DEBUG,"MySQL RealTime: Updated %llu rows on table: %s\n", numrows, table);
 
@@ -379,10 +385,7 @@
 	 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
 	*/
 
-	if (numrows >= 0)
-		return (int)numrows;
-
-	return -1;
+	return (int)numrows;
 }
  
 static int store_mysql(const char *database, const char *table, va_list ap)
@@ -404,65 +407,61 @@
 	newval = va_arg(ap, const char *);
 	if (!newparam || !newval)  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime storage requires at least 1 parameter and 1 value to search on.\n");
-		mysql_close(&mysql);
 		return -1;
 	}
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&mysql_lock);
-	if (!mysql_reconnect(database)) {
-		ast_mutex_unlock(&mysql_lock);
+	ast_mutex_lock(&dbwrite.lock);
+	if (!mysql_reconnect(&dbwrite)) {
+		ast_mutex_unlock(&dbwrite.lock);
 		return -1;
 	}
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 		If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
-	if ((valsz = strlen(newval)) * 1 + 1 > sizeof(buf))
+	if ((valsz = strlen(newval)) * 2 + 1 > sizeof(buf))
 		valsz = (sizeof(buf) - 1) / 2;
 	if (newval) {
-		mysql_real_escape_string(&mysql, buf, newval, valsz);
+		mysql_real_escape_string(&dbwrite.handle, buf, newval, valsz);
 	} else { 
-		buf[0] = 0;
-	}
-	snprintf(fields, sizeof(fields), "%s",newparam);
-	snprintf(values, sizeof(values), "'%s'",buf);
+		buf[0] = '\0';
+	}
+	snprintf(fields, sizeof(fields), "%s", newparam);
+	snprintf(values, sizeof(values), "'%s'", buf);
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		if (newval) {
 			if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
 				valsz = (sizeof(buf) - 1) / 2;
-			mysql_real_escape_string(&mysql, buf, newval, valsz);
+			mysql_real_escape_string(&dbwrite.handle, buf, newval, valsz);
 		} else {
-			buf[0] = 0;
+			buf[0] = '\0';
 		}
-		snprintf(fields + strlen(fields), sizeof(fields), ", %s",newparam);
-		snprintf(values + strlen(values), sizeof(values), ", '%s'",buf);
+		snprintf(fields + strlen(fields), sizeof(fields), ", %s", newparam);
+		snprintf(values + strlen(values), sizeof(values), ", '%s'", buf);
 	}
 	va_end(ap);
 	snprintf(sql, sizeof(sql), "INSERT into %s (%s) values (%s)", table, fields, values);
 	ast_log(LOG_DEBUG,"MySQL RealTime: Insert SQL: %s\n", sql);
 
 	/* Execution. */
-	if (mysql_real_query(&mysql, sql, strlen(sql))) {
+	if (mysql_real_query(&dbwrite.handle, sql, strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
 		ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
-		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
-		ast_mutex_unlock(&mysql_lock);
-		return -1;
-	}
-
-	insertid = mysql_insert_id(&mysql);
-	ast_mutex_unlock(&mysql_lock);
-
-	ast_log(LOG_DEBUG,"MySQL RealTime: row inserted on table: %s, id: %llu\n", table, insertid);
+		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbwrite.handle));
+		ast_mutex_unlock(&dbwrite.lock);
+		return -1;
+	}
+
+	insertid = mysql_insert_id(&dbwrite.handle);
+	ast_mutex_unlock(&dbwrite.lock);
+
+	ast_log(LOG_DEBUG, "MySQL RealTime: row inserted on table: %s, id: %llu\n", table, insertid);
 
 	/* From http://dev.mysql.com/doc/mysql/en/mysql-affected-rows.html
 	 * An integer greater than zero indicates the number of rows affected
 	 * Zero indicates that no records were updated
 	 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
 	*/
-	if (insertid >= 0)
-		return (int)insertid;
-
-	return -1;
+	return (int)insertid;
 }
 
 static int destroy_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
@@ -483,52 +482,47 @@
 	newval = va_arg(ap, const char *);*/
 	if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime destroying requires at least 1 parameter and 1 value to search on.\n");
-		mysql_close(&mysql);
 		return -1;
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
-	ast_mutex_lock(&mysql_lock);
-	if (!mysql_reconnect(database)) {
-		ast_mutex_unlock(&mysql_lock);
+	ast_mutex_lock(&dbwrite.lock);
+	if (!mysql_reconnect(&dbwrite)) {
+		ast_mutex_unlock(&dbwrite.lock);
 		return -1;
 	}
 
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if ((valsz = strlen (lookup)) * 1 + 1 > sizeof(buf))
+	if ((valsz = strlen (lookup)) * 2 + 1 > sizeof(buf))
 		valsz = (sizeof(buf) - 1) / 2;
-	mysql_real_escape_string(&mysql, buf, lookup, valsz);
+	mysql_real_escape_string(&dbwrite.handle, buf, lookup, valsz);
 	snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s'", table, keyfield, buf);
 	while ((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
 			valsz = (sizeof(buf) - 1) / 2;
-		mysql_real_escape_string(&mysql, buf, newval, valsz);
+		mysql_real_escape_string(&dbwrite.handle, buf, newval, valsz);
 		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s = '%s'", newparam, buf);
 	}
 	va_end(ap);
-	//if ((valsz = strlen (lookup)) * 1 + 1 > sizeof(buf))
-	//	valsz = (sizeof(buf) - 1) / 2;
-	//mysql_real_escape_string(&mysql, buf, lookup, valsz);
-	//snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield, buf);
-
-	ast_log(LOG_DEBUG,"MySQL RealTime: Delete SQL: %s\n", sql);
+
+	ast_log(LOG_DEBUG, "MySQL RealTime: Delete SQL: %s\n", sql);
 
 	/* Execution. */
-	if (mysql_real_query(&mysql, sql, strlen(sql))) {
+	if (mysql_real_query(&dbwrite.handle, sql, strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
 		ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
-		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
-		ast_mutex_unlock(&mysql_lock);
-		return -1;
-	}
-
-	numrows = mysql_affected_rows(&mysql);
-	ast_mutex_unlock(&mysql_lock);
-
-	ast_log(LOG_DEBUG,"MySQL RealTime: Deleted %llu rows on table: %s\n", numrows, table);
+		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbwrite.handle));
+		ast_mutex_unlock(&dbwrite.lock);
+		return -1;
+	}
+
+	numrows = mysql_affected_rows(&dbwrite.handle);
+	ast_mutex_unlock(&dbwrite.lock);
+
+	ast_log(LOG_DEBUG, "MySQL RealTime: Deleted %llu rows on table: %s\n", numrows, table);
 
 	/* From http://dev.mysql.com/doc/mysql/en/mysql-affected-rows.html
 	 * An integer greater than zero indicates the number of rows affected
@@ -536,10 +530,7 @@
 	 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
 	*/
 
-	if (numrows >= 0)
-		return (int)numrows;
-
-	return -1;
+	return (int)numrows;
 }
  
 static struct ast_config *config_mysql(const char *database, const char *table, const char *file, struct ast_config *cfg, int withcomments)
@@ -565,21 +556,21 @@
 	ast_log(LOG_DEBUG, "MySQL RealTime: Static SQL: %s\n", sql);
 
 	/* We now have our complete statement; Lets connect to the server and execute it. */
-	ast_mutex_lock(&mysql_lock);
-	if (!mysql_reconnect(database)) {
-		ast_mutex_unlock(&mysql_lock);
-		return NULL;
-	}
-
-	if (mysql_real_query(&mysql, sql, strlen(sql))) {
+	ast_mutex_lock(&dbread.lock);
+	if (!mysql_reconnect(&dbread)) {
+		ast_mutex_unlock(&dbread.lock);
+		return NULL;
+	}
+
+	if (mysql_real_query(&dbread.handle, sql, strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
 		ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
-		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
-		ast_mutex_unlock(&mysql_lock);
-		return NULL;
-	}
-
-	if ((result = mysql_store_result(&mysql))) {
+		ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&dbread.handle));
+		ast_mutex_unlock(&dbread.lock);
+		return NULL;
+	}
+
+	if ((result = mysql_store_result(&dbread.handle))) {
 		num_rows = mysql_num_rows(result);
 		ast_log(LOG_DEBUG, "MySQL RealTime: Found %llu rows.\n", num_rows);
 
@@ -590,7 +581,8 @@
 			if (!strcmp(row[1], "#include")) {
 				if (!ast_config_internal_load(row[2], cfg, 0)) {
 					mysql_free_result(result);
-					ast_mutex_unlock(&mysql_lock);
+					ast_mutex_unlock(&dbread.lock);
+					ast_config_destroy(cfg);
 					return NULL;
 				}
 				continue;
@@ -615,7 +607,7 @@
 	}
 
 	mysql_free_result(result);
-	ast_mutex_unlock(&mysql_lock);
+	ast_mutex_unlock(&dbread.lock);
 
 	return cfg;
 }
@@ -632,188 +624,216 @@
 
 static int load_module(void)
 {
+	int writeokay = 0;
 	parse_config();
 
-	ast_mutex_lock(&mysql_lock);
-
-	if (!mysql_reconnect(NULL)) {
-		ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
-		ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
+	ast_mutex_init(&dbread.lock);
+	ast_mutex_init(&dbwrite.lock);
+
+	if (!mysql_reconnect(&dbwrite))
+		ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish write connection: %s\n", mysql_error(&dbwrite.handle));
+	else
+		writeokay = 1;
+
+	if (!mysql_reconnect(&dbread)) {
+		if (!writeokay)
+			ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish read connection, either: %s\n", mysql_error(&dbread.handle));
 	}
 
 	ast_config_engine_register(&mysql_engine);
-	if (option_verbose) {
-		ast_verbose("MySQL RealTime driver loaded.\n");
-	}
+	if (option_verbose > 1)
+		ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime driver loaded.\n");
 	ast_cli_register(&cli_realtime_mysql_status);
 
-	ast_mutex_unlock(&mysql_lock);
-
 	return 0;
 }
 
 static int unload_module(void)
 {
-	/* Aquire control before doing anything to the module itself. */
-	ast_mutex_lock(&mysql_lock);
-
-	mysql_close(&mysql);
 	ast_cli_unregister(&cli_realtime_mysql_status);
 	ast_config_engine_deregister(&mysql_engine);
-	if (option_verbose) {
-		ast_verbose("MySQL RealTime unloaded.\n");
-	}
+	if (option_verbose > 1)
+		ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime unloaded.\n");
 
 	ast_module_user_hangup_all();
 
-	/* Unlock so something else can destroy the lock. */
-	ast_mutex_unlock(&mysql_lock);
+	usleep(1);
+	ast_mutex_destroy(&dbread.lock);
+	ast_mutex_destroy(&dbwrite.lock);
+
+	mysql_close(&dbwrite.handle);
+	mysql_close(&dbread.handle);
 
 	return 0;
 }
 
 static int reload(void)
 {
-	/* Aquire control before doing anything to the module itself. */
-	ast_mutex_lock(&mysql_lock);
-
-	mysql_close(&mysql);
-	connected = 0;
+	int writeokay = 0;
+
+	ast_mutex_lock(&dbwrite.lock);
+	ast_mutex_lock(&dbread.lock);
+	mysql_close(&dbwrite.handle);
+	mysql_close(&dbread.handle);
 	parse_config();
 
-	if (!mysql_reconnect(NULL)) {
-		ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
-		ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
-	}
-
-	ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime reloaded.\n");
+	if (!mysql_reconnect(&dbwrite))
+		ast_log(LOG_WARNING, "MySQL RealTime: Cannot connect write handle: %s\n", mysql_error(&dbwrite.handle));
+	else
+		writeokay = 1;
+
+	if (!mysql_reconnect(&dbread)) {
+		if (!writeokay)
+			ast_log(LOG_WARNING, "MySQL RealTime: Cannot Connect read handle, either: %s\n", mysql_error(&dbread.handle));
+	}
+	if (option_verbose > 1)
+		ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime reloaded.\n");
 
 	/* Done reloading. Release lock so others can now use driver. */
-	ast_mutex_unlock(&mysql_lock);
+	ast_mutex_unlock(&dbread.lock);
+	ast_mutex_unlock(&dbwrite.lock);
 
 	return 0;
 }
 
-static int parse_config (void)
+static int parse_config(void)
 {
 	struct ast_config *config;
+
+	config = ast_config_load(RES_CONFIG_MYSQL_CONF);
+
+	if (config) {
+		const char *catg = "write";
+		int haswriteconfig = 0;
+		if (!ast_category_exist(config, catg))
+			catg = "general";
+		if (!ast_category_exist(config, catg))
+			ast_log(LOG_WARNING, "No configuration set for writing to the MySQL database.\n");
+		else
+			haswriteconfig = load_mysql_config(config, catg, &dbwrite);
+
+		if (!ast_category_exist(config, "read")) {
+			if (haswriteconfig) {
+				/* Copy from write config */
+				ast_copy_string(dbread.host, dbwrite.host, sizeof(dbread.host));
+				ast_copy_string(dbread.sock, dbwrite.sock, sizeof(dbread.sock));
+				ast_copy_string(dbread.name, dbwrite.name, sizeof(dbread.name));
+				ast_copy_string(dbread.user, dbwrite.user, sizeof(dbread.user));
+				ast_copy_string(dbread.pass, dbwrite.pass, sizeof(dbread.pass));
+				dbread.port = dbwrite.port;
+			} else
+				ast_log(LOG_WARNING, "It's kind of silly to be loading res_config_mysql.so if there's no configuration settings.\n");
+		} else
+			load_mysql_config(config, "read", &dbread);
+	}
+	ast_config_destroy(config);
+
+	return 0;
+}
+
+static int load_mysql_config(struct ast_config *config, const char *category, struct mysql_conn *conn)
+{
 	const char *s;
 
-	config = ast_config_load(RES_CONFIG_MYSQL_CONF);
-
-	if (config) {
-		if (!(s=ast_variable_retrieve(config, "general", "dbuser"))) {
-			ast_log(LOG_WARNING, "MySQL RealTime: No database user found, using 'asterisk' as default.\n");
-			strncpy(dbuser, "asterisk", sizeof(dbuser) - 1);
-		} else {
-			strncpy(dbuser, s, sizeof(dbuser) - 1);
-		}
-
-		if (!(s=ast_variable_retrieve(config, "general", "dbpass"))) {
-                        ast_log(LOG_WARNING, "MySQL RealTime: No database password found, using 'asterisk' as default.\n");
-                        strncpy(dbpass, "asterisk", sizeof(dbpass) - 1);
-                } else {
-                        strncpy(dbpass, s, sizeof(dbpass) - 1);
-                }
-
-		if (!(s=ast_variable_retrieve(config, "general", "dbhost"))) {
-                        ast_log(LOG_WARNING, "MySQL RealTime: No database host found, using localhost via socket.\n");
-			dbhost[0] = '\0';
-                } else {
-                        strncpy(dbhost, s, sizeof(dbhost) - 1);
-                }
-
-		if (!(s=ast_variable_retrieve(config, "general", "dbname"))) {
-                        ast_log(LOG_WARNING, "MySQL RealTime: No database name found, using 'asterisk' as default.\n");
-			strncpy(dbname, "asterisk", sizeof(dbname) - 1);
-                } else {
-                        strncpy(dbname, s, sizeof(dbname) - 1);
-                }
-
-		if (!(s=ast_variable_retrieve(config, "general", "dbport"))) {
-                        ast_log(LOG_WARNING, "MySQL RealTime: No database port found, using 3306 as default.\n");
-			dbport = 3306;
-                } else {
-			dbport = atoi(s);
-                }
-
-		if (dbhost && !(s=ast_variable_retrieve(config, "general", "dbsock"))) {
-                        ast_log(LOG_WARNING, "MySQL RealTime: No database socket found, using '/tmp/mysql.sock' as default.\n");
-                        strncpy(dbsock, "/tmp/mysql.sock", sizeof(dbsock) - 1);
-                } else {
-                        strncpy(dbsock, s, sizeof(dbsock) - 1);
-                }
-	}
-	ast_config_destroy(config);
-
-	if (dbhost) {
-		ast_log(LOG_DEBUG, "MySQL RealTime Host: %s\n", dbhost);
-		ast_log(LOG_DEBUG, "MySQL RealTime Port: %i\n", dbport);
-	} else {
-		ast_log(LOG_DEBUG, "MySQL RealTime Socket: %s\n", dbsock);
-	}
-	ast_log(LOG_DEBUG, "MySQL RealTime User: %s\n", dbuser);
-	ast_log(LOG_DEBUG, "MySQL RealTime Password: %s\n", dbpass);
+	if (!(s = ast_variable_retrieve(config, category, "dbuser"))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: No database user found, using 'asterisk' as default.\n");
+		s = "asterisk";
+	}
+	ast_copy_string(conn->user, s, sizeof(conn->user));
+
+	if (!(s = ast_variable_retrieve(config, category, "dbpass"))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: No database password found, using 'asterisk' as default.\n");
+		s = "asterisk";
+	}
+	ast_copy_string(conn->pass, s, sizeof(conn->pass));
+
+	if (!(s = ast_variable_retrieve(config, category, "dbhost"))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: No database host found, using localhost via socket.\n");
+		s = "";
+	}
+	ast_copy_string(conn->host, s, sizeof(conn->host));
+
+	if (!(s = ast_variable_retrieve(config, category, "dbname"))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: No database name found, using 'asterisk' as default.\n");
+		s = "asterisk";
+	}
+	ast_copy_string(conn->name, s, sizeof(conn->name) - 1);
+
+	if (!(s = ast_variable_retrieve(config, category, "dbport"))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: No database port found, using 3306 as default.\n");
+		conn->port = 3306;
+	} else
+		conn->port = atoi(s);
+
+	if (!conn->host && !(s = ast_variable_retrieve(config, "general", "dbsock"))) {
+		ast_log(LOG_WARNING, "MySQL RealTime: No database socket found, using '/tmp/mysql.sock' as default.\n");
+		s = "/tmp/mysql.sock";
+	}
+	ast_copy_string(conn->sock, s, sizeof(conn->sock));
+
+
+	if (!ast_strlen_zero(conn->host)) {
+		ast_log(LOG_DEBUG, "MySQL RealTime host: %s\n", conn->host);
+		ast_log(LOG_DEBUG, "MySQL RealTime port: %i\n", conn->port);
+	} else
+		ast_log(LOG_DEBUG, "MySQL RealTime socket: %s\n", conn->sock);
+	ast_log(LOG_DEBUG, "MySQL RealTime database name: %s\n", conn->name);
+	ast_log(LOG_DEBUG, "MySQL RealTime user: %s\n", conn->user);
+	ast_log(LOG_DEBUG, "MySQL RealTime password: %s\n", conn->pass);
 
 	return 1;
 }
 
-static int mysql_reconnect(const char *database)
+static int mysql_reconnect(struct mysql_conn *conn)
 {
 	char my_database[50];
 #ifdef MYSQL_OPT_RECONNECT
 	my_bool trueval = 1;
 #endif
 
-	if (!database || ast_strlen_zero(database))
-		ast_copy_string(my_database, dbname, sizeof(my_database));
-	else
-		ast_copy_string(my_database, database, sizeof(my_database));
-
 	/* mutex lock should have been locked before calling this function. */
 
 reconnect_tryagain:
-	if ((!connected) && (dbhost || dbsock) && dbuser && dbpass && my_database) {
-		if (!mysql_init(&mysql)) {
+	if ((!conn->connected) && (!ast_strlen_zero(conn->host) || conn->sock) && !ast_strlen_zero(conn->user) && !ast_strlen_zero(conn->name)) {
+		if (!mysql_init(&conn->handle)) {
 			ast_log(LOG_WARNING, "MySQL RealTime: Insufficient memory to allocate MySQL resource.\n");
-			connected = 0;
+			conn->connected = 0;
 			return 0;
 		}
-		if (mysql_real_connect(&mysql, dbhost, dbuser, dbpass, my_database, dbport, dbsock, 0)) {
+		if (mysql_real_connect(&conn->handle, conn->host, conn->user, conn->pass, conn->name, conn->port, conn->sock, 0)) {
 #ifdef MYSQL_OPT_RECONNECT
 			/* The default is no longer to automatically reconnect on failure,
 			 * (as of 5.0.3) so we have to set that option here. */
-			mysql_options(&mysql, MYSQL_OPT_RECONNECT, &trueval);
+			mysql_options(&conn->handle, MYSQL_OPT_RECONNECT, &trueval);
 #endif
 			ast_log(LOG_DEBUG, "MySQL RealTime: Successfully connected to database.\n");
-			connected = 1;
-			connect_time = time(NULL);
+			conn->connected = 1;
+			conn->connect_time = time(NULL);
 			return 1;
 		} else {
-			ast_log(LOG_ERROR, "MySQL RealTime: Failed to connect database server %s on %s (err %d). Check debug for more info.\n", dbname, dbhost, mysql_errno(&mysql));
-			ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect (%d): %s\n", mysql_errno(&mysql), mysql_error(&mysql));
-			connected = 0;
+			ast_log(LOG_ERROR, "MySQL RealTime: Failed to connect database server %s on %s (err %d). Check debug for more info.\n", conn->name, !ast_strlen_zero(conn->host) ? conn->host : conn->sock, mysql_errno(&conn->handle));
+			ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect (%d): %s\n", mysql_errno(&conn->handle), mysql_error(&conn->handle));
+			conn->connected = 0;
 			return 0;
 		}
 	} else {
 		/* MySQL likes to return an error, even if it reconnects successfully.
 		 * So the postman pings twice. */
-		if (mysql_ping(&mysql) != 0 && mysql_ping(&mysql) != 0) {
-			connected = 0;
-			ast_log(LOG_ERROR, "MySQL RealTime: Ping failed (%d).  Trying an explicit reconnect.\n", mysql_errno(&mysql));
-			ast_log(LOG_DEBUG, "MySQL RealTime: Server Error (%d): %s\n", mysql_errno(&mysql), mysql_error(&mysql));
+		if (mysql_ping(&conn->handle) != 0 && mysql_ping(&conn->handle) != 0) {
+			conn->connected = 0;
+			ast_log(LOG_ERROR, "MySQL RealTime: Ping failed (%d).  Trying an explicit reconnect.\n", mysql_errno(&conn->handle));
+			ast_log(LOG_DEBUG, "MySQL RealTime: Server Error (%d): %s\n", mysql_errno(&conn->handle), mysql_error(&conn->handle));
 			goto reconnect_tryagain;
 		}
 
-		connected = 1;
-
-		if (mysql_select_db(&mysql, my_database) != 0) {
-			ast_log(LOG_WARNING, "MySQL RealTime: Unable to select database: %s. Still Connected (%d).\n", my_database, mysql_errno(&mysql));
-			ast_log(LOG_DEBUG, "MySQL RealTime: Database Select Failed (%d): %s\n", mysql_error(&mysql), mysql_errno(&mysql));
+		conn->connected = 1;
+
+		if (mysql_select_db(&conn->handle, conn->name) != 0) {
+			ast_log(LOG_WARNING, "MySQL RealTime: Unable to select database: %s. Still Connected (%d) - %s.\n", conn->name, mysql_errno(&conn->handle), mysql_error(&conn->handle));
 			return 0;
 		}
 
-		ast_log(LOG_DEBUG, "MySQL RealTime: Everything is fine.\n");
+		ast_log(LOG_DEBUG, "MySQL RealTime: Connection okay.\n");
 		return 1;
 	}
 }
@@ -821,37 +841,33 @@
 static int realtime_mysql_status(int fd, int argc, char **argv)
 {
 	char status[256], status2[100] = "";
-	int ctime = time(NULL) - connect_time;
-
-	if (mysql_reconnect(NULL)) {
-		if (dbhost) {
-			snprintf(status, 255, "Connected to %s@%s, port %d", dbname, dbhost, dbport);
-		} else if (dbsock) {
-			snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
-		} else {
-			snprintf(status, 255, "Connected to %s@%s", dbname, dbhost);
-		}
-
-		if (dbuser && *dbuser) {
-			snprintf(status2, 99, " with username %s", dbuser);
-		}
-
-		if (ctime > 31536000) {
-			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);
-		} else if (ctime > 86400) {
-			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);
-		} else if (ctime > 3600) {
-			ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
-		} else if (ctime > 60) {
-			ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
-		} else {
+	int ctime = time(NULL) - dbread.connect_time;
+
+	if (mysql_reconnect(&dbread)) {
+		if (!ast_strlen_zero(dbread.host))
+			snprintf(status, sizeof(status), "Connected to %s@%s, port %d", dbread.name, dbread.host, dbread.port);
+		else
+			snprintf(status, sizeof(status), "Connected to %s on socket file %s", dbread.name, dbread.sock);
+
+		if (!ast_strlen_zero(dbread.user))
+			snprintf(status2, sizeof(status2), " with username %s", dbread.user);
+
+		if (ctime > 31536000)
+			ast_cli(fd, "%s%s for %.1f years.\n", status, status2, (double)ctime / 31536000.0);
+		else if (ctime > 86400 * 30)
+			ast_cli(fd, "%s%s for %d days.\n", status, status2, ctime / 86400);
+		else if (ctime > 86400)
+			ast_cli(fd, "%s%s for %d days, %d hours.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600);
+		else if (ctime > 3600)
+			ast_cli(fd, "%s%s for %d hours, %d minutes.\n", status, status2, ctime / 3600, (ctime % 3600) / 60);
+		else if (ctime > 60)
+			ast_cli(fd, "%s%s for %d minutes.\n", status, status2, ctime / 60);
+		else
 			ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
-		}
 
 		return RESULT_SUCCESS;
-	} else {
+	} else
 		return RESULT_FAILURE;
-	}
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MySQL RealTime Configuration Driver",



More information about the svn-commits mailing list