From ae74fa109def47dafbf899d4453f07d15f152e19 Mon Sep 17 00:00:00 2001
From: "Ted C. Cheng" <tedcheng@symas.com>
Date: Wed, 23 Jan 2013 17:10:41 -0800
Subject: [PATCH] added tcp keepalive support to back-ldap

---
 doc/man/man5/slapd-ldap.5        | 19 +++++++++++++++++++
 servers/slapd/back-ldap/bind.c   |  3 +++
 servers/slapd/back-ldap/config.c | 31 +++++++++++++++++++++++++++++++
 servers/slapd/config.c           | 30 +++++++++++++++++++++++++++++-
 4 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/doc/man/man5/slapd-ldap.5 b/doc/man/man5/slapd-ldap.5
index 7f80883069..d5700c0e84 100644
--- a/doc/man/man5/slapd-ldap.5
+++ b/doc/man/man5/slapd-ldap.5
@@ -413,6 +413,25 @@ for details on the syntax of this field.
 This directive causes a cached connection to be dropped an recreated
 after it has been idle for the specified time.
 
+.TP
+.B keepalive  <idle>:<probes>:<interval>
+The
+.B keepalive
+parameter sets the values of \fIidle\fP, \fIprobes\fP, and \fIinterval\fP
+used to check whether a socket is alive;
+.I idle
+is the number of seconds a connection needs to remain idle before TCP 
+starts sending keepalive probes;
+.I probes
+is the maximum number of keepalive probes TCP should send before dropping
+the connection;
+.I interval
+is interval in seconds between individual keepalive probes.
+Only some systems support the customization of these values;
+the
+.B keepalive
+parameter is ignored otherwise, and system-wide settings are used.
+
 .TP
 .B network\-timeout <time>
 Sets the network timeout value after which
diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c
index 409b93c454..45f228a282 100644
--- a/servers/slapd/back-ldap/bind.c
+++ b/servers/slapd/back-ldap/bind.c
@@ -716,6 +716,9 @@ ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_
 		ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv );
 	}
 
+	/* turn on network keepalive, if configured so */
+	slap_client_keepalive(ld, &li->li_tls.sb_keepalive); 
+
 #ifdef HAVE_TLS
 	if ( LDAP_BACK_CONN_ISPRIV( lc ) ) {
 		/* See "rationale" comment in ldap_back_getconn() */
diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c
index d6af1ffec5..abb6ec1fec 100644
--- a/servers/slapd/back-ldap/config.c
+++ b/servers/slapd/back-ldap/config.c
@@ -74,6 +74,7 @@ enum {
 	LDAP_BACK_CFG_ONERR,
 
 	LDAP_BACK_CFG_REWRITE,
+	LDAP_BACK_CFG_KEEPALIVE,
 
 	LDAP_BACK_CFG_LAST
 };
@@ -353,6 +354,14 @@ static ConfigTable ldapcfg[] = {
 	{ "rewrite", "<arglist>", 2, 4, STRLENOF( "rewrite" ),
 		ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
 		ldap_back_cf_gen, NULL, NULL, NULL },
+	{ "keepalive", "keepalive", 2, 2, 0,
+		ARG_MAGIC|LDAP_BACK_CFG_KEEPALIVE,
+		ldap_back_cf_gen, "( OLcfgDbAt:3.29 "
+			"NAME 'olcDbKeepalive' "
+			"DESC 'TCP keepalive' "
+			"SYNTAX OMsDirectoryString "
+			"SINGLE-VALUE )",
+		NULL, NULL },
 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
 		NULL, NULL, NULL, NULL }
 };
@@ -393,6 +402,7 @@ static ConfigOCs ldapocs[] = {
 			"$ olcDbNoRefs "
 			"$ olcDbNoUndefFilter "
 			"$ olcDbOnErr "
+			"$ olcDbKeepalive "
 		") )",
 		 	Cft_Database, ldapcfg},
 	{ NULL, 0, NULL }
@@ -1367,6 +1377,16 @@ ldap_back_cf_gen( ConfigArgs *c )
 			}
 			break;
 
