]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
unbound lib work.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 18 Jan 2008 13:52:22 +0000 (13:52 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 18 Jan 2008 13:52:22 +0000 (13:52 +0000)
git-svn-id: file:///svn/unbound/trunk@880 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
doc/libunbound.3
libunbound/context.h
libunbound/unbound.c
libunbound/unbound.h
libunbound/worker.c
libunbound/worker.h
smallapp/unbound-host.c

index 02911a0f565607dc0a18349a9f8c02e718e180a5..2935af0a10394daabb15c49c6265e57cc1c32ff6 100644 (file)
@@ -6,6 +6,8 @@
        - goodbye ip4to6 mapping.
        - update ldns-testpkts with latest version from ldns-trunk.
        - updated makedist for relative ldns pathnames.
+       - library API with more information inside the result structure.
+       - work on background resolves.
 
 17 January 2008: Wouter
        - fixup configure in case -lldns is installed.
index a49e8b16dcd64bad88513307a04725438237dc4f..d2a2bfd95d43f3c27cbc493836787d181024ba8a 100644 (file)
@@ -245,11 +245,16 @@ The result of the DNS resolution and validation is returned as
                char** data; /* array of rdata items, NULL terminated*/
                int* len;    /* array with lengths of rdata items */
                char* canonname; /* canonical name of result */
-               int rcode;   /* additional error code in case of error */
-               int nxdomain; /* true if nodata because no domain */
-               int bogus;   /* true if there was a security failure */
+               int rcode;   /* additional error code in case of no data */
+               int havedata; /* true if there is data */
+               int nxdomain; /* true if nodata because name does not exist */
+               int secure;  /* true if result is secure */
+               int bogus;   /* true if a security failure happened */
        };
 .fi
+.P
+If both secure and bogus are false, security was not enabled for the 
+domain of the query.
 .SH "RETURN VALUES"
 Many routines return an error code. The value 0 (zero) denotes no error
 happened. Other values can be passed to
index 8a472d63d119477bdb77f06641ced8c3b4e1e499..1362ad01e8af3272c1344a7554936fcbaa94ad45 100644 (file)
@@ -154,10 +154,11 @@ struct ctx_query {
 enum ub_ctx_err {
        /** no error */
        UB_NOERROR = 0,
+       /** socket operation. Set to -1, so that if an error from _fd() is
+        * passed (-1) it gives a socket error. */
+       UB_SOCKET = -1,
        /** alloc failure */
-       UB_NOMEM = -1,
-       /** socket operation */
-       UB_SOCKET = -2,
+       UB_NOMEM = -2,
        /** syntax error */
        UB_SYNTAX = -3,
        /** DNS service failed */
index fc39982b332ceed31927672cf6a893420b604737..6785c9e97449f84623430708d45617c608168ca8 100644 (file)
@@ -304,7 +304,7 @@ ub_val_ctx_process(struct ub_val_ctx* ctx)
 
 int 
 ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, 
-       int rrclass, int* secure, int* data, struct ub_val_result** result)
+       int rrclass, struct ub_val_result** result)
 {
        struct ctx_query* q;
        int r;
@@ -323,8 +323,6 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
        if(!q)
                return UB_NOMEM;
        /* become a resolver thread for a bit */
-       *secure = 0;
-       *data = 0;
        *result = NULL;
 
        r = libworker_fg(ctx, q);
@@ -333,11 +331,6 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
                free(q);
                return r;
        }
-
-       if(q->msg_security == sec_status_secure)
-               *secure = 1;
-       if(q->res->data && q->res->data[0])
-               *data = 1;
        *result = q->res;
 
        (void)rbtree_delete(&ctx->queries, q->node.key);
