From ad0cdfe1c346e5778b82ab3d06b4ff2ba7a8c4f9 Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Thu, 13 Aug 2009 01:40:55 +0000
Subject: [PATCH] Introduce options to configure tcp-keepalive settings per
 connection. These settings only work on Linux and are ignore when not
 supported (see

---
 libraries/libldap/init.c     |  3 +++
 libraries/libldap/ldap-int.h |  8 ++++++
 libraries/libldap/options.c  | 25 ++++++++++++++++++
 libraries/libldap/os-ip.c    | 51 ++++++++++++++++++++++++++++++++++++
 4 files changed, 87 insertions(+)

diff --git a/libraries/libldap/init.c b/libraries/libldap/init.c
index 8cf2530b39..d21f44bb79 100644
--- a/libraries/libldap/init.c
+++ b/libraries/libldap/init.c
@@ -545,6 +545,9 @@ void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl
 	gopts->ldo_tls_connect_arg = NULL;
 	gopts->ldo_tls_require_cert = LDAP_OPT_X_TLS_DEMAND;
 #endif
+	gopts->ldo_keepalive_probes = 0;
+	gopts->ldo_keepalive_interval = 0;
+	gopts->ldo_keepalive_idle = 0;
 
 	gopts->ldo_valid = LDAP_INITIALIZED;
    	return;
diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h
index 883566f429..6c5b22e1d8 100644
--- a/libraries/libldap/ldap-int.h
+++ b/libraries/libldap/ldap-int.h
@@ -244,6 +244,14 @@ struct ldapoptions {
 	unsigned ldo_gssapi_options;
 #endif
 
+	/*
+	 * Per connection tcp-keepalive settings (Linux only,
+	 * ignored where unsupported)
+	 */
+	ber_int_t ldo_keepalive_idle;
+	ber_int_t ldo_keepalive_probes;
+	ber_int_t ldo_keepalive_interval;
+
 	int		ldo_refhoplimit;	/* limit on referral nesting */
 
 	/* LDAPv3 server and client controls */
diff --git a/libraries/libldap/options.c b/libraries/libldap/options.c
index 0b25aa6946..e9ae6d4da2 100644
--- a/libraries/libldap/options.c
+++ b/libraries/libldap/options.c
@@ -342,6 +342,18 @@ ldap_get_option(
 	case LDAP_OPT_DEBUG_LEVEL:
 		* (int *) outvalue = lo->ldo_debug;
 		return LDAP_OPT_SUCCESS;
+	
+	case LDAP_OPT_X_KEEPALIVE_IDLE:
+		* (int *) outvalue = lo->ldo_keepalive_idle;
+		return LDAP_OPT_SUCCESS;
+
+	case LDAP_OPT_X_KEEPALIVE_PROBES:
+		* (int *) outvalue = lo->ldo_keepalive_probes;
+		return LDAP_OPT_SUCCESS;
+
+	case LDAP_OPT_X_KEEPALIVE_INTERVAL:
+		* (int *) outvalue = lo->ldo_keepalive_interval;
+		return LDAP_OPT_SUCCESS;
 
 	default:
 #ifdef HAVE_TLS
@@ -681,6 +693,9 @@ ldap_set_option(
 	case LDAP_OPT_TIMEOUT:
 	case LDAP_OPT_NETWORK_TIMEOUT:
 	case LDAP_OPT_CONNECT_CB:
+	case LDAP_OPT_X_KEEPALIVE_IDLE:
+	case LDAP_OPT_X_KEEPALIVE_PROBES :
+	case LDAP_OPT_X_KEEPALIVE_INTERVAL :
 		if(invalue == NULL) {
 			/* no place to set from */
 			return LDAP_OPT_ERROR;
@@ -770,6 +785,16 @@ ldap_set_option(
 			lo->ldo_conn_cbs = ll;
 		}
 		return LDAP_OPT_SUCCESS;
+	case LDAP_OPT_X_KEEPALIVE_IDLE:
+		lo->ldo_keepalive_idle = * (const int *) invalue;
+		return LDAP_OPT_SUCCESS;
+	case LDAP_OPT_X_KEEPALIVE_PROBES :
+		lo->ldo_keepalive_probes = * (const int *) invalue;
+		return LDAP_OPT_SUCCESS;
+	case LDAP_OPT_X_KEEPALIVE_INTERVAL :
+		lo->ldo_keepalive_interval = * (const int *) invalue;
+		return LDAP_OPT_SUCCESS;
+	
 	}
 	return LDAP_OPT_ERROR;
 }
diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c
index a3a3306f93..d2d0fac434 100644
--- a/libraries/libldap/os-ip.c
+++ b/libraries/libldap/os-ip.c
@@ -142,6 +142,57 @@ ldap_int_prepare_socket(LDAP *ld, int s, int proto )
 				"setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n",
 				s, 0, 0 );
 		}
+		if ( ld->ld_options.ldo_keepalive_idle > 0 )
+		{
+#ifdef TCP_KEEPIDLE
+			if ( setsockopt( s, SOL_TCP, TCP_KEEPIDLE,
+					(void*) &ld->ld_options.ldo_keepalive_idle,
+					sizeof(ld->ld_options.ldo_keepalive_idle) ) == AC_SOCKET_ERROR )
+			{
+				osip_debug( ld, "ldap_prepare_socket: "
+					"setsockopt(%d, TCP_KEEPIDLE) failed (ignored).\n",
+					s, 0, 0 );
+			}
+#else
+			osip_debug( ld, "ldap_prepare_socket: "
+					"sockopt TCP_KEEPIDLE not supported on this system.\n", 
+					0, 0, 0 );
+#endif /* TCP_KEEPIDLE */
+		}
+		if ( ld->ld_options.ldo_keepalive_probes > 0 )
+		{
+#ifdef TCP_KEEPCNT
+			if ( setsockopt( s, SOL_TCP, TCP_KEEPCNT,
+					(void*) &ld->ld_options.ldo_keepalive_probes,
+					sizeof(ld->ld_options.ldo_keepalive_probes) ) == AC_SOCKET_ERROR )
+			{
+				osip_debug( ld, "ldap_prepare_socket: "
+					"setsockopt(%d, TCP_KEEPCNT) failed (ignored).\n",
+					s, 0, 0 );
+			}
+#else
+			osip_debug( ld, "ldap_prepare_socket: "
+					"sockopt TCP_KEEPCNT not supported on this system.\n", 
+					0, 0, 0 );
+#endif /* TCP_KEEPCNT */
+		}
+		if ( ld->ld_options.ldo_keepalive_interval > 0 )
+		{
+#ifdef TCP_KEEPINTVL
+			if ( setsockopt( s, SOL_TCP, TCP_KEEPINTVL,
+					(void*) &ld->ld_options.ldo_keepalive_interval,
+					sizeof(ld->ld_options.ldo_keepalive_interval) ) == AC_SOCKET_ERROR )
+			{
+				osip_debug( ld, "ldap_prepare_socket: "
+					"setsockopt(%d, TCP_KEEPINTVL) failed (ignored).\n",
+					s, 0, 0 );
+			} 
+#else
+			osip_debug( ld, "ldap_prepare_socket: "
+					"sockopt TCP_KEEPINTVL not supported on this system.\n", 
+					0, 0, 0 );
+#endif /* TCP_KEEPINTVL */
+		}
 #endif /* SO_KEEPALIVE */
 #ifdef TCP_NODELAY
 		if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY,
-- 
GitLab