aboutsummaryrefslogtreecommitdiff
path: root/resolv/resolv_context.c
diff options
context:
space:
mode:
Diffstat (limited to 'resolv/resolv_context.c')
-rw-r--r--resolv/resolv_context.c38
1 files changed, 33 insertions, 5 deletions
diff --git a/resolv/resolv_context.c b/resolv/resolv_context.c
index 5083a40419..0ee2184055 100644
--- a/resolv/resolv_context.c
+++ b/resolv/resolv_context.c
@@ -17,9 +17,11 @@
<http://www.gnu.org/licenses/>. */
#include <resolv_context.h>
+#include <resolv_conf.h>
#include <resolv-internal.h>
#include <assert.h>
+#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
@@ -52,19 +54,37 @@ static __thread struct resolv_context *current attribute_tls_model_ie;
/* Initialize *RESP if RES_INIT is not yet set in RESP->options, or if
res_init in some other thread requested re-initializing. */
static __attribute__ ((warn_unused_result)) bool
-maybe_init (struct __res_state *resp, bool preinit)
+maybe_init (struct resolv_context *ctx, bool preinit)
{
+ struct __res_state *resp = ctx->resp;
if (resp->options & RES_INIT)
{
- if (__res_initstamp != resp->_u._ext.initstamp)
+ /* If there is no associated resolv_conf object despite the
+ initialization, something modified *ctx->resp. Do not
+ override those changes. */
+ if (ctx->conf != NULL && ctx->conf->initstamp != __res_initstamp)
{
if (resp->nscount > 0)
+ /* This call will detach the extended resolver state. */
__res_iclose (resp, true);
- return __res_vinit (resp, 1) == 0;
+ /* And this call will attach it again. */
+ if (__res_vinit (resp, 1) < 0)
+ {
+ /* The configuration no longer matches after failed
+ initialization. */
+ __resolv_conf_put (ctx->conf);
+ ctx->conf = NULL;
+ return false;
+ }
+ /* Delay the release of the old configuration until this
+ point, so that __res_vinit can reuse it if possible. */
+ __resolv_conf_put (ctx->conf);
+ ctx->conf = __resolv_conf_get (ctx->resp);
}
return true;
}
+ assert (ctx->conf == NULL);
if (preinit)
{
if (!resp->retrans)
@@ -75,7 +95,11 @@ maybe_init (struct __res_state *resp, bool preinit)
if (!resp->id)
resp->id = res_randomid ();
}
- return __res_vinit (resp, preinit) == 0;
+
+ if (__res_vinit (resp, preinit) < 0)
+ return false;
+ ctx->conf = __resolv_conf_get (ctx->resp);
+ return true;
}
/* Allocate a new context object and initialize it. The object is put
@@ -87,6 +111,7 @@ context_alloc (struct __res_state *resp)
if (ctx == NULL)
return NULL;
ctx->resp = resp;
+ ctx->conf = __resolv_conf_get (resp);
ctx->__refcount = 1;
ctx->__from_res = true;
ctx->__next = current;
@@ -98,8 +123,11 @@ context_alloc (struct __res_state *resp)
static void
context_free (struct resolv_context *ctx)
{
+ int error_code = errno;
current = ctx->__next;
+ __resolv_conf_put (ctx->conf);
free (ctx);
+ __set_errno (error_code);
}
/* Reuse the current context object. */
@@ -130,7 +158,7 @@ context_get (bool preinit)
struct resolv_context *ctx = context_alloc (&_res);
if (ctx == NULL)
return NULL;
- if (!maybe_init (ctx->resp, preinit))
+ if (!maybe_init (ctx, preinit))
{
context_free (ctx);
return NULL;