summaryrefslogtreecommitdiffstats
path: root/contrib/unbound/libunbound/libunbound.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/unbound/libunbound/libunbound.c')
-rw-r--r--contrib/unbound/libunbound/libunbound.c221
1 files changed, 162 insertions, 59 deletions
diff --git a/contrib/unbound/libunbound/libunbound.c b/contrib/unbound/libunbound/libunbound.c
index 7efd4cb..78d3196 100644
--- a/contrib/unbound/libunbound/libunbound.c
+++ b/contrib/unbound/libunbound/libunbound.c
@@ -21,16 +21,16 @@
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
@@ -43,6 +43,7 @@
/* include the public api first, it should be able to stand alone */
#include "libunbound/unbound.h"
+#include "libunbound/unbound-event.h"
#include "config.h"
#include <ctype.h>
#include "libunbound/context.h"
@@ -60,14 +61,18 @@
#include "services/localzone.h"
#include "services/cache/infra.h"
#include "services/cache/rrset.h"
+#include "ldns/sbuffer.h"
+#ifdef HAVE_PTHREAD
+#include <signal.h>
+#endif
#if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H)
#include <windows.h>
#include <iphlpapi.h>
#endif /* UB_ON_WINDOWS */
-struct ub_ctx*
-ub_ctx_create(void)
+/** create context functionality, but no pipes */
+static struct ub_ctx* ub_ctx_create_nopipe(void)
{
struct ub_ctx* ctx;
unsigned int seed;
@@ -102,28 +107,11 @@ ub_ctx_create(void)
return NULL;
}
seed = 0;
- if((ctx->qq_pipe = tube_create()) == NULL) {
- int e = errno;
- ub_randfree(ctx->seed_rnd);
- free(ctx);
- errno = e;
- return NULL;
- }
- if((ctx->rr_pipe = tube_create()) == NULL) {
- int e = errno;
- tube_delete(ctx->qq_pipe);
- ub_randfree(ctx->seed_rnd);
- free(ctx);
- errno = e;
- return NULL;
- }
lock_basic_init(&ctx->qqpipe_lock);
lock_basic_init(&ctx->rrpipe_lock);
lock_basic_init(&ctx->cfglock);
ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env));
if(!ctx->env) {
- tube_delete(ctx->qq_pipe);
- tube_delete(ctx->rr_pipe);
ub_randfree(ctx->seed_rnd);
free(ctx);
errno = ENOMEM;
@@ -131,8 +119,6 @@ ub_ctx_create(void)
}
ctx->env->cfg = config_create_forlib();
if(!ctx->env->cfg) {
- tube_delete(ctx->qq_pipe);
- tube_delete(ctx->rr_pipe);
free(ctx->env);
ub_randfree(ctx->seed_rnd);
free(ctx);
@@ -147,6 +133,50 @@ ub_ctx_create(void)
return ctx;
}
+struct ub_ctx*
+ub_ctx_create(void)
+{
+ struct ub_ctx* ctx = ub_ctx_create_nopipe();
+ if(!ctx)
+ return NULL;
+ if((ctx->qq_pipe = tube_create()) == NULL) {
+ int e = errno;
+ ub_randfree(ctx->seed_rnd);
+ config_delete(ctx->env->cfg);
+ modstack_desetup(&ctx->mods, ctx->env);
+ free(ctx->env);
+ free(ctx);
+ errno = e;
+ return NULL;
+ }
+ if((ctx->rr_pipe = tube_create()) == NULL) {
+ int e = errno;
+ tube_delete(ctx->qq_pipe);
+ ub_randfree(ctx->seed_rnd);
+ config_delete(ctx->env->cfg);
+ modstack_desetup(&ctx->mods, ctx->env);
+ free(ctx->env);
+ free(ctx);
+ errno = e;
+ return NULL;
+ }
+ return ctx;
+}
+
+struct ub_ctx*
+ub_ctx_create_event(struct event_base* eb)
+{
+ struct ub_ctx* ctx = ub_ctx_create_nopipe();
+ if(!ctx)
+ return NULL;
+ /* no pipes, but we have the locks to make sure everything works */
+ ctx->created_bg = 0;
+ ctx->dothread = 1; /* the processing is in the same process,
+ makes ub_cancel and ub_ctx_delete do the right thing */
+ ctx->event_base = eb;
+ return ctx;
+}
+
/** delete q */
static void
delq(rbnode_t* n, void* ATTR_UNUSED(arg))
@@ -155,11 +185,9 @@ delq(rbnode_t* n, void* ATTR_UNUSED(arg))
context_query_delete(q);
}
-void
-ub_ctx_delete(struct ub_ctx* ctx)
+/** stop the bg thread */
+static void ub_stop_bg(struct ub_ctx* ctx)
{
- struct alloc_cache* a, *na;
- if(!ctx) return;
/* stop the bg thread */
lock_basic_lock(&ctx->cfglock);
if(ctx->created_bg) {
@@ -195,7 +223,29 @@ ub_ctx_delete(struct ub_ctx* ctx)
else {
lock_basic_unlock(&ctx->cfglock);
}
+}
+
+void
+ub_ctx_delete(struct ub_ctx* ctx)
+{
+ struct alloc_cache* a, *na;
+ int do_stop = 1;
+ if(!ctx) return;
+ /* see if bg thread is created and if threads have been killed */
+ /* no locks, because those may be held by terminated threads */
+ /* for processes the read pipe is closed and we see that on read */
+#ifdef HAVE_PTHREAD
+ if(ctx->created_bg && ctx->dothread) {
+ if(pthread_kill(ctx->bg_tid, 0) == ESRCH) {
+ /* thread has been killed */
+ do_stop = 0;
+ }
+ }
+#endif /* HAVE_PTHREAD */
+ if(do_stop)
+ ub_stop_bg(ctx);
+ libworker_delete_event(ctx->event_worker);
modstack_desetup(&ctx->mods, ctx->env);
a = ctx->alloc_list;
@@ -419,21 +469,21 @@ process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len,
ub_resolve_free(q->res);
} else {
/* parse the message, extract rcode, fill result */
- ldns_buffer* buf = ldns_buffer_new(q->msg_len);
+ sldns_buffer* buf = sldns_buffer_new(q->msg_len);
struct regional* region = regional_create();
*res = q->res;
(*res)->rcode = LDNS_RCODE_SERVFAIL;
if(region && buf) {
- ldns_buffer_clear(buf);
- ldns_buffer_write(buf, q->msg, q->msg_len);
- ldns_buffer_flip(buf);
+ sldns_buffer_clear(buf);
+ sldns_buffer_write(buf, q->msg, q->msg_len);
+ sldns_buffer_flip(buf);
libworker_enter_result(*res, buf, region,
q->msg_security);
}
(*res)->answer_packet = q->msg;
(*res)->answer_len = (int)q->msg_len;
q->msg = NULL;
- ldns_buffer_free(buf);
+ sldns_buffer_free(buf);
regional_destroy(region);
}
q->res = NULL;
@@ -591,6 +641,45 @@ ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype,
}
int
+ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype,
+ int rrclass, void* mydata, ub_event_callback_t callback, int* async_id)
+{
+ struct ctx_query* q;
+ int r;
+
+ if(async_id)
+ *async_id = 0;
+ lock_basic_lock(&ctx->cfglock);
+ if(!ctx->finalized) {
+ int r = context_finalize(ctx);
+ if(r) {
+ lock_basic_unlock(&ctx->cfglock);
+ return r;
+ }
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ if(!ctx->event_worker) {
+ ctx->event_worker = libworker_create_event(ctx,
+ ctx->event_base);
+ if(!ctx->event_worker) {
+ return UB_INITFAIL;
+ }
+ }
+
+ /* create new ctx_query and attempt to add to the list */
+ q = context_new(ctx, name, rrtype, rrclass, (ub_callback_t)callback,
+ mydata);
+ if(!q)
+ return UB_NOMEM;
+
+ /* attach to mesh */
+ if((r=libworker_attach_mesh(ctx, q, async_id)) != 0)
+ return r;
+ return UB_NOERROR;
+}
+
+
+int
ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
int rrclass, void* mydata, ub_callback_t callback, int* async_id)
{
@@ -1016,7 +1105,8 @@ int ub_ctx_print_local_zones(struct ub_ctx* ctx)
}
/* Add a new zone */
-int ub_ctx_zone_add(struct ub_ctx* ctx, char *zone_name, char *zone_type)
+int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name,
+ const char *zone_type)
{
enum localzone_type t;
struct local_zone* z;
@@ -1035,28 +1125,28 @@ int ub_ctx_zone_add(struct ub_ctx* ctx, char *zone_name, char *zone_type)
return UB_SYNTAX;
}
- lock_quick_lock(&ctx->local_zones->lock);
+ lock_rw_wrlock(&ctx->local_zones->lock);
if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs,
LDNS_RR_CLASS_IN))) {
/* already present in tree */
lock_rw_wrlock(&z->lock);
z->type = t; /* update type anyway */
lock_rw_unlock(&z->lock);
- lock_quick_unlock(&ctx->local_zones->lock);
+ lock_rw_unlock(&ctx->local_zones->lock);
free(nm);
return UB_NOERROR;
}
if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs,
LDNS_RR_CLASS_IN, t)) {
- lock_quick_unlock(&ctx->local_zones->lock);
+ lock_rw_unlock(&ctx->local_zones->lock);
return UB_NOMEM;
}
- lock_quick_unlock(&ctx->local_zones->lock);
+ lock_rw_unlock(&ctx->local_zones->lock);
return UB_NOERROR;
}
/* Remove zone */
-int ub_ctx_zone_remove(struct ub_ctx* ctx, char *zone_name)
+int ub_ctx_zone_remove(struct ub_ctx* ctx, const char *zone_name)
{
struct local_zone* z;
uint8_t* nm;
@@ -1070,37 +1160,29 @@ int ub_ctx_zone_remove(struct ub_ctx* ctx, char *zone_name)
return UB_SYNTAX;
}
- lock_quick_lock(&ctx->local_zones->lock);
+ lock_rw_wrlock(&ctx->local_zones->lock);
if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs,
LDNS_RR_CLASS_IN))) {
/* present in tree */
local_zones_del_zone(ctx->local_zones, z);
}
- lock_quick_unlock(&ctx->local_zones->lock);
+ lock_rw_unlock(&ctx->local_zones->lock);
free(nm);
return UB_NOERROR;
}
/* Add new RR data */
-int ub_ctx_data_add(struct ub_ctx* ctx, char *data)
+int ub_ctx_data_add(struct ub_ctx* ctx, const char *data)
{
- ldns_buffer* buf;
int res = ub_ctx_finalize(ctx);
if (res) return res;
- lock_basic_lock(&ctx->cfglock);
- buf = ldns_buffer_new(ctx->env->cfg->msg_buffer_size);
- lock_basic_unlock(&ctx->cfglock);
- if(!buf) return UB_NOMEM;
-
- res = local_zones_add_RR(ctx->local_zones, data, buf);
-
- ldns_buffer_free(buf);
+ res = local_zones_add_RR(ctx->local_zones, data);
return (!res) ? UB_NOMEM : UB_NOERROR;
}
/* Remove RR data */
-int ub_ctx_data_remove(struct ub_ctx* ctx, char *data)
+int ub_ctx_data_remove(struct ub_ctx* ctx, const char *data)
{
uint8_t* nm;
int nmlabs;
@@ -1122,3 +1204,24 @@ const char* ub_version(void)
{
return PACKAGE_VERSION;
}
+
+int
+ub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base) {
+ if (!ctx || !ctx->event_base || !base) {
+ return UB_INITFAIL;
+ }
+ if (ctx->event_base == base) {
+ /* already set */
+ return UB_NOERROR;
+ }
+
+ lock_basic_lock(&ctx->cfglock);
+ /* destroy the current worker - safe to pass in NULL */
+ libworker_delete_event(ctx->event_worker);
+ ctx->event_worker = NULL;
+ ctx->event_base = base;
+ ctx->created_bg = 0;
+ ctx->dothread = 1;
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
OpenPOWER on IntegriCloud