123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- /* Temporary, thread-local resolver state.
- Copyright (C) 2017-2019 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <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>
- /* Currently active struct resolv_context object. This pointer forms
- the start of a single-linked list, using the __next member of
- struct resolv_context. This list serves two purposes:
- (a) A subsequent call to __resolv_context_get will only increment
- the reference counter and will not allocate a new object. The
- _res state freshness check is skipped in this case, too.
- (b) The per-thread cleanup function defined by the resolver calls
- __resolv_context_freeres, which will deallocate all the context
- objects. This avoids the need for cancellation handlers and
- the complexity they bring, but it requires heap allocation of
- the context object because the per-thread cleanup functions run
- only after the stack has been fully unwound (and all on-stack
- objects have been deallocated at this point).
- The TLS variable current is updated even in
- __resolv_context_get_override, to support case (b) above. This does
- not override the per-thread resolver state (as obtained by the
- non-res_state function such as __resolv_context_get) in an
- observable way because the wrapped context is only used to
- implement the res_n* functions in the resolver, and those do not
- call back into user code which could indirectly use the per-thread
- resolver state. */
- static __thread struct resolv_context *current attribute_tls_model_ie;
- /* The resolv_conf handling will gives us a ctx->conf pointer even if
- these fields do not match because a mis-match does not cause a loss
- of state (_res objects can store the full information). This
- function checks to ensure that there is a full patch, to prevent
- overwriting a patched configuration. */
- static bool
- replicated_configuration_matches (const struct resolv_context *ctx)
- {
- return ctx->resp->options == ctx->conf->options
- && ctx->resp->retrans == ctx->conf->retrans
- && ctx->resp->retry == ctx->conf->retry
- && ctx->resp->ndots == ctx->conf->ndots;
- }
- /* 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 resolv_context *ctx, bool preinit)
- {
- struct __res_state *resp = ctx->resp;
- if (resp->options & RES_INIT)
- {
- if (resp->options & RES_NORELOAD)
- /* Configuration reloading was explicitly disabled. */
- return true;
- /* If there is no associated resolv_conf object despite the
- initialization, something modified *ctx->resp. Do not
- override those changes. */
- if (ctx->conf != NULL && replicated_configuration_matches (ctx))
- {
- struct resolv_conf *current = __resolv_conf_get_current ();
- if (current == NULL)
- return false;
- /* Check if the configuration changed. */
- if (current != ctx->conf)
- {
- /* This call will detach the extended resolver state. */
- if (resp->nscount > 0)
- __res_iclose (resp, true);
- /* Reattach the current configuration. */
- if (__resolv_conf_attach (ctx->resp, current))
- {
- __resolv_conf_put (ctx->conf);
- /* ctx takes ownership, so we do not release current. */
- ctx->conf = current;
- }
- }
- else
- /* No change. Drop the reference count for current. */
- __resolv_conf_put (current);
- }
- return true;
- }
- assert (ctx->conf == NULL);
- if (preinit)
- {
- if (!resp->retrans)
- resp->retrans = RES_TIMEOUT;
- if (!resp->retry)
- resp->retry = RES_DFLRETRY;
- resp->options = RES_DEFAULT;
- if (!resp->id)
- resp->id = res_randomid ();
- }
- 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
- on the current list. */
- static struct resolv_context *
- context_alloc (struct __res_state *resp)
- {
- struct resolv_context *ctx = malloc (sizeof (*ctx));
- if (ctx == NULL)
- return NULL;
- ctx->resp = resp;
- ctx->conf = __resolv_conf_get (resp);
- ctx->__refcount = 1;
- ctx->__from_res = true;
- ctx->__next = current;
- current = ctx;
- return ctx;
- }
- /* Deallocate the context object and all the state within. */
- 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. */
- static struct resolv_context *
- context_reuse (void)
- {
- /* A context object created by __resolv_context_get_override cannot
- be reused. */
- assert (current->__from_res);
- ++current->__refcount;
- /* Check for reference counter wraparound. This can only happen if
- the get/put functions are not properly paired. */
- assert (current->__refcount > 0);
- return current;
- }
- /* Backing function for the __resolv_context_get family of
- functions. */
- static struct resolv_context *
- context_get (bool preinit)
- {
- if (current != NULL)
- return context_reuse ();
- struct resolv_context *ctx = context_alloc (&_res);
- if (ctx == NULL)
- return NULL;
- if (!maybe_init (ctx, preinit))
- {
- context_free (ctx);
- return NULL;
- }
- return ctx;
- }
- struct resolv_context *
- __resolv_context_get (void)
- {
- return context_get (false);
- }
- libc_hidden_def (__resolv_context_get)
- struct resolv_context *
- __resolv_context_get_preinit (void)
- {
- return context_get (true);
- }
- libc_hidden_def (__resolv_context_get_preinit)
- struct resolv_context *
- __resolv_context_get_override (struct __res_state *resp)
- {
- /* NB: As explained asbove, context_alloc will put the context on
- the current list. */
- struct resolv_context *ctx = context_alloc (resp);
- if (ctx == NULL)
- return NULL;
- ctx->__from_res = false;
- return ctx;
- }
- libc_hidden_def (__resolv_context_get_override)
- void
- __resolv_context_put (struct resolv_context *ctx)
- {
- if (ctx == NULL)
- return;
- /* NB: Callers assume that this function preserves errno and
- h_errno. */
- assert (current == ctx);
- assert (ctx->__refcount > 0);
- if (ctx->__from_res && --ctx->__refcount > 0)
- /* Do not pop this context yet. */
- return;
- context_free (ctx);
- }
- libc_hidden_def (__resolv_context_put)
- void
- __resolv_context_freeres (void)
- {
- /* Deallocate the entire chain of context objects. */
- struct resolv_context *ctx = current;
- current = NULL;
- while (ctx != NULL)
- {
- struct resolv_context *next = ctx->__next;
- context_free (ctx);
- ctx = next;
- }
- }
|