Blame SOURCES/0065-Ticket-47620-389-ds-rejects-nsds5ReplicaProtocolTime.patch

cc3dff
From 39af2e9e98c895c5145090865d5ab7cde6cc12fd Mon Sep 17 00:00:00 2001
cc3dff
From: Mark Reynolds <mreynolds@redhat.com>
cc3dff
Date: Fri, 6 Dec 2013 16:57:41 -0500
cc3dff
Subject: [PATCH 65/65] Ticket 47620 - 389-ds rejects
cc3dff
 nsds5ReplicaProtocolTimeout attribute
cc3dff
cc3dff
Bug Description:  Attempting to add/modify/delete nsds5ReplicaProtocolTimeout
cc3dff
                  results in an error 53 (unwilling to perform).
cc3dff
cc3dff
Fix Description:  Allow nsds5ReplicaProtocolTimeout to be updated in agreements
cc3dff
                  and the replica configuration.  Also, made the config timeout
cc3dff
                  setting dynamic.
cc3dff
cc3dff
https://fedorahosted.org/389/ticket/47620
cc3dff
cc3dff
Reviewed by: rmeggins(Thanks!)
cc3dff
(cherry picked from commit 58fca2c4e4f2120cb6e5fb249008be8f551e944c)
cc3dff
(cherry picked from commit 490360fd96121d06fa8813e182b44d045257be98)
cc3dff
---
cc3dff
 ldap/servers/plugins/replication/repl5.h           | 12 +++--
cc3dff
 ldap/servers/plugins/replication/repl5_agmt.c      | 54 ++++++++++++++++------
cc3dff
 ldap/servers/plugins/replication/repl5_agmtlist.c  | 27 +++++++++--
cc3dff
 .../plugins/replication/repl5_inc_protocol.c       | 23 +++++++--
cc3dff
 .../plugins/replication/repl5_prot_private.h       |  1 -
cc3dff
 ldap/servers/plugins/replication/repl5_protocol.c  | 13 ++----
cc3dff
 ldap/servers/plugins/replication/repl5_replica.c   | 54 ++++++++++++++--------
cc3dff
 .../plugins/replication/repl5_replica_config.c     | 25 +++++++++-
cc3dff
 .../plugins/replication/repl5_tot_protocol.c       | 17 +++++--
cc3dff
 9 files changed, 169 insertions(+), 57 deletions(-)
cc3dff
cc3dff
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
cc3dff
index 92a9229..321a285 100644
cc3dff
--- a/ldap/servers/plugins/replication/repl5.h
cc3dff
+++ b/ldap/servers/plugins/replication/repl5.h
cc3dff
@@ -386,9 +386,15 @@ char **agmt_get_attrs_to_strip(Repl_Agmt *ra);
cc3dff
 int agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e);
cc3dff
 int agmt_set_timeout(Repl_Agmt *ra, long timeout);
cc3dff
 void agmt_update_done(Repl_Agmt *ra, int is_total);
cc3dff
-int agmt_get_protocol_timeout(Repl_Agmt *agmt);
cc3dff
 
cc3dff
 typedef struct replica Replica;
cc3dff
+PRUint64 agmt_get_protocol_timeout(Repl_Agmt *agmt);
cc3dff
+void agmt_set_protocol_timeout(Repl_Agmt *agmt, PRUint64 timeout);
cc3dff
+void agmt_update_maxcsn(Replica *r, Slapi_DN *sdn, int op, LDAPMod **mods, CSN *csn);
cc3dff
+void add_agmt_maxcsns(Slapi_Entry *e, Replica *r);
cc3dff
+void agmt_set_maxcsn(Repl_Agmt *ra);
cc3dff
+void agmt_remove_maxcsn(Repl_Agmt *ra);
cc3dff
+int agmt_maxcsn_to_smod (Replica *r, Slapi_Mod *smod);
cc3dff
 
cc3dff
 /* In repl5_agmtlist.c */
cc3dff
 int agmtlist_config_init();
