>From 9b4376c827da0891572d37e69165067c7ce66697 Mon Sep 17 00:00:00 2001
From: Michal Zidek <mzidek@redhat.com>
Date: Fri, 10 Aug 2012 15:31:25 +0200
Subject: [PATCH] Duplicate detection in fail over did not work.

https://fedorahosted.org/sssd/ticket/1472
---
 src/providers/ad/ad_common.c     |  4 ++--
 src/providers/data_provider_fo.c | 10 ++++++----
 src/providers/dp_backend.h       |  5 +++--
 src/providers/fail_over.c        | 17 +++++++++++------
 src/providers/fail_over.h        |  8 ++++++--
 src/providers/ipa/ipa_common.c   |  4 ++--
 src/providers/krb5/krb5_common.c |  5 +++--
 src/providers/ldap/ldap_common.c |  6 ++++--
 8 files changed, 37 insertions(+), 22 deletions(-)

diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 800ef13..3e423e1 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -182,7 +182,7 @@ ad_servers_init(TALLOC_CTX *mem_ctx,
 
             ret = be_fo_add_srv_server(bectx, AD_SERVICE_NAME, "ldap",
                                        ad_domain, BE_FO_PROTO_TCP,
-                                       false, NULL);
+                                       false, NULL, NULL);
             if (ret != EOK) {
                 DEBUG(SSSDBG_FATAL_FAILURE,
                       ("Failed to add service discovery to failover: [%s]",
@@ -194,7 +194,7 @@ ad_servers_init(TALLOC_CTX *mem_ctx,
             continue;
         }
 
-        ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, NULL, primary);
+        ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, NULL, NULL, primary);
         if (ret && ret != EEXIST) {
             DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n"));
             goto done;
diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index 1c03e31..a8e4e58 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -254,7 +254,8 @@ int be_fo_add_srv_server(struct be_ctx *ctx,
                          const char *query_service,
                          const char *default_discovery_domain,
                          enum be_fo_protocol proto,
-                         bool proto_fallback, void *user_data)
+                         bool proto_fallback, void *user_data,
+                         int (*user_data_cmp)(void*, void*))
 {
     struct be_svc_data *svc;
     char *domain;
@@ -278,7 +279,7 @@ int be_fo_add_srv_server(struct be_ctx *ctx,
     /* Add the first protocol as the primary lookup */
     ret = fo_add_srv_server(svc->fo_service, query_service,
                             domain, ctx->domain->name,
-                            proto_table[proto], user_data);
+                            proto_table[proto], user_data, user_data_cmp);
     if (ret && ret != EEXIST) {
         DEBUG(1, ("Failed to add SRV lookup reference to failover service\n"));
         return ret;
@@ -290,7 +291,7 @@ int be_fo_add_srv_server(struct be_ctx *ctx,
         while (i != proto) {
             ret = fo_add_srv_server(svc->fo_service, query_service,
                                     domain, ctx->domain->name,
-                                    proto_table[i], user_data);
+                                    proto_table[i], user_data, user_data_cmp);
             if (ret && ret != EEXIST) {
                 DEBUG(1, ("Failed to add SRV lookup reference to failover service\n"));
                 return ret;
@@ -317,6 +318,7 @@ int be_fo_get_server_count(struct be_ctx *ctx, const char *service_name)
 
 int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
                      const char *server, int port, void *user_data,
+                     int (*user_data_cmp)(void*, void*),
                      bool primary)
 {
     struct be_svc_data *svc;
@@ -328,7 +330,7 @@ int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
     }
 
     ret = fo_add_server(svc->fo_service, server, port,
-                        user_data, primary);
+                        user_data, user_data_cmp, primary);
     if (ret && ret != EEXIST) {
         DEBUG(1, ("Failed to add server to failover service\n"));
         return ret;
diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
index 4d079c0..a7951f6 100644
--- a/src/providers/dp_backend.h
+++ b/src/providers/dp_backend.h
@@ -228,10 +228,11 @@ int be_fo_add_srv_server(struct be_ctx *ctx,
                          const char *query_service,
                          const char *default_discovery_domain,
                          enum be_fo_protocol proto,
-                         bool proto_fallback, void *user_data);
+                         bool proto_fallback, void *user_data,
+                         int (*user_data_cmp)(void*, void*));
 int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
                      const char *server, int port, void *user_data,
-                     bool primary);
+                     int (*user_data_cmp)(void*, void*), bool primary);
 
 struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
index facc990..aca336a 100644
--- a/src/providers/fail_over.c
+++ b/src/providers/fail_over.c
@@ -511,7 +511,7 @@ create_server_common(TALLOC_CTX *mem_ctx, struct fo_ctx *ctx, const char *name)
 int
 fo_add_srv_server(struct fo_service *service, const char *srv,
                   const char *discovery_domain, const char *sssd_domain,
-                  const char *proto, void *user_data)
+                  const char *proto, void *user_data, int (*user_data_cmp)(void*, void*))
 {
     struct fo_server *server;
 
@@ -520,7 +520,7 @@ fo_add_srv_server(struct fo_service *service, const char *srv,
                               service->name, proto));
 
     DLIST_FOR_EACH(server, service->server_list) {
-        if (server->user_data != user_data)
+        if (user_data_cmp && user_data_cmp(server->user_data, user_data))
             continue;
 
         if (fo_is_srv_lookup(server)) {
@@ -627,9 +627,14 @@ fo_get_server_count(struct fo_service *service)
 static bool fo_server_match(struct fo_server *server,
                            const char *name,
                            int port,
-                           void *user_data)
+                           void *user_data,
+                           int (*user_data_cmp)(void*, void*))
 {
-    if (server->port != port || server->user_data != user_data) {
+    if (server->port != port) {
+        return false;
+    }
+
+    if (user_data_cmp && user_data_cmp(user_data, user_data)) {
         return false;
     }
 
@@ -647,14 +652,14 @@ static bool fo_server_match(struct fo_server *server,
 
 int
 fo_add_server(struct fo_service *service, const char *name, int port,
-              void *user_data, bool primary)
+              void *user_data, int (*user_data_cmp)(void*, void*), bool primary)
 {
     struct fo_server *server;
 
     DEBUG(3, ("Adding new server '%s', to service '%s'\n",
               name ? name : "(no name)", service->name));
     DLIST_FOR_EACH(server, service->server_list) {
-        if (fo_server_match(server, name, port, user_data)) {
+        if (fo_server_match(server, name, port, user_data, user_data_cmp)) {
             return EEXIST;
         }
     }
diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
index b69e8a5..a8a713e 100644
--- a/src/providers/fail_over.h
+++ b/src/providers/fail_over.h
@@ -114,10 +114,13 @@ int fo_get_server_count(struct fo_service *service);
 /*
  * Adds a server 'name' to the 'service'. Port 'port' will be used for
  * connection. If 'name' is NULL, no server resolution will be done.
+ * Function pointed by user_data_cmp returns 0 (equal) or !=0 (not equal)
+ * and can be set to NULL if no duplicity check is needed.
  */
 int fo_add_server(struct fo_service *service,
                   const char *name, int port,
-                  void *user_data, bool primary);
+                  void *user_data, int (*user_data_cmp)(void*, void*),
+                  bool primary);
 
 
 int fo_add_srv_server(struct fo_service *service,
@@ -125,7 +128,8 @@ int fo_add_srv_server(struct fo_service *service,
                       const char *discovery_domain,
                       const char *sssd_domain,
                       const char *proto,
-                      void *user_data);
+                      void *user_data,
+                      int (*user_data_cmp)(void*, void*));
 
 /*
  * Request the first server from the service's list of servers. It is only
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index bf62fcb..617cf86 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -837,7 +837,7 @@ errno_t ipa_servers_init(struct be_ctx *ctx,
 
             ipa_domain = dp_opt_get_string(options->basic, IPA_DOMAIN);
             ret = be_fo_add_srv_server(ctx, "IPA", "ldap", ipa_domain,
-                                       BE_FO_PROTO_TCP, false, NULL);
+                                       BE_FO_PROTO_TCP, false, NULL, NULL);
             if (ret) {
                 DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n"));
                 goto done;
@@ -847,7 +847,7 @@ errno_t ipa_servers_init(struct be_ctx *ctx,
             continue;
         }
 
-        ret = be_fo_add_server(ctx, "IPA", list[i], 0, NULL, primary);
+        ret = be_fo_add_server(ctx, "IPA", list[i], 0, NULL, NULL, primary);
         if (ret && ret != EEXIST) {
             DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n"));
             goto done;
diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
index 98a2f7d..7ec233f 100644
--- a/src/providers/krb5/krb5_common.c
+++ b/src/providers/krb5/krb5_common.c
@@ -510,7 +510,7 @@ errno_t krb5_servers_init(struct be_ctx *ctx,
             }
 
             ret = be_fo_add_srv_server(ctx, service_name, service_name, NULL,
-                                       BE_FO_PROTO_UDP, true, NULL);
+                                       BE_FO_PROTO_UDP, true, NULL, NULL);
             if (ret) {
                 DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n"));
                 goto done;
@@ -565,7 +565,8 @@ errno_t krb5_servers_init(struct be_ctx *ctx,
         }
 
         ret = be_fo_add_server(ctx, service_name, server_spec, (int) port,
-                               list[i], primary);
+                               list[i], (int (*)(void*, void*)) strcmp,
+                               primary);
         if (ret && ret != EEXIST) {
             DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n"));
             goto done;
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 570ec97..fe2c06b 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -1157,7 +1157,8 @@ errno_t sdap_urls_init(struct be_ctx *ctx,
 
             ret = be_fo_add_srv_server(ctx, service_name,
                                        dns_service_name, NULL,
-                                       BE_FO_PROTO_TCP, false, srv_user_data);
+                                       BE_FO_PROTO_TCP, false, srv_user_data,
+                                       (int (*)(void*, void*)) strcmp);
             if (ret) {
                 DEBUG(0, ("Failed to add server\n"));
                 goto done;
@@ -1186,7 +1187,8 @@ errno_t sdap_urls_init(struct be_ctx *ctx,
         talloc_steal(service, list[i]);
 
         ret = be_fo_add_server(ctx, service->name, lud->lud_host,
-                               lud->lud_port, list[i], primary);
+                               lud->lud_port, list[i],
+                               (int (*)(void*, void*)) strcmp, primary);
         ldap_free_urldesc(lud);
         if (ret) {
             goto done;
-- 
1.7.11.2