+		case LDAP_BACK_CFG_KEEPALIVE: {
+			struct berval bv;
+			char buf[AC_LINE_MAX];
+			bv.bv_len = AC_LINE_MAX;
+			bv.bv_val = &buf[0];
+			slap_keepalive_parse(&bv, &li->li_tls.sb_keepalive, 0, 0, 1);
+			value_add_one( &c->rvalue_vals, &bv );
+			break;
+			}
+
 		default:
 			/* FIXME: we need to handle all... */
 			assert( 0 );
@@ -1534,6 +1554,12 @@ ldap_back_cf_gen( ConfigArgs *c )
 			li->li_flags &= ~LDAP_BACK_F_ONERR_STOP;
 			break;
 
+		case LDAP_BACK_CFG_KEEPALIVE:
+			li->li_tls.sb_keepalive.sk_idle = 0;
+			li->li_tls.sb_keepalive.sk_probes = 0;
+			li->li_tls.sb_keepalive.sk_interval = 0;
+			break;
+
 		default:
 			/* FIXME: we need to handle all... */
 			assert( 0 );
@@ -2222,6 +2248,11 @@ done_url:;
 			"and prefix all directives with \"rwm-\")" );
 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
 		return 1;
+
+	case LDAP_BACK_CFG_KEEPALIVE:
+		slap_keepalive_parse( ber_bvstrdup(c->argv[1]),
+				 &li->li_tls.sb_keepalive, 0, 0, 0);
+		break;
 		
 	default:
 		/* FIXME: try to catch inconsistencies */
diff --git a/servers/slapd/config.c b/servers/slapd/config.c
index abc379f198..374dced4c3 100644
--- a/servers/slapd/config.c
+++ b/servers/slapd/config.c
@@ -1283,7 +1283,7 @@ static slap_verbmasks versionkey[] = {
 	{ BER_BVNULL, 0 }
 };
 
-static int 
+int 
 slap_keepalive_parse(
 	struct berval *val,
 	void *bc,
@@ -1925,6 +1925,29 @@ int bindconf_tls_set( slap_bindconf *bc, LDAP *ld )
 }
 #endif
 
+/*
+ * set connection keepalive options
+ */
+void
+slap_client_keepalive(LDAP *ld, slap_keepalive *sk)
+{
+	if (!sk) return;
+
+	if ( sk->sk_idle ) {
+		ldap_set_option( ld, LDAP_OPT_X_KEEPALIVE_IDLE, &sk->sk_idle );
+	}
+
+	if ( sk->sk_probes ) {
+		ldap_set_option( ld, LDAP_OPT_X_KEEPALIVE_PROBES, &sk->sk_probes );
+	}
+
+	if ( sk->sk_interval ) {
+		ldap_set_option( ld, LDAP_OPT_X_KEEPALIVE_INTERVAL, &sk->sk_interval );
+	}
+
+	return;
+}
+
 /*
  * connect to a client using the bindconf data
  * note: should move "version" into bindconf...
@@ -1963,6 +1986,10 @@ slap_client_connect( LDAP **ldp, slap_bindconf *sb )
 		ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, &tv );
 	}
 
+	/* setting network keepalive options */
+	slap_client_keepalive(ld, &sb->sb_keepalive);
+
+#if 0
 	if ( sb->sb_keepalive.sk_idle ) {
 		ldap_set_option( ld, LDAP_OPT_X_KEEPALIVE_IDLE, &sb->sb_keepalive.sk_idle );
 	}
@@ -1974,6 +2001,7 @@ slap_client_connect( LDAP **ldp, slap_bindconf *sb )
 	if ( sb->sb_keepalive.sk_interval ) {
 		ldap_set_option( ld, LDAP_OPT_X_KEEPALIVE_INTERVAL, &sb->sb_keepalive.sk_interval );
 	}
+#endif /* 0 */
 
 #ifdef HAVE_TLS
 	if ( sb->sb_tls_do_init ) {
-- 
GitLab