cc3dff
@@ -494,7 +500,6 @@ void prot_notify_window_opened (Repl_Protocol *rp);
cc3dff
 void prot_notify_window_closed (Repl_Protocol *rp);
cc3dff
 Object *prot_get_replica_object(Repl_Protocol *rp);
cc3dff
 void prot_replicate_now(Repl_Protocol *rp);
cc3dff
-int prot_get_timeout(Repl_Protocol *rp);
cc3dff
 
cc3dff
 Repl_Protocol *agmt_get_protocol(Repl_Agmt *ra);
cc3dff
 
cc3dff
@@ -591,7 +596,8 @@ char *replica_get_dn(Replica *r);
cc3dff
 void replica_check_for_tasks(Replica*r, Slapi_Entry *e);
cc3dff
 void replica_update_state (time_t when, void *arg);
cc3dff
 void replica_reset_csn_pl(Replica *r);
cc3dff
-int replica_get_protocol_timeout(Replica *r);
cc3dff
+PRUint64 replica_get_protocol_timeout(Replica *r);
cc3dff
+void replica_set_protocol_timeout(Replica *r, PRUint64 timeout);
cc3dff
 int replica_get_backoff_min(Replica *r);
cc3dff
 int replica_get_backoff_max(Replica *r);
cc3dff
 void replica_set_backoff_min(Replica *r, int min);
cc3dff
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
cc3dff
index 90d94f8..b0da172 100644
cc3dff
--- a/ldap/servers/plugins/replication/repl5_agmt.c
cc3dff
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
cc3dff
@@ -142,7 +142,9 @@ typedef struct repl5agmt {
cc3dff
 	char **attrs_to_strip; /* for fractional replication, if a "mod" is empty, strip out these attributes:
cc3dff
 	                        * modifiersname, modifytimestamp, internalModifiersname, internalModifyTimestamp, etc */
cc3dff
 	int agreement_type;
cc3dff
-	PRUint64 protocol_timeout;
cc3dff
+	Slapi_Counter *protocol_timeout;
cc3dff
+	char *maxcsn; /* agmt max csn */
cc3dff
+	Slapi_RWLock *attr_lock; /* RW lock for all the stripped attrs */
cc3dff
 } repl5agmt;
cc3dff
 
cc3dff
 /* Forward declarations */
cc3dff
@@ -265,6 +267,14 @@ agmt_new_from_entry(Slapi_Entry *e)
cc3dff
 			slapi_entry_get_dn_const(e));
cc3dff
 		goto loser;
cc3dff
 	}
cc3dff
+	if ((ra->attr_lock = slapi_new_rwlock()) == NULL)
cc3dff
+	{
cc3dff
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Unable to create new attr lock "
cc3dff
+			"for replication agreement \"%s\" - agreement ignored.\n",
cc3dff
+			slapi_entry_get_dn_const(e));
cc3dff
+		goto loser;
cc3dff
+	}
cc3dff
+	ra->protocol_timeout = slapi_counter_new();
cc3dff
 
cc3dff
 	/* Find all the stuff we need for the agreement */
cc3dff
 
cc3dff
@@ -338,19 +348,14 @@ agmt_new_from_entry(Slapi_Entry *e)
cc3dff
 	tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaRoot);
cc3dff
 	if (NULL != tmpstr)
