[PATCH] Configurable TCP KeepAlives

"Andrew Victor" <[email protected]>
Newsgroups gmane.comp.db.tds.freetds
Message-ID <[email protected]>
hi,

The TCP KeepAlive is currently enabled, but uses the standard OS
setting of 2 hours.
It can be useful to detect sooner if the SQL server has disappeared or
closed the connection.

The attached patch allows the TCP KeepAlive settings to be
configurable via the freetds.conf file.
The new settings are:
   keepalive idle             (seconds)
   keepalive interval      (seconds)
   keepalive count         (counter)

If any of the above values are not configured, then the OS default will be used.


Regards,
  Andrew Victor

_______________________________________________
FreeTDS mailing list
[email protected]
http://lists.ibiblio.org/mailman/listinfo/freetds
keepalive.patch (text/x-patch, 5.3 KB)
diff -urN freetds-0.82/include/tds.h freetds-0.82.new/include/tds.h
--- freetds-0.82/include/tds.h	2008-08-07 17:40:59.000000000 +0200
+++ freetds-0.82.new/include/tds.h	2008-08-07 17:41:46.000000000 +0200
@@ -806,6 +806,10 @@
 #define TDS_STR_ENCRYPTION_OFF	 "off"
 #define TDS_STR_ENCRYPTION_REQUEST "request"
 #define TDS_STR_ENCRYPTION_REQUIRE "require"
+/* keepalive */
+#define TDS_KEEPALIVE_IDLE "keepalive idle"
+#define TDS_KEEPALIVE_INTERVAL "keepalive interval"
+#define TDS_KEEPALIVE_COUNT "keepalive count"
 
 
 /* TODO do a better check for alignment than this */
@@ -878,6 +882,11 @@
 	int broken_dates;
 	int broken_money;
 	int emul_little_endian;
+
+	/* tcp keepalive */
+	int keepalive_idle;
+	int keepalive_interval;
+	int keepalive_count;
 } TDSCONNECTION;
 
 typedef struct tds_locale
@@ -1329,6 +1338,10 @@
 	/* timeout stuff from Jeff */
 	TDS_INT query_timeout;
 	TDSENV env;
+	/* keepalive info */
+	int keepalive_idle;
+	int keepalive_interval;
+	int keepalive_count;
 
 	/* dynamic placeholder stuff */
 	/*@dependent@*/ TDSDYNAMIC *cur_dyn;	/**< dynamic structure in use */
diff -urN freetds-0.82/src/tds/config.c freetds-0.82.new/src/tds/config.c
--- freetds-0.82/src/tds/config.c	2007-12-23 23:12:02.000000000 +0200
+++ freetds-0.82.new/src/tds/config.c	2008-08-07 17:30:53.000000000 +0200
@@ -532,6 +532,12 @@
 		tds_dstr_copy(&connection->instance_name, value);
 	} else if (!strcmp(option, TDS_STR_ENCRYPTION)) {
 		tds_config_encryption(value, connection);
+	} else if (!strcmp(option, TDS_KEEPALIVE_IDLE)) {
+		connection->keepalive_idle = atoi(value);
+	} else if (!strcmp(option, TDS_KEEPALIVE_INTERVAL)) {
+		connection->keepalive_interval = atoi(value);
+	} else if (!strcmp(option, TDS_KEEPALIVE_COUNT)) {
+		connection->keepalive_count = atoi(value);
 	} else {
 		tdsdump_log(TDS_DBG_INFO1, "UNRECOGNIZED option '%s' ... ignoring.\n", option);
 	}
diff -urN freetds-0.82/src/tds/login.c freetds-0.82.new/src/tds/login.c
--- freetds-0.82/src/tds/login.c	2007-12-31 12:06:50.000000000 +0200
+++ freetds-0.82.new/src/tds/login.c	2008-08-07 17:31:21.000000000 +0200
@@ -399,6 +399,11 @@
 	/* Jeff's hack - begin */
 	tds->query_timeout = connect_timeout ? connect_timeout : connection->query_timeout;
 	/* end */
