SSIA. Thanks to Steven for testing out this patch.

Martin
>From 6e6f8bb2f09ddb22cbe767e61ebbd9ecb254f05a Mon Sep 17 00:00:00 2001
From: Martin Nagy <mn...@redhat.com>
Date: Fri, 8 Jan 2010 22:32:25 +0100
Subject: [PATCH] Re-create c-ares channels if /etc/resolv.conf is modified

Fixes: #378
---
 server/providers/data_provider_be.c |   12 ++++-
 server/resolv/async_resolv.c        |   95 ++++++++++++++++++++++++++++++-----
 server/resolv/async_resolv.h        |    2 +
 3 files changed, 95 insertions(+), 14 deletions(-)

diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c
index e59f64a..97cc9f8 100644
--- a/server/providers/data_provider_be.c
+++ b/server/providers/data_provider_be.c
@@ -51,9 +51,12 @@
 #define ACCESS_DENY "deny"
 #define NO_PROVIDER "none"
 
+static int data_provider_res_init(DBusMessage *message,
+                                  struct sbus_connection *conn);
+
 struct sbus_method monitor_be_methods[] = {
     { MON_CLI_METHOD_PING, monitor_common_pong },
-    { MON_CLI_METHOD_RES_INIT, monitor_common_res_init },
+    { MON_CLI_METHOD_RES_INIT, data_provider_res_init },
     { NULL, NULL }
 };
 
@@ -1195,3 +1198,10 @@ int main(int argc, const char *argv[])
     return 0;
 }
 