cc3dff
 	{
cc3dff
+		PRUint64 ptimeout = 0;
cc3dff
+
cc3dff
 		ra->replarea = slapi_sdn_new_dn_passin(tmpstr);
cc3dff
 
cc3dff
 		/* If this agmt has its own timeout, grab it, otherwise use the replica's protocol timeout */
cc3dff
-		ra->protocol_timeout = slapi_entry_attr_get_int(e, type_replicaProtocolTimeout);
cc3dff
-		if(ra->protocol_timeout == 0){
cc3dff
-			/* grab the replica protocol timeout */
cc3dff
-			Object *replobj = replica_get_replica_from_dn(ra->replarea);
cc3dff
-			if(replobj){
cc3dff
-				Replica *replica =(Replica*)object_get_data (replobj);
cc3dff
-				ra->protocol_timeout = replica_get_protocol_timeout(replica);
cc3dff
-			} else {
cc3dff
-				ra->protocol_timeout = DEFAULT_PROTOCOL_TIMEOUT;
cc3dff
-			}
cc3dff
+		ptimeout = slapi_entry_attr_get_int(e, type_replicaProtocolTimeout);
cc3dff
+		if(ptimeout){
cc3dff
+			slapi_counter_set_value(ra->protocol_timeout, ptimeout);
cc3dff
 		}
cc3dff
 	}
cc3dff
 
cc3dff
@@ -613,6 +618,17 @@ agmt_delete(void **rap)
cc3dff
 	if(ra->attrs_to_strip){
cc3dff
 		slapi_ch_array_free(ra->attrs_to_strip);
cc3dff
 	}
cc3dff
+	if(ra->maxcsn){
cc3dff
+		slapi_ch_free_string(&ra->maxcsn);
cc3dff
+	}
cc3dff
+	schedule_destroy(ra->schedule);
cc3dff
+	slapi_ch_free_string(&ra->long_name);
cc3dff
+
cc3dff
+	slapi_counter_destroy(&ra->protocol_timeout);
cc3dff
+
cc3dff
+	/* free the locks */
cc3dff
+	PR_DestroyLock(ra->lock);
cc3dff
+	slapi_destroy_rwlock(ra->attr_lock);
cc3dff
 
cc3dff
 	schedule_destroy(ra->schedule);
cc3dff
 	slapi_ch_free((void **)&ra->long_name);
cc3dff
@@ -2663,9 +2679,21 @@ agmt_update_done(Repl_Agmt *agmt, int is_total)
cc3dff
     windows_update_done(agmt, is_total);
cc3dff
 }
cc3dff
 
cc3dff
-int
cc3dff
+PRUint64
cc3dff
 agmt_get_protocol_timeout(Repl_Agmt *agmt)
cc3dff
 {
cc3dff
-    return (int)agmt->protocol_timeout;
cc3dff
+	if(agmt){
cc3dff
+		return slapi_counter_get_value(agmt->protocol_timeout);
cc3dff
+	} else {
cc3dff
+		return 0;
cc3dff
+	}
cc3dff
+}
cc3dff
+
cc3dff
+void
cc3dff
+agmt_set_protocol_timeout(Repl_Agmt *agmt, PRUint64 timeout)
cc3dff
+{
cc3dff
+	if(agmt){
cc3dff
+		slapi_counter_set_value(agmt->protocol_timeout, timeout);
cc3dff
+	}
cc3dff
 }
cc3dff
 
cc3dff
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
cc3dff
index 1167b0c..04891b7 100644
cc3dff
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
cc3dff
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
cc3dff
@@ -209,6 +209,7 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
cc3dff
 	LDAPMod **mods;
cc3dff
     char buff [SLAPI_DSE_RETURNTEXT_SIZE];
cc3dff
     char *errortext = returntext ? returntext : buff;
cc3dff
+    char *val = NULL;
cc3dff
     int rc = SLAPI_DSE_CALLBACK_OK;
cc3dff
     Slapi_Operation *op;
cc3dff
     void *identity;
cc3dff
@@ -243,16 +244,21 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
cc3dff
 	slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods;;
cc3dff
 	for (i = 0; NULL != mods && NULL != mods[i]; i++)
cc3dff
 	{
cc3dff
+		slapi_ch_free_string(&val;;
cc3dff
 		if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaInitialize))
