On 08/07/2013 01:56 PM, Lukas Slebodnik wrote:
On (06/08/13 14:43), Pavel Březina wrote:
On 08/06/2013 10:20 AM, Lukas Slebodnik wrote:
On (05/08/13 15:24), Pavel Březina wrote:
https://fedorahosted.org/sssd/ticket/2001

There is a bug in underlying resolv_sort_srv_reply(). It sometimes
returns less servers than there is on the input. This seems to be
related to configuration when two servers has the same priority and
weight (0). I haven't found the root cause yet, I'll investigate
more.

NACK

>From ab328b91f0bdd5168a5d09f3748e5b2091c085b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com>
Date: Sat, 3 Aug 2013 01:02:02 +0200
Subject: [PATCH 3/7] Add is_host_in_domain() util function

Tests failed with 3rd patch and last patch did not fix this.

FAIL: util-tests
============================================================================
Testsuite summary for sssd 1.10.93
============================================================================
# TOTAL: 30
# PASS:  29
# SKIP:  0
# XFAIL: 0
# FAIL:  1
# XPASS: 0
# ERROR: 0
============================================================================
See ./test-suite.log
Please report to sssd-devel@lists.fedorahosted.org
============================================================================
make[3]: *** [test-suite.log] Error 1
make[3]: Leaving directory `/dev/shm/sssd_build'
make[2]: *** [check-TESTS] Error 2
make[2]: Leaving directory `/dev/shm/sssd_build'
make[1]: *** [check-am] Error 2
make[1]: Leaving directory `/dev/shm/sssd_build'
make: *** [check-recursive] Error 1

bash$ cat util-tests.log
Running suite(s): util
test_murmurhash3_random seed: 1375776937
95%: Checks: 20, Failures: 1, Errors: 0
../sssd/src/tests/util-tests.c:833:F:util:test_is_host_in_domain:0: Host: 
example.com, Domain: child.example.com, Expected: 0, Got: 1

LS

Thanks. I switch from int to size_t after running the tests and it
caused troubles, because size_t is obviously unsigned.

New patches are attached.


From 592f208dd35703fed7da813dcef7f61724d94edb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com>
Date: Fri, 2 Aug 2013 23:07:53 +0200
Subject: [PATCH 1/5] resolv_sort_srv_reply: remove unnecessary mem_ctx

ACK

From 978227dcd225948d58fdb00b501da7e8c230f9fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com>
Date: Thu, 1 Aug 2013 16:15:58 +0200
Subject: [PATCH 2/5] fo_discover_srv_send: allow custom ordering function

+    state->sort_srv_fn = sort_srv_fn;
+    state->sort_srv_pvt = sort_srv_pvt;
+
     subreq = resolv_discover_srv_send(state, ev, resolv_ctx, service,
                                       protocol, discovery_domains);
     if (subreq == NULL) {
@@ -98,7 +106,11 @@ static void fo_discover_srv_done(struct tevent_req *subreq)
     DEBUG(SSSDBG_TRACE_FUNC, ("Got answer. Processing...\n"));

     /* sort and store the answer */
-    ret = resolv_sort_srv_reply(&reply_list);
+    if (state->sort_srv_fn == NULL) {
+        ret = resolv_sort_srv_reply(&reply_list);
+    } else {
+        ret = state->sort_srv_fn(&reply_list, state->sort_srv_pvt);
+    }
resolv_sort_srv_reply is called inside of ad_sort_servers
(only one implenentation of sorting function state->sort_srv_fn)
Would it be better to call resolv_sort_srv_reply here every time?

I had it originally like that, but I think it is better this way, In my opinion, if a sorting function is provided, it should not expect that the list is already presorted. Otherwise we may get into trouble with future changes.

     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Could not sort the answers from DNS "
                                     "[%d]: %s\n", ret, strerror(ret)));
@@ -172,6 +184,8 @@ struct fo_discover_servers_state {
     const char *protocol;
     const char *primary_domain;
     const char *backup_domain;
+    fo_sort_srv_list_t sort_srv_fn;
+    void *sort_srv_pvt;


From ff7cd0f69449d8b2382a041d4424ca0b2ef5410e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com>
Date: Sat, 3 Aug 2013 01:02:02 +0200
Subject: [PATCH 3/5] Add is_host_in_domain() util function

---
src/tests/util-tests.c | 28 ++++++++++++++++++++++++++++
src/util/util.c        | 15 +++++++++++++++
src/util/util.h        |  2 ++
3 files changed, 45 insertions(+)
test++ :-). It is really good.
ACK

From 7cd5f605121ab8af457400c13f7e6374a90535df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com>
Date: Fri, 2 Aug 2013 23:01:57 +0200
Subject: [PATCH 4/5] ad srv: prefer servers that are in the same domain as
client

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

diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
index 
dfb15b30c634f2fc672d1072425dc48bdf6b7740..cd60cf6ee8669b32840a6156a04bbaf300ac222b
 100644
--- a/src/providers/ad/ad_srv.c
+++ b/src/providers/ad/ad_srv.c
@@ -38,6 +38,15 @@
#define AD_AT_NT_VERSION "NtVer"
#define AD_AT_NETLOGON "netlogon"

+#define APPEND_ARES_LIST(dst_tail, src_head, src_tail) do { \
+    if (src_head->next != NULL) { \
+        dst_tail->next = src_head->next; \
+        dst_tail = src_tail; \
+        src_head->next = NULL; \
+        src_tail = src_head; \
+    } \
+} while (0);
+
struct ad_get_dc_servers_state {
     struct fo_server_info *servers;
     size_t num_servers;
@@ -548,6 +557,77 @@ static void ad_srv_plugin_dcs_done(struct tevent_req 
*subreq);
static void ad_srv_plugin_site_done(struct tevent_req *subreq);
static void ad_srv_plugin_servers_done(struct tevent_req *subreq);

+static errno_t ad_sort_servers(struct ares_srv_reply **list, void *pvt)
+{
+    struct ad_srv_plugin_state *state = NULL;
+    struct ares_srv_reply dummy[3] = {{NULL, NULL, 0, 0, 0}};
+    struct ares_srv_reply *head = &dummy[0];
+    struct ares_srv_reply *tail = &dummy[0];
+    struct ares_srv_reply *in_head = &dummy[1];
+    struct ares_srv_reply *in_tail = &dummy[1];
+    struct ares_srv_reply *out_head = &dummy[2];
+    struct ares_srv_reply *out_tail = &dummy[2];
+    struct ares_srv_reply *cur = NULL;
+    struct ares_srv_reply *next = NULL;
+    const char *domain = NULL;
+    errno_t ret;
+
+    if (list == NULL) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (*list == NULL || (*list)->next == NULL) {
+        ret = EOK;
+        goto done;
+    }
+
+    state = talloc_get_type(pvt, struct ad_srv_plugin_state);
+    domain = state->discovery_domain;
+
+    /* first sort by rfc2782 */
+    ret = resolv_sort_srv_reply(list);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("resolv_sort_srv_reply() failed "
+                                    "[%d]: %s\n", ret, strerror(ret)));
+        goto done;
+    }
+
+    /* when several servers share priority, prefer the one that is located
+     * in the same domain as client (e.g. child domain instead of forest
+     * root) */
+
+    next = *list;
+    do {
+        cur = next;
+        next = cur->next;
+
+        if (is_host_in_domain(cur->host, domain)) {
+            in_tail->next = cur;
+            in_tail = in_tail->next;
+            in_tail->next = NULL;
+        } else {
+            out_tail->next = cur;
+            out_tail = out_tail->next;
+            out_tail->next = NULL;
+        }
+
+        if (next == NULL || cur->priority != next->priority) {
+            /* priority has changed or we have reached the end of the srv list,
+             * we will merge the lists */
+            APPEND_ARES_LIST(tail, in_head, in_tail);
+            APPEND_ARES_LIST(tail, out_head, out_tail);
+        }
+    } while (next != NULL);
+
+    *list = head->next;
+
+    ret = EOK;
+
+done:
+    return ret;
+}

I am sorry, but this linked list sorting is not very readable.
There is a lot of "struct ares_srv_reply" pointers:
     head, tail, in_head, in_tail, out_head, out_tail, cur, next
I tried to visualize this sorting with pencil and paper, but
it was a real mess.

Hehe, it's actually quite simple - it is first level of quicksort, using domain as pivot. It is enough since the list is already presorted.

I will add some more comments and convert to similar api as dlinklist as Simo suggested.


I would prefer to:
   either: use similar approach like in reply_priority_sort
           from file src/resolv/async_resolv.c (merger-sort)
   or: don't change this function, but unit test should be written for this
       function

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to