+static int data_provider_res_init(DBusMessage *message,
+                                  struct sbus_connection *conn)
+{
+    resolv_reread_configuration();
+
+    return monitor_common_res_init(message, conn);
+}
diff --git a/server/resolv/async_resolv.c b/server/resolv/async_resolv.c
index 14e9f0c..c350d6c 100644
--- a/server/resolv/async_resolv.c
+++ b/server/resolv/async_resolv.c
@@ -62,6 +62,11 @@ struct fd_watch {
 };
 
 struct resolv_ctx {
+    /* Contexts are linked so we can keep track of them and re-create
+     * the ares channels in all of them at once if we need to. */
+    struct resolv_ctx *prev;
+    struct resolv_ctx *next;
+
     struct tevent_context *ev_ctx;
 
     ares_channel channel;
@@ -69,6 +74,8 @@ struct resolv_ctx {
     struct fd_watch *fds;
 };
 
+struct resolv_ctx *context_list;
+
 static int
 return_code(int ares_code)
 {
@@ -207,6 +214,8 @@ fd_event_close(struct resolv_ctx *ctx, int s)
 static int
 resolv_ctx_destructor(struct resolv_ctx *ctx)
 {
+    DLIST_REMOVE(context_list, ctx);
+
     if (ctx->channel == NULL) {
         DEBUG(1, ("Ares channel already destroyed?\n"));
         return -1;
@@ -218,34 +227,57 @@ resolv_ctx_destructor(struct resolv_ctx *ctx)
     return 0;
 }
 
-int
-resolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
-            struct resolv_ctx **ctxp)
+static int
+recreate_ares_channel(struct resolv_ctx *ctx)
 {
     int ret;
-    struct resolv_ctx *ctx;
+    ares_channel new_channel;
+    ares_channel old_channel;
     struct ares_options options;
 
-    ctx = talloc_zero(mem_ctx, struct resolv_ctx);
-    if (ctx == NULL)
-        return ENOMEM;
-
-    ctx->ev_ctx = ev_ctx;
-
+    DEBUG(4, ("Initializing new c-ares channel\n"));
     /* FIXME: the options would contain
      * the nameservers to contact, the domains
      * to search, timeout... => get from confdb
      */
     options.sock_state_cb = fd_event;
     options.sock_state_cb_data = ctx;
-    ret = ares_init_options(&ctx->channel, &options, ARES_OPT_SOCK_STATE_CB);
+    ret = ares_init_options(&new_channel, &options, ARES_OPT_SOCK_STATE_CB);
     if (ret != ARES_SUCCESS) {
         DEBUG(1, ("Failed to initialize ares channel: %s\n",
                   resolv_strerror(ret)));
-        ret = return_code(ret);
+        return return_code(ret);
+    }
+
+    old_channel = ctx->channel;
+    ctx->channel = new_channel;
+    if (old_channel != NULL) {
+        DEBUG(4, ("Destroying the old c-ares channel\n"));
+        ares_destroy(old_channel);
+    }
+
+    return EOK;
+}
+
+int
+resolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
+            struct resolv_ctx **ctxp)
+{
+    int ret;
+    struct resolv_ctx *ctx;
+
+    ctx = talloc_zero(mem_ctx, struct resolv_ctx);
+    if (ctx == NULL)
+        return ENOMEM;
+
+    ctx->ev_ctx = ev_ctx;
+
+    ret = recreate_ares_channel(ctx);
+    if (ret != EOK) {
         goto done;
     }
 
+    DLIST_ADD(context_list, ctx);
     talloc_set_destructor(ctx, resolv_ctx_destructor);
 
     *ctxp = ctx;
@@ -256,6 +288,17 @@ done:
     return ret;
 }
 
+void
+resolv_reread_configuration(void)
+{
+    struct resolv_ctx *ctx;
+
+    DEBUG(4, ("Recreating all c-ares channels\n"));
+    DLIST_FOR_EACH(ctx, context_list) {
+        recreate_ares_channel(ctx);
+    }
+}
+
 struct hostent *
 resolv_copy_hostent(TALLOC_CTX *mem_ctx, struct hostent *src)
 {
@@ -328,6 +371,7 @@ struct gethostbyname_state {
     struct hostent *hostent;
     int status;
     int timeouts;
+    int retrying;
 };
 
 static void
@@ -358,6 +402,7 @@ resolv_gethostbyname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     state->hostent = NULL;
     state->status = 0;
     state->timeouts = 0;
+    state->retrying = 0;
 
     /* We need to have a wrapper around ares_gethostbyname(), because
      * ares_gethostbyname() can in some cases call it's callback immediately.
@@ -379,6 +424,13 @@ resolv_gethostbyname_done(void *arg, int status, int timeouts, struct hostent *h
     struct tevent_req *req = talloc_get_type(arg, struct tevent_req);
     struct gethostbyname_state *state = tevent_req_data(req, struct gethostbyname_state);
 
+    if (state->retrying == 0 && status == ARES_EDESTRUCTION) {
+        state->retrying = 1;
+        ares_gethostbyname(state->resolv_ctx->channel, state->name,
+                           state->family, resolv_gethostbyname_done, req);
+        return;
+    }
+
     if (hostent != NULL) {
         state->hostent = resolv_copy_hostent(req, hostent);
         if (state->hostent == NULL) {
@@ -521,6 +573,7 @@ struct getsrv_state {
     struct ares_srv_reply *reply_list;
     int status;
     int timeouts;
+    int retrying;
 };
 
 static void
@@ -550,6 +603,7 @@ resolv_getsrv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     state->reply_list = NULL;
     state->status = 0;
     state->timeouts = 0;
+    state->retrying = 0;
 
     subreq = tevent_wakeup_send(req, ev, tv);
     if (subreq == NULL) {
@@ -570,6 +624,13 @@ resolv_getsrv_done(void *arg, int status, int timeouts, unsigned char *abuf, int
     int ret;
     struct ares_srv_reply *reply_list;
 
+    if (state->retrying == 0 && status == ARES_EDESTRUCTION) {
+        state->retrying = 1;
+        ares_query(state->resolv_ctx->channel, state->query,
+                   ns_c_in, ns_t_srv, resolv_getsrv_done, req);
+        return;
+    }
+
     state->status = status;
     state->timeouts = timeouts;
 
@@ -712,6 +773,7 @@ struct gettxt_state {
     struct ares_txt_reply *reply_list;
     int status;
     int timeouts;
+    int retrying;
 };
 
 static void
@@ -741,7 +803,7 @@ resolv_gettxt_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     state->reply_list = NULL;
     state->status = 0;
     state->timeouts = 0;
-
+    state->retrying = 0;
 
     subreq = tevent_wakeup_send(req, ev, tv);
     if (subreq == NULL) {
@@ -762,6 +824,13 @@ resolv_gettxt_done(void *arg, int status, int timeouts, unsigned char *abuf, int
     int ret;
     struct ares_txt_reply *reply_list;
 
+    if (state->retrying == 0 && status == ARES_EDESTRUCTION) {
+        state->retrying = 1;
+        ares_query(state->resolv_ctx->channel, state->query,
+                   ns_c_in, ns_t_txt, resolv_gettxt_done, req);
+        return;
+    }
+
     state->status = status;
     state->timeouts = timeouts;
 
diff --git a/server/resolv/async_resolv.h b/server/resolv/async_resolv.h
index dab2fdf..e051538 100644
--- a/server/resolv/async_resolv.h
+++ b/server/resolv/async_resolv.h
@@ -49,6 +49,8 @@ struct resolv_ctx;
 int resolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
                 struct resolv_ctx **ctxp);
 
+void resolv_reread_configuration(void);
+
 const char *resolv_strerror(int ares_code);
 
 struct hostent *resolv_copy_hostent(TALLOC_CTX *mem_ctx,
-- 
1.6.2.5

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

Reply via email to