cc3dff
 		{
cc3dff
             /* we don't allow delete attribute operations unless it was issued by
cc3dff
                the replication plugin - handled above */
cc3dff
             if (mods[i]->mod_op & LDAP_MOD_DELETE)
cc3dff
             {
cc3dff
-                if(strcasecmp (mods[i]->mod_type, type_nsds5ReplicaCleanRUVnotified) == 0){
cc3dff
+                if(strcasecmp (mods[i]->mod_type, type_nsds5ReplicaCleanRUVnotified) == 0 ){
cc3dff
                     /* allow the deletion of cleanallruv agmt attr */
cc3dff
                     continue;
cc3dff
                 }
cc3dff
+                if(strcasecmp (mods[i]->mod_type, type_replicaProtocolTimeout) == 0){
cc3dff
+                    agmt_set_protocol_timeout(agmt, 0);
cc3dff
+                    continue;
cc3dff
+                }
cc3dff
 
cc3dff
                 slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " 
cc3dff
                                 "deletion of %s attribute is not allowed\n", type_nsds5ReplicaInitialize);	
cc3dff
@@ -262,8 +268,6 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
cc3dff
             }
cc3dff
             else
cc3dff
             {
cc3dff
-                char *val;
cc3dff
-
cc3dff
                 if (mods[i]->mod_bvalues && mods[i]->mod_bvalues[0])
cc3dff
                     val = slapi_berval_get_string_copy (mods[i]->mod_bvalues[0]);
cc3dff
                 else
cc3dff
@@ -304,7 +308,6 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
cc3dff
                              val, mods[i]->mod_type);
cc3dff
                     slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: %s\n", errortext);
cc3dff
                 }
cc3dff
-                slapi_ch_free ((void**)&val;;
cc3dff
             }
cc3dff
 		}
cc3dff
 		else if (slapi_attr_types_equivalent(mods[i]->mod_type,
cc3dff
@@ -511,6 +514,21 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
cc3dff
                 rc = SLAPI_DSE_CALLBACK_ERROR;
cc3dff
             }
cc3dff
         }
cc3dff
+        else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_replicaProtocolTimeout)){
cc3dff
+            if (val){
cc3dff
+                long ptimeout = atol(val);
cc3dff
+
cc3dff
+                if(ptimeout <= 0){
cc3dff
+                    *returncode = LDAP_UNWILLING_TO_PERFORM;
cc3dff
+                    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "attribute %s value (%s) is invalid, "
cc3dff
+                                    "must be a number greater than zero.\n",
cc3dff
+                                    type_replicaProtocolTimeout, val);
cc3dff
+                    rc = SLAPI_DSE_CALLBACK_ERROR;
cc3dff
+                    break;
cc3dff
+                }
cc3dff
+                agmt_set_protocol_timeout(agmt, ptimeout);
cc3dff
+            }
cc3dff
+        }
cc3dff
         else if (0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e))
cc3dff
         {
cc3dff
             slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " 
cc3dff
@@ -561,6 +579,7 @@ done:
cc3dff
 	{
cc3dff
 		agmtlist_release_agmt(agmt);
cc3dff
 	}
cc3dff
+	slapi_ch_free_string(&val;;
cc3dff
 
cc3dff
 	return rc;
cc3dff
 }
cc3dff
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
cc3dff
index 612fe46..05074b0 100644
cc3dff
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
cc3dff
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
cc3dff
@@ -1921,10 +1921,24 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
cc3dff
 static int
cc3dff
 repl5_inc_stop(Private_Repl_Protocol *prp)
cc3dff
 {
cc3dff
-	int return_value;
cc3dff
 	PRIntervalTime start, maxwait, now;
cc3dff
+	Replica *replica = NULL;
cc3dff
+	PRUint64 timeout;
cc3dff
+	int return_value;
cc3dff
+
cc3dff
+	if((timeout = agmt_get_protocol_timeout(prp->agmt)) == 0){
cc3dff
+		timeout = DEFAULT_PROTOCOL_TIMEOUT;
cc3dff
+		if(prp->replica_object){
cc3dff
+			object_acquire(prp->replica_object);
cc3dff
+			replica = object_get_data(prp->replica_object);
cc3dff
+			if((timeout = replica_get_protocol_timeout(replica)) == 0){
cc3dff
+				timeout = DEFAULT_PROTOCOL_TIMEOUT;
cc3dff
+			}
cc3dff
+			object_release(prp->replica_object);
cc3dff
+		}
cc3dff
+	}
cc3dff
 
cc3dff
-	maxwait = PR_SecondsToInterval(prp->timeout);
cc3dff
+	maxwait = PR_SecondsToInterval(timeout);
cc3dff
 	prp->terminate = 1;
cc3dff
 	event_notify(prp, EVENT_PROTOCOL_SHUTDOWN);
cc3dff
 	start = PR_IntervalNow();
cc3dff
@@ -1939,8 +1953,8 @@ repl5_inc_stop(Private_Repl_Protocol *prp)
cc3dff
 		/* Isn't listening. Do something drastic. */
cc3dff
 		return_value = -1;
cc3dff
 		slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
cc3dff
-				"%s: repl5_inc_stop: protocol does not stop after %d seconds\n",
cc3dff
-				agmt_get_long_name(prp->agmt), (int)prp->timeout);
cc3dff
+				"%s: repl5_inc_stop: protocol does not stop after %llu seconds\n",
cc3dff
+				agmt_get_long_name(prp->agmt), (long long unsigned int)timeout);
cc3dff
 	}
