>From 601301c37661e91ccc318f09edaa42a7dbcd351d Mon Sep 17 00:00:00 2001
From: Jan Zeleny <jzeleny@redhat.com>
Date: Wed, 20 Jun 2012 13:42:06 -0400
Subject: [PATCH 03/12] Primary server support: support for "disconnecting"
 connections in LDAP

This patch adds support for marking existing connections as being
disconnected. Each such connection can't be used for new queries and a
new one has to be created instead if necessary. This will ensure that
pending operations will end gracefully during reconnection. Also all new
queries to the server we are reconnecting to will use another (probably
newly created) connection.
---
 src/providers/ldap/sdap_id_op.c |   41 +++++++++++++++++++++++++++++++++++---
 1 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c
index d4f6fe3450678d9c9331613c892870ef9236d512..3036d0cc144111b89319a7bf075c37789cb911d0 100644
--- a/src/providers/ldap/sdap_id_op.c
+++ b/src/providers/ldap/sdap_id_op.c
@@ -72,9 +72,14 @@ struct sdap_id_conn_data {
     int notify_lock;
     /* list of operations using connect */
     struct sdap_id_op *ops;
+    /* A flag which is signalizing that this
+     * connection will be disconnected and should
+     * not be used any more */
+    bool disconnecting;
 };
 
 static void sdap_id_conn_cache_be_offline_cb(void *pvt);
+static void sdap_id_conn_cache_fo_reconnect_cb(void *pvt);
 
 static void sdap_id_release_conn_data(struct sdap_id_conn_data *conn_data);
 static int sdap_id_conn_data_destroy(struct sdap_id_conn_data *conn_data);
@@ -118,6 +123,14 @@ int sdap_id_conn_cache_create(TALLOC_CTX *memctx,
         goto fail;
     }
 
+    ret = be_add_reconnect_cb(conn_cache, id_ctx->be,
+                              sdap_id_conn_cache_fo_reconnect_cb, conn_cache,
+                              NULL);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("be_add_reconnect_cb failed.\n"));
+        goto fail;
+    }
+
     *conn_cache_out = conn_cache;
     return EOK;
 
@@ -139,6 +152,18 @@ static void sdap_id_conn_cache_be_offline_cb(void *pvt)
     }
 }
 
+/* Callback for attempt to reconnect to primary server */
+static void sdap_id_conn_cache_fo_reconnect_cb(void *pvt)
+{
+    struct sdap_id_conn_cache *conn_cache = talloc_get_type(pvt, struct sdap_id_conn_cache);
+    struct sdap_id_conn_data *cached_connection = conn_cache->cached_connection;
+
+    /* Release any cached connection on going offline */
+    if (cached_connection != NULL) {
+        cached_connection->disconnecting = true;
+    }
+}
+
 /* Release sdap_id_conn_data and destroy it if no longer needed */
 static void sdap_id_release_conn_data(struct sdap_id_conn_data *conn_data)
 {
@@ -194,7 +219,8 @@ static bool sdap_can_reuse_connection(struct sdap_id_conn_data *conn_data)
 {
     int timeout;
 
-    if (!conn_data || !conn_data->sh || !conn_data->sh->connected) {
+    if (!conn_data || !conn_data->sh ||
+        !conn_data->sh->connected || conn_data->disconnecting) {
         return false;
     }
 
@@ -721,6 +747,7 @@ int sdap_id_op_connect_recv(struct tevent_req *req, int *dp_error)
 int sdap_id_op_done(struct sdap_id_op *op, int retval, int *dp_err_out)
 {
     bool communication_error;
+    struct sdap_id_conn_data *current_conn = op->conn_data;
     switch (retval) {
         case EIO:
         case ETIMEDOUT:
@@ -733,8 +760,8 @@ int sdap_id_op_done(struct sdap_id_op *op, int retval, int *dp_err_out)
             break;
     }
 
-    if (communication_error && op->conn_data != 0
-            && op->conn_data == op->conn_cache->cached_connection) {
+    if (communication_error && current_conn != 0
+            && current_conn == op->conn_cache->cached_connection) {
         /* do not reuse failed connection */
         op->conn_cache->cached_connection = NULL;
 
@@ -774,9 +801,15 @@ int sdap_id_op_done(struct sdap_id_op *op, int retval, int *dp_err_out)
         op->reconnect_retry_count = 0;
     }
 
-    if (op->conn_data) {
+    if (current_conn) {
         DEBUG(9, ("releasing operation connection\n"));
         sdap_id_op_hook_conn_data(op, NULL);
+
+        if (current_conn->ops == NULL || current_conn->disconnecting) {
+            DEBUG(SSSDBG_TRACE_FUNC, ("Connection is marked for "
+                                      "disconnection, executing ...\n"));
+            sdap_id_release_conn_data(current_conn);
+        }
     }
 
     *dp_err_out = dp_err;
-- 
1.7.7.6

