From 65c32939bf78767a74ba8d57f4b0a5229b3d829a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Thu, 25 Nov 2010 11:08:37 +0100
Subject: [PATCH] Allow protocol fallback for SRV queries

https://fedorahosted.org/sssd/ticket/691
---
 src/providers/data_provider_fo.c |   25 ++++++++++++++++++++++---
 src/providers/dp_backend.h       |   10 ++++++++--
 src/providers/fail_over.c        |    4 ++--
 src/providers/ipa/ipa_common.c   |    2 +-
 src/providers/krb5/krb5_common.c |    2 +-
 src/providers/ldap/ldap_common.c |    5 ++---
 6 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index dff0aef..8617cd2 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -54,6 +54,8 @@ struct be_failover_ctx {
     struct be_svc_data *svcs;
 };
 
+static const char *proto_table[] = { FO_PROTO_TCP, FO_PROTO_UDP, NULL };
+
 int be_fo_is_srv_identifier(const char *server)
 {
     return server && strcasecmp(server, BE_SRV_IDENTIFIER) == 0;
@@ -258,12 +260,13 @@ int be_fo_service_add_callback(TALLOC_CTX *memctx,
 }
 
 int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name,
-                         const char *query_service, const char *proto,
-                         void *user_data)
+                         const char *query_service, enum be_fo_protocol proto,
+                         bool proto_fallback, void *user_data)
 {
     struct be_svc_data *svc;
     char *domain;
     int ret;
+    int i;
 
     svc = be_fo_find_svc_data(ctx, service_name);
     if (NULL == svc) {
@@ -279,13 +282,29 @@ int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name,
         return ret;
     }
 
+    /* Add the first protocol as the primary lookup */
     ret = fo_add_srv_server(svc->fo_service, query_service,
-                            domain, proto, user_data);
+                            domain, proto_table[proto], user_data);
     if (ret && ret != EEXIST) {
         DEBUG(1, ("Failed to add SRV lookup reference to failover service\n"));
         return ret;
     }
 
+    if (proto_fallback) {
+        i = (proto + 1) % BE_FO_PROTO_SENTINEL;
+        /* All the rest as fallback */
+        while (i != proto) {
+            ret = fo_add_srv_server(svc->fo_service, query_service,
+                                    domain, proto_table[i], user_data);
+            if (ret && ret != EEXIST) {
+                DEBUG(1, ("Failed to add SRV lookup reference to failover service\n"));
+                return ret;
+            }
+
+            i = (i + 1) % BE_FO_PROTO_SENTINEL;
+        }
+    }
+
     return EOK;
 }
 
diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
index a31e458..e11b3b6 100644
--- a/src/providers/dp_backend.h
+++ b/src/providers/dp_backend.h
@@ -157,6 +157,12 @@ int be_add_offline_cb(TALLOC_CTX *mem_ctx,
 void be_run_offline_cb(struct be_ctx *be);
 
 /* from data_provider_fo.c */
+enum be_fo_protocol {
+    BE_FO_PROTO_TCP,
+    BE_FO_PROTO_UDP,
+    BE_FO_PROTO_SENTINEL
+};
+
 typedef void (be_svc_callback_fn_t)(void *, struct fo_server *);
 
 int be_init_failover(struct be_ctx *ctx);
@@ -167,8 +173,8 @@ int be_fo_service_add_callback(TALLOC_CTX *memctx,
                                be_svc_callback_fn_t *fn, void *private_data);
 int be_fo_get_server_count(struct be_ctx *ctx, const char *service_name);
 int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name,
-                         const char *query_service, const char *proto,
-                         void *user_data);
+                         const char *query_service, enum be_fo_protocol proto,
+                         bool proto_fallback, void *user_data);
 int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
                      const char *server, int port, void *user_data);
 
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
index fa91aec..9b818d0 100644
--- a/src/providers/fail_over.c
+++ b/src/providers/fail_over.c
@@ -502,8 +502,8 @@ fo_add_srv_server(struct fo_service *service, const char *srv,
 {
     struct fo_server *server;
 
-    DEBUG(3, ("Adding new SRV server in domain '%s', to service '%s'\n",
-              dns_domain ? dns_domain : "unknown", service->name));
+    DEBUG(3, ("Adding new SRV server in domain '%s', to service '%s' using %s\n",
+              dns_domain ? dns_domain : "unknown", service->name, proto));
 
     DLIST_FOR_EACH(server, service->server_list) {
         if (server->user_data != user_data)
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index aee8b65..a7f4494 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -625,7 +625,7 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
 
         if (be_fo_is_srv_identifier(list[i])) {
             ret = be_fo_add_srv_server(ctx, "IPA", "ldap",
-                                       FO_PROTO_TCP, NULL);
+                                       BE_FO_PROTO_TCP, false, NULL);
             if (ret) {
                 DEBUG(0, ("Failed to add server\n"));
                 goto done;
diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
index 4d57725..bf47dcc 100644
--- a/src/providers/krb5/krb5_common.c
+++ b/src/providers/krb5/krb5_common.c
@@ -387,7 +387,7 @@ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
 
         if (be_fo_is_srv_identifier(server_spec)) {
             ret = be_fo_add_srv_server(ctx, service_name, service_name,
-                                       FO_PROTO_TCP, NULL);
+                                       BE_FO_PROTO_UDP, true, NULL);
             if (ret) {
                 DEBUG(0, ("Failed to add server\n"));
                 goto done;
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 5de3d55..aa0bac6 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -692,9 +692,8 @@ int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
                 goto done;
             }
 
-            ret = be_fo_add_srv_server(ctx, service_name,
-                                       dns_service_name, FO_PROTO_TCP,
-                                       srv_user_data);
+            ret = be_fo_add_srv_server(ctx, service_name, dns_service_name,
+                                       BE_FO_PROTO_TCP, false, srv_user_data);
             if (ret) {
                 DEBUG(0, ("Failed to add server\n"));
                 goto done;
-- 
1.7.3.2