cc3dff
 	else
cc3dff
 	{
cc3dff
@@ -2044,7 +2058,6 @@ Repl_5_Inc_Protocol_new(Repl_Protocol *rp)
cc3dff
     prp->notify_window_closed = repl5_inc_notify_window_closed;
cc3dff
 	prp->update_now = repl5_inc_update_now;
cc3dff
 	prp->replica_object = prot_get_replica_object(rp);
cc3dff
-	prp->timeout = prot_get_timeout(rp);
cc3dff
 	if ((prp->lock = PR_NewLock()) == NULL)
cc3dff
 	{
cc3dff
 		goto loser;
cc3dff
diff --git a/ldap/servers/plugins/replication/repl5_prot_private.h b/ldap/servers/plugins/replication/repl5_prot_private.h
cc3dff
index 37072ee..586e1eb 100644
cc3dff
--- a/ldap/servers/plugins/replication/repl5_prot_private.h
cc3dff
+++ b/ldap/servers/plugins/replication/repl5_prot_private.h
cc3dff
@@ -75,7 +75,6 @@ typedef struct private_repl_protocol
cc3dff
 	int repl50consumer; /* Flag to tell us if this is a 5.0-style consumer we're talking to */
cc3dff
 	int repl71consumer; /* Flag to tell us if this is a 7.1-style consumer we're talking to */
cc3dff
 	int repl90consumer; /* Flag to tell us if this is a 9.0-style consumer we're talking to */
cc3dff
-	PRUint64 timeout;
cc3dff
 } Private_Repl_Protocol;
cc3dff
 
cc3dff
 extern Private_Repl_Protocol *Repl_5_Inc_Protocol_new();
cc3dff
diff --git a/ldap/servers/plugins/replication/repl5_protocol.c b/ldap/servers/plugins/replication/repl5_protocol.c
cc3dff
index 34fe8a0..0e9668d 100644
cc3dff
--- a/ldap/servers/plugins/replication/repl5_protocol.c
cc3dff
+++ b/ldap/servers/plugins/replication/repl5_protocol.c
cc3dff
@@ -71,8 +71,7 @@ typedef struct repl_protocol
cc3dff
 	Object *replica_object; /* Local replica. If non-NULL, replica object is acquired */
cc3dff
 	int state;
cc3dff
 	int next_state;
cc3dff
-	PRUint64 protocol_timeout;
cc3dff
-        PRThread *agmt_thread;
cc3dff
+	PRThread *agmt_thread;
cc3dff
 	PRLock *lock;
cc3dff
 } repl_protocol;
cc3dff
 
cc3dff
@@ -134,16 +133,17 @@ prot_new(Repl_Agmt *agmt, int protocol_state)
cc3dff
 		rp->prp_total = private_protocol_factory(rp, PROTOCOL_WINDOWS_TOTAL);
cc3dff
 		rp->delete_conn = windows_conn_delete;
cc3dff
 	}
