Make TDS CDR more resilient (bug #3597)
authorMark Spencer <markster@digium.com>
Wed, 16 Feb 2005 03:52:47 +0000 (03:52 +0000)
committerMark Spencer <markster@digium.com>
Wed, 16 Feb 2005 03:52:47 +0000 (03:52 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5037 65c4cc65-6c06-0410-ace0-fbb531ad65f3

cdr/cdr_tds.c

index 15a7be8..c70e62e 100755 (executable)
@@ -65,6 +65,10 @@ static char *desc = "MSSQL CDR Backend";
 static char *name = "mssql";
 static char *config = "cdr_tds.conf";
 
+static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *charset = NULL, *language = NULL;
+
+static int connected = 0;
+
 AST_MUTEX_DEFINE_STATIC(tds_lock);
 
 static TDSSOCKET *tds;
@@ -75,11 +79,15 @@ static char *stristr(const char*, const char*);
 static char *anti_injection(const char *, int);
 static void get_date(char *, struct timeval);
 
+static int mssql_connect(void);
+static int mssql_disconnect(void);
+
 static int tds_log(struct ast_cdr *cdr)
 {
        char sqlcmd[2048], start[80], answer[80], end[80];
        char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid;
        int res = 0;
+       int retried = 0;
 #ifdef TDS_PRE_0_62
        TDS_INT result_type;
 #endif
@@ -164,16 +172,27 @@ static int tds_log(struct ast_cdr *cdr)
                uniqueid
        );
 
+       do {
+               if (!connected) {
+                       if (mssql_connect())
+                               ast_log(LOG_ERROR, "Failed to reconnect to SQL database.\n");
+                       else
+                               ast_log(LOG_WARNING, "Reconnected to SQL database.\n");
+
+                       retried = 1;    /* note that we have now tried */
+               }
+
 #ifdef TDS_PRE_0_62
-       if ((tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
+               if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
 #else
-       if ((tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
+               if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
 #endif
-       {
-               ast_log(LOG_ERROR, "Failed to insert record into database.\n");
+               {
+                       ast_log(LOG_ERROR, "Failed to insert Call Data Record into SQL database.\n");
 
-               res = -1;
-       }
+                       mssql_disconnect();     /* this is ok even if we are already disconnected */
+               }
+       } while (!connected && !retried);
 
        free(accountcode);
        free(src);
@@ -368,32 +387,129 @@ char *description(void)
        return desc;
 }
 
+static int mssql_disconnect(void)
+{
+       if (tds) {
+               tds_free_socket(tds);
+               tds = NULL;
+       }
+
+       if (context) {
+               tds_free_context(context);
+               context = NULL;
+       }
+
+       if (login) {
+               tds_free_login(login);
+               login = NULL;
+       }
+
+       connected = 0;
+
+       return 0;
+}
+
+static int mssql_connect(void)
+{
+       TDSCONNECTINFO *connection = NULL;
+       char query[128];
+
+       /* Connect to M$SQL Server */
+       if (!(login = tds_alloc_login()))
+       {
+               ast_log(LOG_ERROR, "tds_alloc_login() failed.\n");
+               return -1;
+       }
+       
+       tds_set_server(login, hostname);
+       tds_set_user(login, dbuser);
+       tds_set_passwd(login, password);
+       tds_set_app(login, "TSQL");
+       tds_set_library(login, "TDS-Library");
+#ifndef TDS_PRE_0_62
+       tds_set_client_charset(login, charset);
+#endif
+       tds_set_language(login, language);
+       tds_set_packet(login, 512);
+       tds_set_version(login, 7, 0);
+
+       if (!(context = tds_alloc_context()))
+       {
+               ast_log(LOG_ERROR, "tds_alloc_context() failed.\n");
+               goto connect_fail;
+       }
+
+       if (!(tds = tds_alloc_socket(context, 512))) {
+               ast_log(LOG_ERROR, "tds_alloc_socket() failed.\n");
+               goto connect_fail;
+       }
+
+       tds_set_parent(tds, NULL);
+       connection = tds_read_config_info(tds, login, context->locale);
+       if (!connection)
+       {
+               ast_log(LOG_ERROR, "tds_read_config() failed.\n");
+               goto connect_fail;
+       }
+
+       if (tds_connect(tds, connection) == TDS_FAIL)
+       {
+               ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n");
+               tds = NULL;     /* freed by tds_connect() on error */
+               tds_free_connect(connection);
+               connection = NULL;
+               goto connect_fail;
+       }
+       tds_free_connect(connection);
+       connection = NULL;
+
+       sprintf(query, "USE %s", dbname);
+#ifdef TDS_PRE_0_62
+       if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
+#else
+       if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
+#endif
+       {
+               ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname);
+               goto connect_fail;
+       }
+
+       connected = 1;
+       return 0;
+
+connect_fail:
+       mssql_disconnect();
+       return -1;
+}
+
 int unload_module(void)
 {
-       tds_free_socket(tds);
-       tds_free_login(login);
-       tds_free_context(context);
+       mssql_disconnect();
 
        ast_cdr_unregister(name);
 
+       if (hostname) free(hostname);
+       if (dbname) free(dbname);
+       if (dbuser) free(dbuser);
+       if (password) free(password);
+       if (charset) free(charset);
+       if (language) free(language);
+
        return 0;
 }
 
 int load_module(void)
 {
-       TDSCONNECTINFO *connection;
        int res = 0;
        struct ast_config *cfg;
        struct ast_variable *var;
-       char query[1024], *ptr = NULL;
-       char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *charset = NULL, *language = NULL;
+       char *ptr = NULL;
 #ifdef TDS_PRE_0_62
        TDS_INT result_type;
 #endif
 
        cfg = ast_config_load(config);
-       if (!cfg)
-       {
+       if (!cfg) {
                ast_log(LOG_NOTICE, "Unable to load config for MSSQL CDR's: %s\n", config);
                return 0;
        }
@@ -404,133 +520,69 @@ int load_module(void)
 
        ptr = ast_variable_retrieve(cfg, "global", "hostname");
        if (ptr)
-       {
-               hostname = strdupa(ptr);
-       }
+               hostname = strdup(ptr);
        else
-       {
                ast_log(LOG_ERROR,"Database server hostname not specified.\n");
-       }
 
        ptr = ast_variable_retrieve(cfg, "global", "dbname");
        if (ptr)
-       {
-               dbname = strdupa(ptr);
-       }
+               dbname = strdup(ptr);
        else
-       {
                ast_log(LOG_ERROR,"Database dbname not specified.\n");
-       }
 
        ptr = ast_variable_retrieve(cfg, "global", "user");
        if (ptr)
-       {
-               dbuser = strdupa(ptr);
-       }
+               dbuser = strdup(ptr);
        else
-       {
                ast_log(LOG_ERROR,"Database dbuser not specified.\n");
-       }
 
        ptr = ast_variable_retrieve(cfg, "global", "password");
        if (ptr)
-       {
-               password = strdupa(ptr);
-       }
+               password = strdup(ptr);
        else
-       {
                ast_log(LOG_ERROR,"Database password not specified.\n");
-       }
 
        ptr = ast_variable_retrieve(cfg, "global", "charset");
        if (ptr)
-       {
-               charset = strdupa(ptr);
-       }
+               charset = strdup(ptr);
        else
-       {
-               charset = strdupa("iso_1");
-       }
+               charset = strdup("iso_1");
 
        ptr = ast_variable_retrieve(cfg, "global", "language");
        if (ptr)
-       {
-               language = strdupa(ptr);
-       }
+               language = strdup(ptr);
        else
-       {
-               language = strdupa("us_english");
-       }
+               language = strdup("us_english");
 
        ast_config_destroy(cfg);
 
-       /* Connect to M$SQL Server */
-       if (!(login = tds_alloc_login()))
+       mssql_connect();
+
+       /* Register MSSQL CDR handler */
+       res = ast_cdr_register(name, desc, tds_log);
+       if (res)
        {
-               ast_log(LOG_ERROR, "tds_alloc_login() failed.\n");
-               res = -1;
+               ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n");
        }
-       else
-       {
-               tds_set_server(login, hostname);
-               tds_set_user(login, dbuser);
-               tds_set_passwd(login, password);
-               tds_set_app(login, "TSQL");
-               tds_set_library(login, "TDS-Library");
-#ifndef TDS_PRE_0_62
-               tds_set_client_charset(login, charset);
-#endif
-               tds_set_language(login, language);
-               tds_set_packet(login, 512);
-               tds_set_version(login, 7, 0);
-
-               context = tds_alloc_context();
-               tds = tds_alloc_socket(context, 512);
-
-               tds_set_parent(tds, NULL);
-               connection = tds_read_config_info(NULL, login, context->locale);
-               if (!connection || tds_connect(tds, connection) == TDS_FAIL)
-               {
-                       ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n");
-                       res = -1;
-               }
-               tds_free_connect(connection);
 
-               if (!res)
-               {
-                       memset(query, 0, sizeof(query));
-                       sprintf(query, "USE %s", dbname);
-#ifdef TDS_PRE_0_62
-                       if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
-#else
-                       if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
-#endif
-                       {
-                               ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname);
-                               res = -1;
-                       }
-                       else
-                       {
-                               /* Register MSSQL CDR handler */
-                               res = ast_cdr_register(name, desc, tds_log);
-                               if (res)
-                               {
-                                       ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n");
-                               }
-                       }
-               }
-       }
        return res;
 }
 
 int reload(void)
 {
-       return 0;
+       unload_module();
+       return load_module();
 }
 
 int usecount(void)
 {
-       return 0;
+       /* Simplistic use count */
+       if (ast_mutex_trylock(&tds_lock)) {
+               return 1;
+       } else {
+               ast_mutex_unlock(&tds_lock);
+               return 0;
+       }
 }
 
 char *key()