@@ -418,8 +411,8 @@ ub_val_strerror(int err)
 {
        switch(err) {
                case UB_NOERROR: return "no error";
-               case UB_NOMEM: return "out of memory";
                case UB_SOCKET: return "socket io error";
+               case UB_NOMEM: return "out of memory";
                case UB_SYNTAX: return "syntax error";
                case UB_SERVFAIL: return "server failure";
                case UB_FORKFAIL: return "could not fork";
index 711caefa3be0232daeb0b7402ae66a601b0e0a93..91d39fd3d93a5c4bc785bb7e3cc54f2dfdf74695 100644 (file)
  *     shared cache data from the context.
  *
  * Application threaded. Non-blocking ('asynchronous').
+ *     ... setup threaded-asynchronous config option
  *     err = ub_val_ctx_async(ctx, 1);
  *     ... same as async for non-threaded
  *     ... the callbacks are called in the thread that calls process(ctx)
  *
- * If not threading is compiled in, the above async example uses fork(2) to
+ * If no threading is compiled in, the above async example uses fork(2) to
  * create a process to perform the work. The forked process exits when the 
  * calling process exits, or ctx_delete() is called.
  * Otherwise, for asynchronous with threading, a worker thread is created.
@@ -85,9 +86,9 @@
  * The blocking calls use shared ctx-cache when threaded. Thus
  * ub_val_resolve() and ub_val_resolve_async() && ub_val_ctx_wait() are
  * not the same. The first makes the current thread do the work, setting
- * up buffers, etc, to perform its thing (but using shared cache data).
+ * up buffers, etc, to perform the work (but using shared cache data).
  * The second calls another worker thread (or process) to perform the work.
- * And no buffers need to be setup, but a context-switch happens.
+ * And no buffers need to be set up, but a context-switch happens.
  */
 #ifndef _UB_UNBOUND_H
 #define _UB_UNBOUND_H
@@ -138,6 +139,12 @@ struct ub_val_result {
         */
        int rcode;
 
+       /**
+        * If there is any data, this is true.
+        * If false, there was no data (nxdomain may be true, rcode can be set).
+        */
+       int havedata;
+
        /** 
         * If there was no data, and the domain did not exist, this is true.
         * If it is false, and there was no data, then the domain name 
@@ -145,6 +152,16 @@ struct ub_val_result {
         */
        int nxdomain;
 
+       /**
+        * True, if the result is validated securely.
+        * False, if validation failed or domain queried has no security info.
+        *
+        * It is possible to get a result with no data (havedata is false),
+        * and secure is true. This means that the non-existance of the data
+        * was cryptographically proven (with signatures).
+        */
+       int secure;
+
        /** 
         * If the result was not secure (secure==0), and this result is due 
         * to a security failure, bogus is true.
@@ -165,16 +182,15 @@ struct ub_val_result {
  * void my_callback(void* my_arg, int err, int secure, int havedata,
  *     struct ub_val_result* result);
  * It is called with
- *     my_arg: your pointer to a (struct of) data of your choice, or NULL.
- *     err: if 0 all is OK, otherwise an error occured and no results
+ *     void* my_arg: your pointer to a (struct of) data of your choice, 
+ *             or NULL.
+ *     int err: if 0 all is OK, otherwise an error occured and no results
  *          are forthcoming.
- *     secure: if true, the result is validated securely.
- *     havedata: if true, there was data, false if no data.
- *     result: pointer to more detailed result structure.
+ *     struct result: pointer to more detailed result structure.
  *             This structure is allocated on the heap and needs to be
  *             freed with ub_val_result_free(result);
  */
-typedef void (*ub_val_callback_t)(void*, int, int, int, struct ub_val_result*);
+typedef void (*ub_val_callback_t)(void*, int, struct ub_val_result*);
 
 /**
  * Create a resolving and validation context.
@@ -306,19 +322,13 @@ int ub_val_ctx_process(struct ub_val_ctx* ctx);
  * @param name: domain name in text format (a zero terminated text string).
  * @param rrtype: type of RR in host order, 1 is A (address).
  * @param rrclass: class of RR in host order, 1 is IN (for internet).
- * @param secure: returns true if the answer validated securely.
- *     false if not.
- *     It is possible to get a result with no data (data is false),
- *     and secure is true. This means that the non-existance of the data
- *     was cryptographically proven (with signatures).
- * @param data: returns false if there was no data, or the domain did not exist,
- *     else true.
  * @param result: the result data is returned in a newly allocated result
- *     structure.
+ *     structure. May be NULL on return, return value is set to an error 
+ *     in that case (out of memory).
  * @return 0 if OK, else error.
  */
 int ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, 
-       int rrclass, int* secure, int* data, struct ub_val_result** result);
+       int rrclass, struct ub_val_result** result);
 
 /**
  * Perform resolution and validation of the target name.
@@ -337,14 +347,13 @@ int ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
  *     It is called as:
  *     void callback(void* mydata, int err, int secure, int havedata, 
  *             struct ub_val_result* result)
- *     with mydata, the same as passed here,
- *     with err is 0 when a result has been found.
- *     with secure true if the answer validated securely.
- *     with havedata true if any data was found.
- *     with result newly allocated result structure.
+ *     with mydata: the same as passed here, you may pass NULL,
+ *     with err: is 0 when a result has been found.
+ *     with result: a newly allocated result structure.
+ *             The result may be NULL, in that case err is set.
  *
  *     If an error happens during processing, your callback will be called
- *     with error set to a nonzero value (and secure=0, data=0, result=0).
+ *     with error set to a nonzero value (and result==NULL).
  * @param async_id: if you pass a non-NULL value, an identifier number is
  *     returned for the query as it is in progress. It can be used to 
  *     cancel the query.
index c890bb2f17d097fc9ffb052c18ed7598185c2f7c..f2a48da93430933108923bd25ff08b6ceff8dbd6 100644 (file)
@@ -78,6 +78,8 @@ libworker_delete(struct libworker* w)
                free(w->env);
        }
        outside_network_delete(w->back);
+       comm_point_delete(w->cmd_com);
+       comm_point_delete(w->res_com);
        comm_base_delete(w->base);
        free(w);
 }
@@ -153,14 +155,86 @@ libworker_setup(struct ub_val_ctx* ctx)
        return w;
 }
 
+static int 
+libworker_handle_control_cmd(struct comm_point* c, void* arg, 
+       int err, struct comm_reply* ATTR_UNUSED(rep))
+{
+       /*struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;*/
+       if(err != NETEVENT_NOERROR) {
+               if(err == NETEVENT_CLOSED) {
+                       /* parent closed pipe, must have exited somehow */
+                       /* it is of no use to go on, exit */
+                       exit(0);
+               }
+               log_err("internal error: control cmd err %d", err);
+               exit(0);
+       }
+       return 0;
+}
+
+static int 
+libworker_handle_result_write(struct comm_point* c, void* arg, 
+       int err, struct comm_reply* ATTR_UNUSED(rep))
+{
+       /*struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;*/
+       if(err != NETEVENT_NOERROR) {
+               if(err == NETEVENT_CLOSED) {
+                       /* parent closed pipe, must have exited somehow */
+                       /* it is of no use to go on, exit */
+                       exit(0);
+               }
+               log_err("internal error: pipe comm err %d", err);
+               exit(0);
+       }
+       return 0;
+}
+
+/** get bufsize for cfg */
+static size_t
+getbufsz(struct ub_val_ctx* ctx)
+{
+       size_t s = 65535;
+       lock_basic_lock(&ctx->cfglock);
+       s = ctx->env->cfg->msg_buffer_size;
+       lock_basic_unlock(&ctx->cfglock);
+       return s;
+}
+
 /** the background thread func */
 static void*
 libworker_dobg(void* arg)
 {
+       /* setup */
        struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;
        struct libworker* w = libworker_setup(ctx);
+       size_t bufsz = getbufsz(ctx);
        log_thread_set(&w->thread_num);
-       /* TODO do bg thread */
+       if(!w) {
+               log_err("libunbound bg worker init failed, nomem");
+               return NULL;
+       }
+       lock_basic_lock(&ctx->qqpipe_lock);
+       if(!(w->cmd_com=comm_point_create_local(w->base, ctx->qqpipe[0], 
+               bufsz, libworker_handle_control_cmd, w))) {
+               lock_basic_unlock(&ctx->qqpipe_lock);
+               log_err("libunbound bg worker init failed, no cmdcom");
+               return NULL;
+       }
+       lock_basic_unlock(&ctx->qqpipe_lock);
+       lock_basic_lock(&ctx->rrpipe_lock);
+       /* TODO create writing local commpoint */
+       if(!(w->res_com=comm_point_create_local(w->base, ctx->rrpipe[1], 
+               bufsz, libworker_handle_result_write, w))) {
+               lock_basic_unlock(&ctx->qqpipe_lock);
+               log_err("libunbound bg worker init failed, no cmdcom");
+               return NULL;
+       }
+       lock_basic_unlock(&ctx->rrpipe_lock);
+
+       /* do the work */
+       comm_base_dispatch(w->base);
+
+       /* cleanup */
        libworker_delete(w);
        return NULL;
 }