cc3dff
-	rp->protocol_timeout = agmt_get_protocol_timeout(agmt);
cc3dff
-
cc3dff
 	/* XXXggood register callback handlers for entries updated, and
cc3dff
 		schedule window enter/leave. */
cc3dff
 	
cc3dff
 	goto done;
cc3dff
+
cc3dff
 loser:
cc3dff
 	prot_delete(&rp);
cc3dff
+
cc3dff
 done:
cc3dff
 	slapi_sdn_free(&replarea_sdn);
cc3dff
+
cc3dff
 	return rp;
cc3dff
 }
cc3dff
 
cc3dff
@@ -593,8 +593,3 @@ private_protocol_factory(Repl_Protocol *rp, int type)
cc3dff
 	return prp;
cc3dff
 }
cc3dff
 
cc3dff
-int
cc3dff
-prot_get_timeout(Repl_Protocol *rp)
cc3dff
-{
cc3dff
-	return (int)rp->protocol_timeout;
cc3dff
-}
cc3dff
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
cc3dff
index 8a1c590..02d4e74 100644
cc3dff
--- a/ldap/servers/plugins/replication/repl5_replica.c
cc3dff
+++ b/ldap/servers/plugins/replication/repl5_replica.c
cc3dff
@@ -87,7 +87,7 @@ struct replica {
cc3dff
 	PRBool state_update_inprogress; /* replica state is being updated */
cc3dff
 	PRLock *agmt_lock;          	/* protects agreement creation, start and stop */
cc3dff
 	char *locking_purl;				/* supplier who has exclusive access */
cc3dff
-	PRUint64 protocol_timeout;		/* protocol shutdown timeout */
cc3dff
+	Slapi_Counter *protocol_timeout;	/* protocol shutdown timeout */
cc3dff
 	PRUint64 backoff_min;			/* backoff retry minimum */
cc3dff
 	PRUint64 backoff_max;			/* backoff retry maximum */
cc3dff
 };
cc3dff
@@ -164,26 +164,26 @@ replica_new(const Slapi_DN *root)
cc3dff
 Replica *
cc3dff
 replica_new_from_entry (Slapi_Entry *e, char *errortext, PRBool is_add_operation)
cc3dff
 {
cc3dff
-    int rc = 0;
cc3dff
-    Replica *r;
cc3dff
+	int rc = 0;
cc3dff
+	Replica *r;
cc3dff
 	char *repl_name = NULL;
cc3dff
 
cc3dff
-    if (e == NULL)
cc3dff
-    {
cc3dff
-        if (NULL != errortext)
cc3dff
+	if (e == NULL)
cc3dff
+	{
cc3dff
+		if (NULL != errortext)
cc3dff
 		{
cc3dff
-            PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "NULL entry");
cc3dff
+			PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "NULL entry");
cc3dff
 		}
cc3dff
-        return NULL;        
cc3dff
-    }
cc3dff
+		return NULL;
cc3dff
+	}
cc3dff
 
cc3dff
-   	r = (Replica *)slapi_ch_calloc(1, sizeof(Replica));
cc3dff
+	r = (Replica *)slapi_ch_calloc(1, sizeof(Replica));
cc3dff
 
cc3dff
-        if (!r)
cc3dff
+	if (!r)
cc3dff
 	{
cc3dff
-        	if (NULL != errortext)
cc3dff
+		if (NULL != errortext)
cc3dff
 		{
cc3dff
-            PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "Out of memory");
cc3dff
+			PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "Out of memory");
cc3dff
 		}
cc3dff
 		rc = -1;
cc3dff
 		goto done;
cc3dff
@@ -208,6 +208,7 @@ replica_new_from_entry (Slapi_Entry *e, char *errortext, PRBool is_add_operation
cc3dff
 		rc = -1;
cc3dff
 		goto done;
cc3dff
 	}
cc3dff
+	r->protocol_timeout = slapi_counter_new();
cc3dff
 
cc3dff
     /* read parameters from the replica config entry */
cc3dff
     rc = _replica_init_from_config (r, e, errortext);
