<p>Tzafrir Cohen has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/7928">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">cdr_mysql: run a full reconnect on log if not connected<br><br>If the MySQL CDR backend is not connected at startup, it will try to<br>reconnect each time it needs to log a record.<br><br>However it dos not run the full connection startup sequence and thus<br>fails to set up the columns to log. As a result all subsequent records<br>will be empty.<br><br>This commit makes the mysql backend run the same connection sequence in<br>that case as it does on module load.<br><br>ASTERISK-27572 #close<br><br>Change-Id: I7603c7501dae7070fac35081cf35161579c47590<br>---<br>M addons/cdr_mysql.c<br>1 file changed, 169 insertions(+), 155 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/28/7928/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c<br>index 00c75dd..f9d1561 100644<br>--- a/addons/cdr_mysql.c<br>+++ b/addons/cdr_mysql.c<br>@@ -161,48 +161,53 @@<br>     }<br> }<br> <br>+static int my_connect_db(struct ast_config *cfg);<br>+<br> static int mysql_log(struct ast_cdr *cdr)<br> {<br>       struct ast_str *sql1 = ast_str_thread_get(&sql1_buf, 1024), *sql2 = ast_str_thread_get(&sql2_buf, 1024);<br>      int retries = 5;<br>-#if MYSQL_VERSION_ID >= 50013<br>-  my_bool my_bool_true = 1;<br>-#endif<br> <br>         if (!sql1 || !sql2) {<br>                 ast_log(LOG_ERROR, "Memory error\n");<br>               return -1;<br>    }<br>+    if (!connected) {<br>+            if (!((hostname || dbsock) && dbuser && password && dbname<br>+                                   && dbtable) ) {<br>+                      ast_debug(1, "Not connected. Cannot reconnect due to missing configuration items.\n");<br>+                     return -1;<br>+           }<br>+    }<br> <br>  ast_mutex_lock(&mysql_lock);<br> <br> db_reconnect:<br>-  if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) {<br>-              /* Attempt to connect */<br>-             mysql_init(&mysql);<br>-              /* Add option to quickly timeout the connection */<br>-           if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout) != 0) {<br>-                    ast_log(LOG_ERROR, "mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));<br>-          }<br>-#if MYSQL_VERSION_ID >= 50013<br>-         /* Add option for automatic reconnection */<br>-          if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {<br>-                        ast_log(LOG_ERROR, "mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));<br>-          }<br>-#endif<br>-           if (ssl_ca || ssl_cert || ssl_key) {<br>-                 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);<br>-         }<br>-<br>-         configure_connection_charset();<br>-<br>-           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)) {<br>-                 connected = 1;<br>-                       connect_time = time(NULL);<br>-                   records = 0;<br>+ if (!connected) {<br>+            struct ast_flags config_flags = { 0 };<br>+               struct ast_config *cfg = ast_config_load(config, config_flags);<br>+              ast_verb(3, "Not connected. Attemptint to re-establish connection to MySQL CDR database.\n");<br>+              if (cfg == CONFIG_STATUS_FILEMISSING) {<br>+                      ast_log(LOG_WARNING, "Unable to load config for mysql CDR's: %s\n", config);<br>+           } else if (cfg == CONFIG_STATUS_FILEINVALID) {<br>+                       ast_log(LOG_ERROR, "Unable to load configuration file '%s'\n", config);<br>             } else {<br>-                     ast_log(LOG_ERROR, "Cannot connect to database server %s: (%d) %s\n", ast_str_buffer(hostname), mysql_errno(&mysql), mysql_error(&mysql));<br>-                 connected = 0;<br>+                       int res;<br>+<br>+                  AST_RWLIST_WRLOCK(&columns);<br>+                     res = my_connect_db(cfg);<br>+                    AST_RWLIST_UNLOCK(&columns);<br>+                     ast_config_destroy(cfg);<br>+<br>+                  if (res == AST_MODULE_LOAD_SUCCESS) {<br>+                                connected = 1;<br>+                               connect_time = time(NULL);<br>+                           records = 0;<br>+                         ast_verb(1, "Re-established connection to MySQL CDR database.\n");<br>+                 } else {<br>+                             ast_verb(3, "Failed to re-establish connection to MySQL CDR database.\n");<br>+                         connected = 0;<br>+                       }<br>             }<br>     } else {<br>              /* Long connection - ping the server */<br>@@ -440,6 +445,139 @@<br>        return 0;<br> }<br> <br>+/** Connect to MySQL. Initializes the connection.<br>+ *<br>+ * * Assumes the read-write lock for columns is held.<br>+ * * Caller should allocate and free cfg<br>+ * */<br>+static int my_connect_db(struct ast_config *cfg)<br>+{<br>+  struct ast_variable *var;<br>+    char *temp;<br>+  MYSQL_ROW row;<br>+       MYSQL_RES *result;<br>+   char sqldesc[128];<br>+#if MYSQL_VERSION_ID >= 50013<br>+        my_bool my_bool_true = 1;<br>+#endif<br>+<br>+        mysql_init(&mysql);<br>+<br>+   if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout) != 0) {<br>+            ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));<br>+       }<br>+<br>+#if MYSQL_VERSION_ID >= 50013<br>+      /* Add option for automatic reconnection */<br>+  if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {<br>+                ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));<br>+       }<br>+#endif<br>+<br>+        if ((ssl_ca && ast_str_strlen(ssl_ca)) || (ssl_cert && ast_str_strlen(ssl_cert)) || (ssl_key && ast_str_strlen(ssl_key))) {<br>+          mysql_ssl_set(&mysql,<br>+                    ssl_key ? ast_str_buffer(ssl_key) : NULL,<br>+                    ssl_cert ? ast_str_buffer(ssl_cert) : NULL,<br>+                  ssl_ca ? ast_str_buffer(ssl_ca) : NULL,<br>+                      NULL, NULL);<br>+ }<br>+    temp = dbsock && ast_str_strlen(dbsock) ? ast_str_buffer(dbsock) : NULL;<br>+<br>+  configure_connection_charset();<br>+<br>+   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)) {<br>+          ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", ast_str_buffer(dbname), ast_str_buffer(hostname));<br>+           connected = 0;<br>+               records = 0;<br>+<br>+              return AST_MODULE_LOAD_SUCCESS; /* May be reconnected later */<br>+       }<br>+<br>+ ast_debug(1, "Successfully connected to MySQL database.\n");<br>+       connected = 1;<br>+       records = 0;<br>+ connect_time = time(NULL);<br>+<br>+        /* Get table description */<br>+  snprintf(sqldesc, sizeof(sqldesc), "DESC %s", dbtable ? ast_str_buffer(dbtable) : "cdr");<br>+        if (mysql_query(&mysql, sqldesc)) {<br>+              ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");<br>+            mysql_close(&mysql);<br>+             connected = 0;<br>+<br>+            return AST_MODULE_LOAD_DECLINE;<br>+      }<br>+<br>+ if (!(result = mysql_store_result(&mysql))) {<br>+            ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");<br>+            mysql_close(&mysql);<br>+             connected = 0;<br>+<br>+            return AST_MODULE_LOAD_DECLINE;<br>+      }<br>+<br>+ while ((row = mysql_fetch_row(result))) {<br>+            struct column *entry;<br>+                char *cdrvar = "", *staticvalue = "";<br>+<br>+         ast_debug(1, "Got a field '%s' of type '%s'\n", row[0], row[1]);<br>+           /* Check for an alias or a static value */<br>+           for (var = ast_variable_browse(cfg, "columns"); var; var = var->next) {<br>+                 if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, row[0]) == 0 ) {<br>+                           char *alias = ast_strdupa(var->name + 5);<br>+                         cdrvar = ast_strip(alias);<br>+                           ast_verb(3, "Found alias %s for column %s\n", cdrvar, row[0]);<br>+                             break;<br>+                       } else if (strncmp(var->name, "static", 6) == 0 && strcasecmp(var->value, row[0]) == 0) {<br>+                            char *item = ast_strdupa(var->name + 6);<br>+                          item = ast_strip(item);<br>+                              if (item[0] == '"' && item[strlen(item) - 1] == '"') {<br>+                                     /* Remove surrounding quotes */<br>+                                      item[strlen(item) - 1] = '\0';<br>+                                       item++;<br>+                              }<br>+                            staticvalue = item;<br>+                  }<br>+            }<br>+<br>+         entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(row[0]) + 1 + strlen(cdrvar) + 1 + strlen(staticvalue) + 1 + strlen(row[1]) + 1);<br>+           if (!entry) {<br>+                        ast_log(LOG_ERROR, "Out of memory creating entry for column '%s'\n", row[0]);<br>+                      return AST_MODULE_LOAD_DECLINE;<br>+              }<br>+<br>+         entry->name = (char *)entry + sizeof(*entry);<br>+             strcpy(entry->name, row[0]);<br>+<br>+           if (!ast_strlen_zero(cdrvar)) {<br>+                      entry->cdrname = entry->name + strlen(row[0]) + 1;<br>+                     strcpy(entry->cdrname, cdrvar);<br>+           } else { /* Point to same place as the column name */<br>+                        entry->cdrname = (char *)entry + sizeof(*entry);<br>+          }<br>+<br>+         if (!ast_strlen_zero(staticvalue)) {<br>+                 entry->staticvalue = entry->cdrname + strlen(entry->cdrname) + 1;<br>+                   strcpy(entry->staticvalue, staticvalue);<br>+                  ast_debug(1, "staticvalue length: %d\n", (int) strlen(staticvalue) );<br>+                      entry->type = entry->staticvalue + strlen(entry->staticvalue) + 1;<br>+          } else {<br>+                     entry->type = entry->cdrname + strlen(entry->cdrname) + 1;<br>+          }<br>+            strcpy(entry->type, row[1]);<br>+<br>+           ast_debug(1, "Entry name '%s'\n", entry->name);<br>+         ast_debug(1, "   cdrname '%s'\n", entry->cdrname);<br>+              ast_debug(1, "    static '%s'\n", entry->staticvalue);<br>+          ast_debug(1, "      type '%s'\n", entry->type);<br>+<br>+              AST_LIST_INSERT_TAIL(&columns, entry, list);<br>+     }<br>+    mysql_free_result(result);<br>+<br>+        return AST_MODULE_LOAD_SUCCESS;<br>+}<br>+<br> static int my_load_module(int reload)<br> {<br>    int res;<br>@@ -450,14 +588,7 @@<br>         * rescan the table layout. */<br>        struct ast_flags config_flags = { 0 };<br>        struct column *entry;<br>-        char *temp;<br>   struct ast_str *compat;<br>-      MYSQL_ROW row;<br>-       MYSQL_RES *result;<br>-   char sqldesc[128];<br>-#if MYSQL_VERSION_ID >= 50013<br>-        my_bool my_bool_true = 1;<br>-#endif<br> <br>         /* Cannot use a conditionally different flag, because the table layout may<br>     * have changed, which is not detectable by config file change detection,<br>@@ -554,129 +685,12 @@<br>             ast_debug(1, "Got DB charset of %s\n", ast_str_buffer(dbcharset));<br>  }<br> <br>- mysql_init(&mysql);<br>-<br>-   if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout) != 0) {<br>-            ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));<br>-       }<br>-<br>-#if MYSQL_VERSION_ID >= 50013<br>-      /* Add option for automatic reconnection */<br>-  if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {<br>-                ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));<br>-       }<br>-#endif<br>-<br>-        if ((ssl_ca && ast_str_strlen(ssl_ca)) || (ssl_cert && ast_str_strlen(ssl_cert)) || (ssl_key && ast_str_strlen(ssl_key))) {<br>-          mysql_ssl_set(&mysql,<br>-                    ssl_key ? ast_str_buffer(ssl_key) : NULL,<br>-                    ssl_cert ? ast_str_buffer(ssl_cert) : NULL,<br>-                  ssl_ca ? ast_str_buffer(ssl_ca) : NULL,<br>-                      NULL, NULL);<br>- }<br>-    temp = dbsock && ast_str_strlen(dbsock) ? ast_str_buffer(dbsock) : NULL;<br>-<br>-  configure_connection_charset();<br>-<br>-   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)) {<br>-          ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", ast_str_buffer(dbname), ast_str_buffer(hostname));<br>-           connected = 0;<br>-               records = 0;<br>- } else {<br>-             ast_debug(1, "Successfully connected to MySQL database.\n");<br>-               connected = 1;<br>-               records = 0;<br>-         connect_time = time(NULL);<br>-<br>-                /* Get table description */<br>-          snprintf(sqldesc, sizeof(sqldesc), "DESC %s", dbtable ? ast_str_buffer(dbtable) : "cdr");<br>-                if (mysql_query(&mysql, sqldesc)) {<br>-                      ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");<br>-                    mysql_close(&mysql);<br>-                     connected = 0;<br>-                       AST_RWLIST_UNLOCK(&columns);<br>-                     ast_config_destroy(cfg);<br>-                     free_strings();<br>-<br>-                   return AST_MODULE_LOAD_DECLINE;<br>-              }<br>-<br>-         if (!(result = mysql_store_result(&mysql))) {<br>-                    ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");<br>-                    mysql_close(&mysql);<br>-                     connected = 0;<br>-                       AST_RWLIST_UNLOCK(&columns);<br>-                     ast_config_destroy(cfg);<br>-                     free_strings();<br>-<br>-                   return AST_MODULE_LOAD_DECLINE;<br>-              }<br>-<br>-         while ((row = mysql_fetch_row(result))) {<br>-                    struct column *entry;<br>-                        char *cdrvar = "", *staticvalue = "";<br>-<br>-                 ast_debug(1, "Got a field '%s' of type '%s'\n", row[0], row[1]);<br>-                   /* Check for an alias or a static value */<br>-                   for (var = ast_variable_browse(cfg, "columns"); var; var = var->next) {<br>-                         if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, row[0]) == 0 ) {<br>-                                   char *alias = ast_strdupa(var->name + 5);<br>-                                 cdrvar = ast_strip(alias);<br>-                                   ast_verb(3, "Found alias %s for column %s\n", cdrvar, row[0]);<br>-                                     break;<br>-                               } else if (strncmp(var->name, "static", 6) == 0 && strcasecmp(var->value, row[0]) == 0) {<br>-                                    char *item = ast_strdupa(var->name + 6);<br>-                                  item = ast_strip(item);<br>-                                      if (item[0] == '"' && item[strlen(item) - 1] == '"') {<br>-                                             /* Remove surrounding quotes */<br>-                                              item[strlen(item) - 1] = '\0';<br>-                                               item++;<br>-                                      }<br>-                                    staticvalue = item;<br>-                          }<br>-                    }<br>-<br>-                 entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(row[0]) + 1 + strlen(cdrvar) + 1 + strlen(staticvalue) + 1 + strlen(row[1]) + 1);<br>-                   if (!entry) {<br>-                                ast_log(LOG_ERROR, "Out of memory creating entry for column '%s'\n", row[0]);<br>-                              res = -1;<br>-                            break;<br>-                       }<br>-<br>-                 entry->name = (char *)entry + sizeof(*entry);<br>-                     strcpy(entry->name, row[0]);<br>-<br>-                   if (!ast_strlen_zero(cdrvar)) {<br>-                              entry->cdrname = entry->name + strlen(row[0]) + 1;<br>-                             strcpy(entry->cdrname, cdrvar);<br>-                   } else { /* Point to same place as the column name */<br>-                                entry->cdrname = (char *)entry + sizeof(*entry);<br>-                  }<br>-<br>-                 if (!ast_strlen_zero(staticvalue)) {<br>-                         entry->staticvalue = entry->cdrname + strlen(entry->cdrname) + 1;<br>-                           strcpy(entry->staticvalue, staticvalue);<br>-                          ast_debug(1, "staticvalue length: %d\n", (int) strlen(staticvalue) );<br>-                              entry->type = entry->staticvalue + strlen(entry->staticvalue) + 1;<br>-                  } else {<br>-                             entry->type = entry->cdrname + strlen(entry->cdrname) + 1;<br>-                  }<br>-                    strcpy(entry->type, row[1]);<br>-<br>-                   ast_debug(1, "Entry name '%s'\n", entry->name);<br>-                 ast_debug(1, "   cdrname '%s'\n", entry->cdrname);<br>-                      ast_debug(1, "    static '%s'\n", entry->staticvalue);<br>-                  ast_debug(1, "      type '%s'\n", entry->type);<br>-<br>-                      AST_LIST_INSERT_TAIL(&columns, entry, list);<br>-             }<br>-            mysql_free_result(result);<br>-   }<br>+    res = my_connect_db(cfg);<br>     AST_RWLIST_UNLOCK(&columns);<br>      ast_config_destroy(cfg);<br>-     if (res < 0) {<br>+    if (res != AST_MODULE_LOAD_SUCCESS) {<br>                 my_unload_module(0);<br>-         return AST_MODULE_LOAD_DECLINE;<br>+              return res;<br>   }<br> <br>  if (!reload) {<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/7928">change 7928</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/7928"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I7603c7501dae7070fac35081cf35161579c47590 </div>
<div style="display:none"> Gerrit-Change-Number: 7928 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Tzafrir Cohen <tzafrir.cohen@xorcom.com> </div>