[Asterisk-code-review] cdr mysql: run a full reconnect on log if not connected (asterisk[master])

Tzafrir Cohen asteriskteam at digium.com
Thu Jan 11 07:03:32 CST 2018


Tzafrir Cohen has uploaded this change for review. ( https://gerrit.asterisk.org/7928


Change subject: cdr_mysql: run a full reconnect on log if not connected
......................................................................

cdr_mysql: run a full reconnect on log if not connected

If the MySQL CDR backend is not connected at startup, it will try to
reconnect each time it needs to log a record.

However it dos not run the full connection startup sequence and thus
fails to set up the columns to log. As a result all subsequent records
will be empty.

This commit makes the mysql backend run the same connection sequence in
that case as it does on module load.

ASTERISK-27572 #close

Change-Id: I7603c7501dae7070fac35081cf35161579c47590
---
M addons/cdr_mysql.c
1 file changed, 169 insertions(+), 155 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/28/7928/1

diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c
index 00c75dd..f9d1561 100644
--- a/addons/cdr_mysql.c
+++ b/addons/cdr_mysql.c
@@ -161,48 +161,53 @@
 	}
 }
 
+static int my_connect_db(struct ast_config *cfg);
+
 static int mysql_log(struct ast_cdr *cdr)
 {
 	struct ast_str *sql1 = ast_str_thread_get(&sql1_buf, 1024), *sql2 = ast_str_thread_get(&sql2_buf, 1024);
 	int retries = 5;
-#if MYSQL_VERSION_ID >= 50013
-	my_bool my_bool_true = 1;
-#endif
 
 	if (!sql1 || !sql2) {
 		ast_log(LOG_ERROR, "Memory error\n");
 		return -1;
 	}
+	if (!connected) {
+		if (!((hostname || dbsock) && dbuser && password && dbname
+					&& dbtable) ) {
+			ast_debug(1, "Not connected. Cannot reconnect due to missing configuration items.\n");
+			return -1;
+		}
+	}
 
 	ast_mutex_lock(&mysql_lock);
 
 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, "mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
-		}
-#if MYSQL_VERSION_ID >= 50013
-		/* Add option for automatic reconnection */
-		if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {
-			ast_log(LOG_ERROR, "mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
-		}
-#endif
-		if (ssl_ca || ssl_cert || ssl_key) {
-			mysql_ssl_set(&mysql, ssl_key ? ast_str_buffer(ssl_key) : NULL, ssl_cert ? ast_str_buffer(ssl_cert) : NULL, ssl_ca ? ast_str_buffer(ssl_ca) : NULL, NULL, NULL);
-		}
-
-		configure_connection_charset();
-
-		if (mysql_real_connect(&mysql, ast_str_buffer(hostname), ast_str_buffer(dbuser), ast_str_buffer(password), ast_str_buffer(dbname), dbport, dbsock && ast_str_strlen(dbsock) ? ast_str_buffer(dbsock) : NULL, ssl_ca ? CLIENT_SSL : 0)) {
-			connected = 1;
-			connect_time = time(NULL);
-			records = 0;
+	if (!connected) {
+		struct ast_flags config_flags = { 0 };
+		struct ast_config *cfg = ast_config_load(config, config_flags);
+		ast_verb(3, "Not connected. Attemptint to re-establish connection to MySQL CDR database.\n");
+		if (cfg == CONFIG_STATUS_FILEMISSING) {
+			ast_log(LOG_WARNING, "Unable to load config for mysql CDR's: %s\n", config);
+		} else if (cfg == CONFIG_STATUS_FILEINVALID) {
+			ast_log(LOG_ERROR, "Unable to load configuration file '%s'\n", config);
 		} else {
-			ast_log(LOG_ERROR, "Cannot connect to database server %s: (%d) %s\n", ast_str_buffer(hostname), mysql_errno(&mysql), mysql_error(&mysql));
-			connected = 0;
+			int res;
+
+			AST_RWLIST_WRLOCK(&columns);
+			res = my_connect_db(cfg);
+			AST_RWLIST_UNLOCK(&columns);
+			ast_config_destroy(cfg);
+
+			if (res == AST_MODULE_LOAD_SUCCESS) {
+				connected = 1;
+				connect_time = time(NULL);
+				records = 0;
+				ast_verb(1, "Re-established connection to MySQL CDR database.\n");
+			} else {
+				ast_verb(3, "Failed to re-establish connection to MySQL CDR database.\n");
+				connected = 0;
+			}
 		}
 	} else {
 		/* Long connection - ping the server */
@@ -440,6 +445,139 @@
 	return 0;
 }
 
+/** Connect to MySQL. Initializes the connection.
+ *
+ * * Assumes the read-write lock for columns is held.
+ * * Caller should allocate and free cfg
+ * */
+static int my_connect_db(struct ast_config *cfg)
+{
+	struct ast_variable *var;
+	char *temp;
+	MYSQL_ROW row;
+	MYSQL_RES *result;
+	char sqldesc[128];
+#if MYSQL_VERSION_ID >= 50013
+	my_bool my_bool_true = 1;
+#endif
+
+	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_VERSION_ID >= 50013
+	/* Add option for automatic reconnection */
+	if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {
+		ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
+	}
+#endif
+
+	if ((ssl_ca && ast_str_strlen(ssl_ca)) || (ssl_cert && ast_str_strlen(ssl_cert)) || (ssl_key && ast_str_strlen(ssl_key))) {
+		mysql_ssl_set(&mysql,
+			ssl_key ? ast_str_buffer(ssl_key) : NULL,
+			ssl_cert ? ast_str_buffer(ssl_cert) : NULL,
+			ssl_ca ? ast_str_buffer(ssl_ca) : NULL,
+			NULL, NULL);
+	}
+	temp = dbsock && ast_str_strlen(dbsock) ? ast_str_buffer(dbsock) : NULL;
+
+	configure_connection_charset();
+
+	if (!mysql_real_connect(&mysql, ast_str_buffer(hostname), ast_str_buffer(dbuser), ast_str_buffer(password), ast_str_buffer(dbname), dbport, temp, ssl_ca && ast_str_strlen(ssl_ca) ? CLIENT_SSL : 0)) {
+		ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", ast_str_buffer(dbname), ast_str_buffer(hostname));
+		connected = 0;
+		records = 0;
+
+		return AST_MODULE_LOAD_SUCCESS;	/* May be reconnected later */
+	}
+
+	ast_debug(1, "Successfully connected to MySQL database.\n");
+	connected = 1;
+	records = 0;
+	connect_time = time(NULL);
+
+	/* Get table description */
+	snprintf(sqldesc, sizeof(sqldesc), "DESC %s", dbtable ? ast_str_buffer(dbtable) : "cdr");
+	if (mysql_query(&mysql, sqldesc)) {
+		ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");
+		mysql_close(&mysql);
+		connected = 0;
+
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	if (!(result = mysql_store_result(&mysql))) {
+		ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");
+		mysql_close(&mysql);
+		connected = 0;
+
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	while ((row = mysql_fetch_row(result))) {
+		struct column *entry;
+		char *cdrvar = "", *staticvalue = "";
+
+		ast_debug(1, "Got a field '%s' of type '%s'\n", row[0], row[1]);
+		/* Check for an alias or a static value */
+		for (var = ast_variable_browse(cfg, "columns"); var; var = var->next) {
+			if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, row[0]) == 0 ) {
+				char *alias = ast_strdupa(var->name + 5);
+				cdrvar = ast_strip(alias);
+				ast_verb(3, "Found alias %s for column %s\n", cdrvar, row[0]);
+				break;
+			} else if (strncmp(var->name, "static", 6) == 0 && strcasecmp(var->value, row[0]) == 0) {
+				char *item = ast_strdupa(var->name + 6);
+				item = ast_strip(item);
+				if (item[0] == '"' && item[strlen(item) - 1] == '"') {
+					/* Remove surrounding quotes */
+					item[strlen(item) - 1] = '\0';
+					item++;
+				}
+				staticvalue = item;
+			}
+		}
+
+		entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(row[0]) + 1 + strlen(cdrvar) + 1 + strlen(staticvalue) + 1 + strlen(row[1]) + 1);
+		if (!entry) {
+			ast_log(LOG_ERROR, "Out of memory creating entry for column '%s'\n", row[0]);
+			return AST_MODULE_LOAD_DECLINE;
+		}
+
+		entry->name = (char *)entry + sizeof(*entry);
+		strcpy(entry->name, row[0]);
+
+		if (!ast_strlen_zero(cdrvar)) {
+			entry->cdrname = entry->name + strlen(row[0]) + 1;
+			strcpy(entry->cdrname, cdrvar);
+		} else { /* Point to same place as the column name */
+			entry->cdrname = (char *)entry + sizeof(*entry);
+		}
+
+		if (!ast_strlen_zero(staticvalue)) {
+			entry->staticvalue = entry->cdrname + strlen(entry->cdrname) + 1;
+			strcpy(entry->staticvalue, staticvalue);
+			ast_debug(1, "staticvalue length: %d\n", (int) strlen(staticvalue) );
+			entry->type = entry->staticvalue + strlen(entry->staticvalue) + 1;
+		} else {
+			entry->type = entry->cdrname + strlen(entry->cdrname) + 1;
+		}
+		strcpy(entry->type, row[1]);
+
+		ast_debug(1, "Entry name '%s'\n", entry->name);
+		ast_debug(1, "   cdrname '%s'\n", entry->cdrname);
+		ast_debug(1, "    static '%s'\n", entry->staticvalue);
+		ast_debug(1, "      type '%s'\n", entry->type);
+
+		AST_LIST_INSERT_TAIL(&columns, entry, list);
+	}
+	mysql_free_result(result);
+
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
 static int my_load_module(int reload)
 {
 	int res;
@@ -450,14 +588,7 @@
 	 * rescan the table layout. */
 	struct ast_flags config_flags = { 0 };
 	struct column *entry;
-	char *temp;
 	struct ast_str *compat;
-	MYSQL_ROW row;
-	MYSQL_RES *result;
-	char sqldesc[128];
-#if MYSQL_VERSION_ID >= 50013
-	my_bool my_bool_true = 1;
-#endif
 
 	/* Cannot use a conditionally different flag, because the table layout may
 	 * have changed, which is not detectable by config file change detection,
@@ -554,129 +685,12 @@
 		ast_debug(1, "Got DB charset of %s\n", ast_str_buffer(dbcharset));
 	}
 
-	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_VERSION_ID >= 50013
-	/* Add option for automatic reconnection */
-	if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {
-		ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
-	}
-#endif
-
-	if ((ssl_ca && ast_str_strlen(ssl_ca)) || (ssl_cert && ast_str_strlen(ssl_cert)) || (ssl_key && ast_str_strlen(ssl_key))) {
-		mysql_ssl_set(&mysql,
-			ssl_key ? ast_str_buffer(ssl_key) : NULL,
-			ssl_cert ? ast_str_buffer(ssl_cert) : NULL,
-			ssl_ca ? ast_str_buffer(ssl_ca) : NULL,
-			NULL, NULL);
-	}
-	temp = dbsock && ast_str_strlen(dbsock) ? ast_str_buffer(dbsock) : NULL;
-
-	configure_connection_charset();
-
-	if (!mysql_real_connect(&mysql, ast_str_buffer(hostname), ast_str_buffer(dbuser), ast_str_buffer(password), ast_str_buffer(dbname), dbport, temp, ssl_ca && ast_str_strlen(ssl_ca) ? CLIENT_SSL : 0)) {
-		ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", ast_str_buffer(dbname), ast_str_buffer(hostname));
-		connected = 0;
-		records = 0;
-	} else {
-		ast_debug(1, "Successfully connected to MySQL database.\n");
-		connected = 1;
-		records = 0;
-		connect_time = time(NULL);
-
-		/* Get table description */
-		snprintf(sqldesc, sizeof(sqldesc), "DESC %s", dbtable ? ast_str_buffer(dbtable) : "cdr");
-		if (mysql_query(&mysql, sqldesc)) {
-			ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");
-			mysql_close(&mysql);
-			connected = 0;
-			AST_RWLIST_UNLOCK(&columns);
-			ast_config_destroy(cfg);
-			free_strings();
-
-			return AST_MODULE_LOAD_DECLINE;
-		}
-
-		if (!(result = mysql_store_result(&mysql))) {
-			ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");
-			mysql_close(&mysql);
-			connected = 0;
-			AST_RWLIST_UNLOCK(&columns);
-			ast_config_destroy(cfg);
-			free_strings();
-
-			return AST_MODULE_LOAD_DECLINE;
-		}
-
-		while ((row = mysql_fetch_row(result))) {
-			struct column *entry;
-			char *cdrvar = "", *staticvalue = "";
-
-			ast_debug(1, "Got a field '%s' of type '%s'\n", row[0], row[1]);
-			/* Check for an alias or a static value */
-			for (var = ast_variable_browse(cfg, "columns"); var; var = var->next) {
-				if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, row[0]) == 0 ) {
-					char *alias = ast_strdupa(var->name + 5);
-					cdrvar = ast_strip(alias);
-					ast_verb(3, "Found alias %s for column %s\n", cdrvar, row[0]);
-					break;
-				} else if (strncmp(var->name, "static", 6) == 0 && strcasecmp(var->value, row[0]) == 0) {
-					char *item = ast_strdupa(var->name + 6);
-					item = ast_strip(item);
-					if (item[0] == '"' && item[strlen(item) - 1] == '"') {
-						/* Remove surrounding quotes */
-						item[strlen(item) - 1] = '\0';
-						item++;
-					}
-					staticvalue = item;
-				}
-			}
-
-			entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(row[0]) + 1 + strlen(cdrvar) + 1 + strlen(staticvalue) + 1 + strlen(row[1]) + 1);
-			if (!entry) {
-				ast_log(LOG_ERROR, "Out of memory creating entry for column '%s'\n", row[0]);
-				res = -1;
-				break;
-			}
-
-			entry->name = (char *)entry + sizeof(*entry);
-			strcpy(entry->name, row[0]);
-
-			if (!ast_strlen_zero(cdrvar)) {
-				entry->cdrname = entry->name + strlen(row[0]) + 1;
-				strcpy(entry->cdrname, cdrvar);
-			} else { /* Point to same place as the column name */
-				entry->cdrname = (char *)entry + sizeof(*entry);
-			}
-
-			if (!ast_strlen_zero(staticvalue)) {
-				entry->staticvalue = entry->cdrname + strlen(entry->cdrname) + 1;
-				strcpy(entry->staticvalue, staticvalue);
-				ast_debug(1, "staticvalue length: %d\n", (int) strlen(staticvalue) );
-				entry->type = entry->staticvalue + strlen(entry->staticvalue) + 1;
-			} else {
-				entry->type = entry->cdrname + strlen(entry->cdrname) + 1;
-			}
-			strcpy(entry->type, row[1]);
-
-			ast_debug(1, "Entry name '%s'\n", entry->name);
-			ast_debug(1, "   cdrname '%s'\n", entry->cdrname);
-			ast_debug(1, "    static '%s'\n", entry->staticvalue);
-			ast_debug(1, "      type '%s'\n", entry->type);
-
-			AST_LIST_INSERT_TAIL(&columns, entry, list);
-		}
-		mysql_free_result(result);
-	}
+	res = my_connect_db(cfg);
 	AST_RWLIST_UNLOCK(&columns);
 	ast_config_destroy(cfg);
-	if (res < 0) {
+	if (res != AST_MODULE_LOAD_SUCCESS) {
 		my_unload_module(0);
-		return AST_MODULE_LOAD_DECLINE;
+		return res;
 	}
 
 	if (!reload) {

-- 
To view, visit https://gerrit.asterisk.org/7928
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I7603c7501dae7070fac35081cf35161579c47590
Gerrit-Change-Number: 7928
Gerrit-PatchSet: 1
Gerrit-Owner: Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20180111/1d057166/attachment-0001.html>


More information about the asterisk-code-review mailing list