cc3dff
@@ -403,6 +404,8 @@ replica_destroy(void **arg)
cc3dff
 		csnplFree(&r->min_csn_pl);;
cc3dff
 	}
cc3dff
 
cc3dff
+	slapi_counter_destroy(&r->protocol_timeout);
cc3dff
+
cc3dff
 	slapi_ch_free((void **)arg);
cc3dff
 }
cc3dff
 
cc3dff
@@ -796,10 +799,22 @@ replica_get_type (const Replica *r)
cc3dff
 	return r->repl_type;
cc3dff
 }
cc3dff
 
cc3dff
-int
cc3dff
+PRUint64
cc3dff
 replica_get_protocol_timeout(Replica *r)
cc3dff
 {
cc3dff
-	return (int)r->protocol_timeout;
cc3dff
+	if(r){
cc3dff
+		return slapi_counter_get_value(r->protocol_timeout);
cc3dff
+	} else {
cc3dff
+		return 0;
cc3dff
+	}
cc3dff
+}
cc3dff
+
cc3dff
+void
cc3dff
+replica_set_protocol_timeout(Replica *r, PRUint64 timeout)
cc3dff
+{
cc3dff
+	if(r){
cc3dff
+		slapi_counter_set_value(r->protocol_timeout, timeout);
cc3dff
+	}
cc3dff
 }
cc3dff
 
cc3dff
 /* 
cc3dff
@@ -1659,6 +1674,7 @@ _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext)
cc3dff
     char *val;
cc3dff
     int backoff_min;
cc3dff
     int backoff_max;
cc3dff
+    int ptimeout = 0;
cc3dff
     int rc;
cc3dff
 
cc3dff
     PR_ASSERT (r && e);
cc3dff
@@ -1731,9 +1747,11 @@ _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext)
cc3dff
     }
cc3dff
 
cc3dff
     /* get the protocol timeout */
