summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/providers/data_provider_be.c12
-rw-r--r--server/resolv/async_resolv.c95
-rw-r--r--server/resolv/async_resolv.h2
3 files changed, 95 insertions, 14 deletions
diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c
index e59f64a6..97cc9f87 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 14e9f0c8..c350d6c3 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 dab2fdfc..e0515383 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,