@@ -287,10 +361,14 @@ libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s)
        if(!fill_res(d->q->res, reply_find_answer_rrset(&rq, rep), 
                reply_find_final_cname_target(&rq, rep), &rq))
                return; /* out of memory */
-       /* rcode, nxdomain, bogus */
+       /* rcode, havedata, nxdomain, secure, bogus */
        d->q->res->rcode = (int)LDNS_RCODE_WIRE(d->q->msg);
+       if(d->q->res->data && d->q->res->data[0])
+               d->q->res->havedata = 1;
        if(d->q->res->rcode == LDNS_RCODE_NXDOMAIN)
                d->q->res->nxdomain = 1;
+       if(s == sec_status_secure)
+               d->q->res->secure = 1;
        if(s == sec_status_bogus)
                d->q->res->bogus = 1;
 
@@ -340,20 +418,25 @@ int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q)
        qflags = BIT_RD;
        d.q = q;
        d.w = w;
+       /* see if there is a fixed answer */
        if(local_zones_answer(ctx->local_zones, &qinfo, &edns, 
                w->back->udp_buff, w->env->scratch)) {
                libworker_fg_done_cb(&d, LDNS_RCODE_NOERROR, 
                        w->back->udp_buff, sec_status_insecure);
+               libworker_delete(w);
+               return UB_NOERROR;
        }
