Index: cdr_tds.c
===================================================================
RCS file: /usr/cvsroot/asterisk/cdr/cdr_tds.c,v
retrieving revision 1.4
diff -u -r1.4 cdr_tds.c
--- cdr_tds.c	13 Aug 2004 20:27:58 -0000	1.4
+++ cdr_tds.c	15 Feb 2005 09:05:30 -0000
@@ -65,6 +65,11 @@
 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;
+static time_t connect_time = 0;
+
 AST_MUTEX_DEFINE_STATIC(tds_lock);
 
 static TDSSOCKET *tds;
@@ -75,11 +80,15 @@
 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 +173,27 @@
 		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 +388,129 @@
 	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_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 +521,69 @@
 
 	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_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()