cc3dff
-    r->protocol_timeout = slapi_entry_attr_get_int(e, type_replicaProtocolTimeout);
cc3dff
-    if(r->protocol_timeout == 0){
cc3dff
-        r->protocol_timeout = DEFAULT_PROTOCOL_TIMEOUT;
cc3dff
+    ptimeout = slapi_entry_attr_get_int(e, type_replicaProtocolTimeout);
cc3dff
+    if(ptimeout <= 0){
cc3dff
+        slapi_counter_set_value(r->protocol_timeout, DEFAULT_PROTOCOL_TIMEOUT);
cc3dff
+    } else {
cc3dff
+        slapi_counter_set_value(r->protocol_timeout, ptimeout);
cc3dff
     }
cc3dff
 
cc3dff
     /* get replica flags */
cc3dff
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
cc3dff
index 94c23c0..9452d51 100644
cc3dff
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
cc3dff
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
cc3dff
@@ -396,9 +396,16 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
cc3dff
                 else if (strcasecmp (config_attr, type_replicaCleanRUV) == 0 ||
cc3dff
                          strcasecmp (config_attr, type_replicaAbortCleanRUV) == 0)
cc3dff
                 {
cc3dff
-                    /* only allow the deletion of the cleanAllRUV config attributes */
cc3dff
+                    /*
cc3dff
+                     * Only allow the deletion of the cleanAllRUV config attributes, and the
cc3dff
+                     * protocol timeout.
cc3dff
+                     */
cc3dff
                     continue;
cc3dff
                 }
cc3dff
+                else if (strcasecmp (config_attr, type_replicaProtocolTimeout) == 0 )
cc3dff
+                {
cc3dff
+                	replica_set_protocol_timeout(r, DEFAULT_PROTOCOL_TIMEOUT);
cc3dff
+                }
cc3dff
                 else
cc3dff
                 {
cc3dff
                     *returncode = LDAP_UNWILLING_TO_PERFORM;
cc3dff
@@ -487,6 +494,22 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
cc3dff
                 {
cc3dff
                     *returncode = LDAP_SUCCESS;
cc3dff
                 }
cc3dff
+                else if (strcasecmp (config_attr, type_replicaProtocolTimeout) == 0 ){
cc3dff
+                    if (apply_mods && config_attr_value && config_attr_value[0])
cc3dff
+                    {
cc3dff
+                        long ptimeout = atol(config_attr_value);
cc3dff
+
cc3dff
+                        if(ptimeout <= 0){
cc3dff
+                            *returncode = LDAP_UNWILLING_TO_PERFORM;
cc3dff
+                            PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
cc3dff
+                                         "attribute %s value (%s) is invalid, must be a number greater than zero.\n",
cc3dff
+                                         config_attr, config_attr_value);
cc3dff
+                            slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n", errortext);
cc3dff
+                        } else {
cc3dff
+                            replica_set_protocol_timeout(r, ptimeout);
cc3dff
+                        }
cc3dff
+                    }
cc3dff
+                }
cc3dff
                 else
cc3dff
                 {
cc3dff
                     *returncode = LDAP_UNWILLING_TO_PERFORM;
cc3dff
diff --git a/ldap/servers/plugins/replication/repl5_tot_protocol.c b/ldap/servers/plugins/replication/repl5_tot_protocol.c
cc3dff
index 5bb203a..a241128 100644
cc3dff
--- a/ldap/servers/plugins/replication/repl5_tot_protocol.c
cc3dff
+++ b/ldap/servers/plugins/replication/repl5_tot_protocol.c
cc3dff
@@ -505,11 +505,22 @@ static int
cc3dff
 repl5_tot_stop(Private_Repl_Protocol *prp)
cc3dff
 {
cc3dff
 	int return_value;
cc3dff
-	int seconds = 600;
cc3dff
 	PRIntervalTime start, maxwait, now;
cc3dff
+	PRUint64 timeout = DEFAULT_PROTOCOL_TIMEOUT;
cc3dff
+	Replica *replica = NULL;
cc3dff
+
cc3dff
+	if((timeout = agmt_get_protocol_timeout(prp->agmt)) == 0){
cc3dff
+		timeout = DEFAULT_PROTOCOL_TIMEOUT;
cc3dff
+		if(prp->replica_object){
cc3dff
+			replica = object_get_data(prp->replica_object);
cc3dff
+			if((timeout = replica_get_protocol_timeout(replica)) == 0){
cc3dff
+				timeout = DEFAULT_PROTOCOL_TIMEOUT;
cc3dff
+			}
cc3dff
+		}
cc3dff
+	}
cc3dff
 
cc3dff
 	prp->terminate = 1;
cc3dff
-	maxwait = PR_SecondsToInterval(seconds);
cc3dff
+	maxwait = PR_SecondsToInterval(timeout);
cc3dff
 	start = PR_IntervalNow();
cc3dff
 	now = start;
cc3dff
 	while (!prp->stopped && ((now - start) < maxwait))
cc3dff
@@ -567,7 +578,6 @@ Repl_5_Tot_Protocol_new(Repl_Protocol *rp)
cc3dff
 	prp->notify_window_opened = repl5_tot_noop;
cc3dff
 	prp->notify_window_closed = repl5_tot_noop;
cc3dff
 	prp->update_now = repl5_tot_noop;
cc3dff
-	prp->timeout = DEFAULT_PROTOCOL_TIMEOUT;
cc3dff
 	if ((prp->lock = PR_NewLock()) == NULL)
cc3dff
 	{
cc3dff
 		goto loser;
cc3dff
@@ -588,6 +598,7 @@ Repl_5_Tot_Protocol_new(Repl_Protocol *rp)
cc3dff
 	prp->repl50consumer = 0;
cc3dff
 	prp->repl71consumer = 0;
cc3dff
 	prp->repl90consumer = 0;
cc3dff
+	prp->replica_object = prot_get_replica_object(rp);
cc3dff
 	return prp;
cc3dff
 loser:
cc3dff
 	repl5_tot_delete(&prp;;
cc3dff
-- 
cc3dff
1.8.1.4
cc3dff