From 210cd5852a865e389caf83f220e976114bf2f030 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 26 Aug 2013 16:02:51 +0200
Subject: [PATCH 4/4] ad srv: prefer servers that are in the same domain as
 client

https://fedorahosted.org/sssd/ticket/2001
---
 src/providers/ad/ad_srv.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
index 4ae91f07bfbaafcb12caf82d3e3847f111cdf9fc..af25c10728ea047655013ee474934ed280236aa6 100644
--- a/src/providers/ad/ad_srv.c
+++ b/src/providers/ad/ad_srv.c
@@ -38,6 +38,77 @@
 #define AD_AT_NT_VERSION "NtVer"
 #define AD_AT_NETLOGON "netlogon"
 
+static errno_t ad_sort_servers_by_dns(TALLOC_CTX *mem_ctx,
+                                      const char *domain,
+                                      struct fo_server_info **_srv,
+                                      size_t num)
+{
+    struct fo_server_info *out = NULL;
+    struct fo_server_info *srv = NULL;
+    struct fo_server_info in_domain[num];
+    struct fo_server_info out_domain[num];
+    size_t srv_index = 0;
+    size_t in_index = 0;
+    size_t out_index = 0;
+    size_t i, j;
+
+    if (_srv == NULL) {
+        return EINVAL;
+    }
+
+    srv = *_srv;
+
+    if (num <= 1) {
+        return EOK;
+    }
+
+    out = talloc_zero_array(mem_ctx, struct fo_server_info, num);
+    if (out == NULL) {
+        return ENOMEM;
+    }
+
+    /* When several servers share priority, we will prefer the one that
+     * is located in the same domain as client (e.g. child domain instead
+     * of forest root) but obey their weight. We will use the fact that
+     * the servers are already sorted by priority. */
+
+    for (i = 0; i < num; i++) {
+        if (is_host_in_domain(srv[i].host, domain)) {
+            /* this is a preferred server, push it to the in domain list */
+            in_domain[in_index] = srv[i];
+            in_index++;
+        } else {
+            /* this is a normal server, push it to the out domain list */
+            out_domain[out_index] = srv[i];
+            out_index++;
+        }
+
+        if (i + 1 == num || srv[i].priority != srv[i + 1].priority) {
+            /* priority has changed or we have reached the end of the srv list,
+             * we will merge the list into final list and start over with
+             * next priority */
+            for (j = 0; j < in_index; j++) {
+                out[srv_index] = in_domain[j];
+                talloc_steal(out, out[srv_index].host);
+                srv_index++;
+            }
+
+            for (j = 0; j < out_index; j++) {
+                out[srv_index] = out_domain[j];
+                talloc_steal(out, out[srv_index].host);
+                srv_index++;
+            }
+
+            in_index = 0;
+            out_index = 0;
+        }
+    }
+
+    talloc_free(*_srv);
+    *_srv = out;
+    return EOK;
+}
+
 struct ad_get_dc_servers_state {
     struct fo_server_info *servers;
     size_t num_servers;
@@ -762,6 +833,24 @@ static void ad_srv_plugin_servers_done(struct tevent_req *subreq)
     DEBUG(SSSDBG_TRACE_FUNC, ("Got %lu primary and %lu backup servers\n",
           state->num_primary_servers, state->num_backup_servers));
 
+    ret = ad_sort_servers_by_dns(state, state->discovery_domain,
+                                 &state->primary_servers,
+                                 state->num_primary_servers);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to sort primary servers by DNS"
+                                     "[%d]: %s\n", ret, sss_strerror(ret)));
+        /* continue */
+    }
+
+    ret = ad_sort_servers_by_dns(state, state->discovery_domain,
+                                 &state->backup_servers,
+                                 state->num_backup_servers);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to sort backup servers by DNS"
+                                     "[%d]: %s\n", ret, sss_strerror(ret)));
+        /* continue */
+    }
+
     tevent_req_done(req);
 }
 
-- 
1.7.11.7