-       else {
-               if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
-                       w->back->udp_buff, qid, libworker_fg_done_cb, &d)) {
-                       free(qinfo.qname);
-                       return UB_NOMEM;
-               }
+       /* process new query */
+       if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
+               w->back->udp_buff, qid, libworker_fg_done_cb, &d)) {
                free(qinfo.qname);
-               comm_base_dispatch(w->base);
+               return UB_NOMEM;
        }
+       free(qinfo.qname);
+
+       /* wait for reply */
+       comm_base_dispatch(w->base);
+
        libworker_delete(w);
        return UB_NOERROR;
 }
index dae67da43b253bd848e790586d4154c19c817116..3382b6dd92d7c0d29fd0ba320998fd3e14e713b9 100644 (file)
@@ -76,6 +76,10 @@ struct libworker {
 
        /** random() table for this worker. */
        struct ub_randstate* rndstate;
+       /** commpoint to listen to commands */
+       struct comm_point* cmd_com;
+       /** commpoint to write results back (nonblocking) */
+       struct comm_point* res_com;
 };
 
 /**
index 4b5651943590c61b0e4d16052613ac4b57a543cd..f8f8782dc9999ca7839db8d2c7c1c5f28fe400db 100644 (file)
@@ -176,10 +176,10 @@ massage_class(const char* c)
 
 /** nice security status string */
 static const char* 
-statstr(int sec, struct ub_val_result* result)
+secure_str(struct ub_val_result* result)
 {
-       if(sec) return "(secure)";
-       if(result->bogus) return "(BOGUS (security failure))]";
+       if(result->secure) return "(secure)";
+       if(result->bogus) return "(BOGUS (security failure))";
        return "(insecure)";
 }
 
@@ -274,11 +274,10 @@ pretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec,
 
 /** pretty line of output for results */
 static void
-pretty_output(char* q, int t, int c, int sec, int haved, 
-       struct ub_val_result* result, int docname)
+pretty_output(char* q, int t, int c, struct ub_val_result* result, int docname)
 {
        int i;
-       const char *secstatus = statstr(sec, result);
+       const char *secstatus = secure_str(result);
        char tstr[16];
        char cstr[16];
        char rcodestr[16];
@@ -286,7 +285,7 @@ pretty_output(char* q, int t, int c, int sec, int haved,
        pretty_class(cstr, 16, c);
        pretty_rcode(rcodestr, 16, result->rcode);
 
-       if(!haved && result->rcode) {
+       if(!result->havedata && result->rcode) {
                printf("Host %s not found: %d(%s).",
                        q, result->rcode, rcodestr);
                if(verb > 0)
@@ -305,7 +304,7 @@ pretty_output(char* q, int t, int c, int sec, int haved,
        /* remove trailing . from long canonnames for nicer output */
        if(result->canonname && strlen(result->canonname) > 1)
                result->canonname[strlen(result->canonname)-1] = 0;
-       if(!haved) {
+       if(!result->havedata) {
                if(verb > 0) {
                        printf("%s", result->canonname?result->canonname:q);
                        if(strcmp(cstr, "IN") != 0)
@@ -339,15 +338,15 @@ pretty_output(char* q, int t, int c, int sec, int haved,
 static int
 dnslook(struct ub_val_ctx* ctx, char* q, int t, int c, int docname)
 {
-       int ret, sec, haved;
+       int ret;
        struct ub_val_result* result;
 
-       ret = ub_val_resolve(ctx, q, t, c, &sec, &haved, &result);
+       ret = ub_val_resolve(ctx, q, t, c, &result);
        if(ret != 0) {
                fprintf(stderr, "resolve error: %s\n", ub_val_strerror(ret));
                exit(1);
        }
-       pretty_output(q, t, c, sec, haved, result, docname);
+       pretty_output(q, t, c, result, docname);
        ret = result->nxdomain;
        ub_val_result_free(result);
        return ret;