+
+	/* setup keepalive times */
+	tds->keepalive_idle = connection->keepalive_idle;
+	tds->keepalive_interval = connection->keepalive_interval;
+	tds->keepalive_count = connection->keepalive_count;
 
 	/* verify that ip_addr is not empty */
 	if (tds_dstr_isempty(&connection->ip_addr)) {
diff -urN freetds-0.82/src/tds/mem.c freetds-0.82.new/src/tds/mem.c
--- freetds-0.82/src/tds/mem.c	2007-12-31 12:06:50.000000000 +0200
+++ freetds-0.82.new/src/tds/mem.c	2008-08-07 17:39:01.000000000 +0200
@@ -747,6 +747,9 @@
 	connection->minor_version = TDS_DEF_MINOR;
 	connection->port = TDS_DEF_PORT;
 	connection->block_size = 0;
+	connection->keepalive_idle = 0;
+	connection->keepalive_interval = 0;
+	connection->keepalive_count = 0;
 	/* TODO use system default ?? */
 	if (!tds_dstr_copy(&connection->client_charset, "ISO-8859-1"))
 		goto Cleanup;
@@ -975,6 +978,10 @@
 	tds_socket->s = INVALID_SOCKET;
 	tds_socket->state = TDS_DEAD;
 	tds_socket->env_chg_func = NULL;
+	/* keepalive */
+	tds_socket->keepalive_idle = 0;
+	tds_socket->keepalive_interval = 0;
+	tds_socket->keepalive_count = 0;
 	return tds_socket;
       Cleanup:
 	tds_free_socket(tds_socket);
diff -urN freetds-0.82/src/tds/net.c freetds-0.82.new/src/tds/net.c
--- freetds-0.82/src/tds/net.c	2008-08-07 17:40:59.000000000 +0200
+++ freetds-0.82.new/src/tds/net.c	2008-08-07 17:40:12.000000000 +0200
@@ -220,6 +220,27 @@
 #ifdef SO_KEEPALIVE
 	len = 1;
 	setsockopt(tds->s, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len));
+
+	/* Amount to time before starting to send keepalives */
+	if (tds->keepalive_idle > 0) {
+		tdsdump_log(TDS_DBG_NETWORK, "TDS: Setting keeplive idle interval: %i\n", tds->keepalive_idle);
+		len = tds->keepalive_idle;
+		setsockopt(tds->s, SOL_TCP, TCP_KEEPIDLE, (const void *) &len, sizeof(len));
+	}
+
+	/* Interval at which to send keepalive packets */
+	if (tds->keepalive_interval > 0) {
+		tdsdump_log(TDS_DBG_NETWORK, "TDS: Setting keeplive probe interval: %i\n", tds->keepalive_interval);
+		len = tds->keepalive_interval;
+		setsockopt(tds->s, SOL_TCP, TCP_KEEPINTVL, (const void *) &len, sizeof(len));
+	}
+
+	/* Number of keepalive packets to send */
+	if (tds->keepalive_count > 0) {
+		tdsdump_log(TDS_DBG_NETWORK, "TDS: Setting keeplive probe count: %i\n", tds->keepalive_count);
+		len = tds->keepalive_count;
+		setsockopt(tds->s, SOL_TCP, TCP_KEEPCNT, (const void *) &len, sizeof(len));
+	}
 #endif
 
 	len = 1;
@@ -300,6 +321,24 @@
 		goto not_available;
 	}
 
+#ifdef SO_KEEPALIVE
+	len = 0;
+	getsockopt(tds->s, SOL_SOCKET, SO_KEEPALIVE, (void *) &len, &optlen);
+	tdsdump_log(TDS_DBG_NETWORK, "TDS: KeepAlives: %s\n", (len) ? "yes" : "no");
+
+	len = 0;
+	getsockopt(tds->s, SOL_TCP, TCP_KEEPIDLE, (void *) &len, &optlen);
+	tdsdump_log(TDS_DBG_NETWORK, "TDS: KeepAlive Idle: %i\n", len);
+
+	len = 0;
+	getsockopt(tds->s, SOL_TCP, TCP_KEEPINTVL, (void *) &len, &optlen);
+	tdsdump_log(TDS_DBG_NETWORK, "TDS: KeepAlive Interval: %i\n", len);
+
+	len = 0;
+	getsockopt(tds->s, SOL_TCP, TCP_KEEPCNT, (void *) &len, &optlen);
+	tdsdump_log(TDS_DBG_NETWORK, "TDS: KeepAlive Count: %i\n", len);
+#endif
+
 	tdsdump_log(TDS_DBG_ERROR, "tds_open_socket() succeeded\n");
 	return TDS_SUCCEED;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.