]> granicus.if.org Git - libevent/commitdiff
Ensure that evdns_request is a persistent handle.
authorChristopher Davis <chrisd@mangrin.org>
Thu, 22 Apr 2010 04:21:21 +0000 (21:21 -0700)
committerChristopher Davis <chrisd@mangrin.org>
Thu, 22 Apr 2010 04:21:21 +0000 (21:21 -0700)
When searching is enabled, evdns may make multiple requests before
calling the user callback with the result. This is a problem because
the same evdns_request handle is not retained for each search request,
so the user cannot reliably cancel the request.

This patch attempts to ensure that evdns_request persists accross
search requests.

evdns.c

diff --git a/evdns.c b/evdns.c
index 1635ab261c087ab780c4748027b80f59023f5662..10733ede514bf47e3fdf419f1145b5ca05f510fb 100644 (file)
--- a/evdns.c
+++ b/evdns.c
@@ -145,7 +145,12 @@ typedef unsigned int uint;
 
 #define CLASS_INET     EVDNS_CLASS_INET
 
+/* persistent handle */
 struct evdns_request {
+       struct request *current_req;
+};
+
+struct request {
        u8 *request;  /* the dns packet data */
        u8 request_type; /* TYPE_PTR or TYPE_A or TYPE_AAAA */
        unsigned int request_len;
@@ -155,6 +160,7 @@ struct evdns_request {
        evdns_callback_type user_callback;
        struct nameserver *ns;  /* the server which we last sent it */
 
+       // XXX this could be moved to the evdns_request handle 
        /* elements used by the searching code */
        int search_index;
        struct search_state *search_state;
@@ -162,7 +168,7 @@ struct evdns_request {
        int search_flags;
 
        /* these objects are kept in a circular list */
-       struct evdns_request *next, *prev;
+       struct request *next, *prev;
 
        struct event timeout_event;
 
@@ -174,6 +180,8 @@ struct evdns_request {
        char **put_cname_in_ptr; /* store the cname here if we get one. */
 
        struct evdns_base *base;
+       
+       struct evdns_request *handle;
 };
 
 struct reply {
@@ -281,10 +289,10 @@ struct evdns_base {
        /* An array of n_req_heads circular lists for inflight requests.
         * Each inflight request req is in req_heads[req->trans_id % n_req_heads].
         */
-       struct evdns_request **req_heads;
+       struct request **req_heads;
        /* A circular list of requests that we're waiting to send, but haven't
         * sent yet because there are too many requests inflight */
-       struct evdns_request *req_waiting_head;
+       struct request *req_waiting_head;
        /* A circular list of nameservers. */
        struct nameserver *server_head;
        int n_req_heads;
@@ -364,19 +372,19 @@ evdns_get_global_base(void)
 #define REQ_HEAD(base, id) ((base)->req_heads[id % (base)->n_req_heads])
 
 static struct nameserver *nameserver_pick(struct evdns_base *base);
-static void evdns_request_insert(struct evdns_request *req, struct evdns_request **head);
-static void evdns_request_remove(struct evdns_request *req, struct evdns_request **head);
+static void evdns_request_insert(struct request *req, struct request **head);
+static void evdns_request_remove(struct request *req, struct request **head);
 static void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg);
 static int evdns_transmit(struct evdns_base *base);
-static int evdns_request_transmit(struct evdns_request *req);
+static int evdns_request_transmit(struct request *req);
 static void nameserver_send_probe(struct nameserver *const ns);
-static void search_request_finished(struct evdns_request *const);
-static int search_try_next(struct evdns_request *const req);
-static struct evdns_request *search_request_new(struct evdns_base *base, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
+static void search_request_finished(struct request *const);
+static int search_try_next(struct request *const req);
+static struct request *search_request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
 static void evdns_requests_pump_waiting_queue(struct evdns_base *base);
 static u16 transaction_id_pick(struct evdns_base *base);
-static struct evdns_request *request_new(struct evdns_base *base, int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
-static void request_submit(struct evdns_request *const req);
+static struct request *request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
+static void request_submit(struct request *const req);
 
 static int server_request_free(struct server_request *req);
 static void server_request_free_answers(struct server_request *req);
@@ -485,10 +493,10 @@ _evdns_log(int warn, const char *fmt, ...)
 /* This walks the list of inflight requests to find the */
 /* one with a matching transaction id. Returns NULL on */
 /* failure */
-static struct evdns_request *
+static struct request *
 request_find_from_trans_id(struct evdns_base *base, u16 trans_id) {
-       struct evdns_request *req = REQ_HEAD(base, trans_id);
-       struct evdns_request *const started_at = req;
+       struct request *req = REQ_HEAD(base, trans_id);
+       struct request *const started_at = req;
 
        ASSERT_LOCKED(base);
 
@@ -563,7 +571,7 @@ nameserver_probe_failed(struct nameserver *const ns) {
 /* many packets have timed out etc */
 static void
 nameserver_failed(struct nameserver *const ns, const char *msg) {
-       struct evdns_request *req, *started_at;
+       struct request *req, *started_at;
        struct evdns_base *base = ns->base;
        int i;
 
@@ -633,7 +641,7 @@ nameserver_up(struct nameserver *const ns)
 }
 
 static void
-request_trans_id_set(struct evdns_request *const req, const u16 trans_id) {
+request_trans_id_set(struct request *const req, const u16 trans_id) {
        req->trans_id = trans_id;
        *((u16 *) req->request) = htons(trans_id);
 }
@@ -641,8 +649,9 @@ request_trans_id_set(struct evdns_request *const req, const u16 trans_id) {
 /* Called to remove a request from a list and dealloc it. */
 /* head is a pointer to the head of the list it should be */
 /* removed from or NULL if the request isn't in a list. */
+/* when free_handle is one, free the handle as well. */
 static void
-request_finished(struct evdns_request *const req, struct evdns_request **head) {
+request_finished(struct request *const req, struct request **head, int free_handle) {
        struct evdns_base *base = req->base;
        int was_inflight = (head != &base->req_waiting_head);
        EVDNS_LOCK(base);
@@ -667,6 +676,9 @@ request_finished(struct evdns_request *const req, struct evdns_request **head) {
                /* so everything gets free()ed when we: */
        }
 
+       if (free_handle && req->handle)
+               mm_free(req->handle);
+
        mm_free(req);
 
        evdns_requests_pump_waiting_queue(base);
@@ -680,7 +692,7 @@ request_finished(struct evdns_request *const req, struct evdns_request **head) {
 /*   0 ok */
 /*   1 failed/reissue is pointless */
 static int
-request_reissue(struct evdns_request *req) {
+request_reissue(struct request *req) {
        const struct nameserver *const last_ns = req->ns;
        ASSERT_LOCKED(req->base);
        /* the last nameserver should have been marked as failing */
@@ -708,7 +720,7 @@ evdns_requests_pump_waiting_queue(struct evdns_base *base) {
        ASSERT_LOCKED(base);
        while (base->global_requests_inflight < base->global_max_requests_inflight &&
                   base->global_requests_waiting) {
-               struct evdns_request *req;
+               struct request *req;
                /* move a request from the waiting queue to the inflight queue */
                EVUTIL_ASSERT(base->req_waiting_head);
                req = base->req_waiting_head;
@@ -779,7 +791,7 @@ reply_run_callback(struct deferred_cb *d, void *user_pointer)
 }
 
 static void
-reply_schedule_callback(struct evdns_request *const req, u32 ttl, u32 err, struct reply *reply)
+reply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply)
 {
        struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d));
 
@@ -803,7 +815,7 @@ reply_schedule_callback(struct evdns_request *const req, u32 ttl, u32 err, struc
 
 /* this processes a parsed reply packet */
 static void
-reply_handle(struct evdns_request *const req, u16 flags, u32 ttl, struct reply *reply) {
+reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
        int error;
        static const int error_codes[] = {
                DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
@@ -861,21 +873,21 @@ reply_handle(struct evdns_request *const req, u16 flags, u32 ttl, struct reply *
                                /* the user callback will be made when
                                 * that request (or a */
                                /* child of it) finishes. */
-                               request_finished(req, &REQ_HEAD(req->base, req->trans_id));
+                               request_finished(req, &REQ_HEAD(req->base, req->trans_id), 0);
                                return;
                        }
                }
 
                /* all else failed. Pass the failure up */
                reply_schedule_callback(req, 0, error, NULL);
-               request_finished(req, &REQ_HEAD(req->base, req->trans_id));
+               request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
        } else {
                /* all ok, tell the user */
                reply_schedule_callback(req, ttl, 0, reply);
-               if (req == req->ns->probe_request)
+               if (req->handle == req->ns->probe_request)
                        req->ns->probe_request = NULL; /* Avoid double-free */
                nameserver_up(req->ns);
-               request_finished(req, &REQ_HEAD(req->base, req->trans_id));
+               request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
        }
 }
 
@@ -948,7 +960,7 @@ reply_parse(struct evdns_base *base, u8 *packet, int length) {
        u16 flags = 0;
        u32 ttl, ttl_r = 0xffffffff;
        struct reply reply;
-       struct evdns_request *req = NULL;
+       struct request *req = NULL;
        unsigned int i;
 
        ASSERT_LOCKED(base);
@@ -2037,7 +2049,7 @@ evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, stru
 /* has timed out. */
 static void
 evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
-       struct evdns_request *const req = (struct evdns_request *) arg;
+       struct request *const req = (struct request *) arg;
 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
        struct evdns_base *base = req->base;
 #endif
@@ -2056,7 +2068,7 @@ evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
        if (req->tx_count >= req->base->global_max_retransmits) {
                /* this request has failed */
                reply_schedule_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
-               request_finished(req, &REQ_HEAD(req->base, req->trans_id));
+               request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
        } else {
                /* retransmit it */
                (void) evtimer_del(&req->timeout_event);
@@ -2072,7 +2084,7 @@ evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
 /*   1 temporary failure */
 /*   2 other failure */
 static int
-evdns_request_transmit_to(struct evdns_request *req, struct nameserver *server) {
+evdns_request_transmit_to(struct request *req, struct nameserver *server) {
        int r;
        ASSERT_LOCKED(req->base);
        r = sendto(server->socket, req->request, req->request_len, 0,
@@ -2097,7 +2109,7 @@ evdns_request_transmit_to(struct evdns_request *req, struct nameserver *server)
 /*   0 ok */
 /*   1 failed */
 static int
-evdns_request_transmit(struct evdns_request *req) {
+evdns_request_transmit(struct request *req) {
        int retcode = 0, r;
 
        ASSERT_LOCKED(req->base);
@@ -2165,17 +2177,19 @@ nameserver_probe_callback(int result, char type, int count, int ttl, void *addre
 
 static void
 nameserver_send_probe(struct nameserver *const ns) {
-       struct evdns_request *req;
+       struct evdns_request *handle;
+       struct request *req;
        /* here we need to send a probe to a given nameserver */
        /* in the hope that it is up now. */
 
        ASSERT_LOCKED(ns->base);
        log(EVDNS_LOG_DEBUG, "Sending probe to %s",
                debug_ntop((struct sockaddr *)&ns->address));
-
-       req = request_new(ns->base, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
+       handle = mm_calloc(1, sizeof(*handle));
+       if (!handle) return;
+       req = request_new(ns->base, handle, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
        if (!req) return;
-       ns->probe_request = req;
+       ns->probe_request = handle;
        /* we force this into the inflight queue no matter what */
        request_trans_id_set(req, transaction_id_pick(ns->base));
        req->ns = ns;
@@ -2193,7 +2207,7 @@ evdns_transmit(struct evdns_base *base) {
        ASSERT_LOCKED(base);
        for (i = 0; i < base->n_req_heads; ++i) {
                if (base->req_heads[i]) {
-                       struct evdns_request *const started_at = base->req_heads[i], *req = started_at;
+                       struct request *const started_at = base->req_heads[i], *req = started_at;
                        /* first transmit all the requests which are currently waiting */
                        do {
                                if (req->transmit_me) {
@@ -2265,10 +2279,10 @@ evdns_base_clear_nameservers_and_suspend(struct evdns_base *base)
        base->global_good_nameservers = 0;
 
        for (i = 0; i < base->n_req_heads; ++i) {
-               struct evdns_request *req, *req_started_at;
+               struct request *req, *req_started_at;
                req = req_started_at = base->req_heads[i];
                while (req) {
-                       struct evdns_request *next = req->next;
+                       struct request *next = req->next;
                        req->tx_count = req->reissue_count = 0;
                        req->ns = NULL;
                        /* ???? What to do about searches? */
@@ -2477,13 +2491,13 @@ evdns_nameserver_ip_add(const char *ip_as_string) {
 
 /* remove from the queue */
 static void
-evdns_request_remove(struct evdns_request *req, struct evdns_request **head)
+evdns_request_remove(struct request *req, struct request **head)
 {
        ASSERT_LOCKED(req->base);
 
 #if 0
        {
-               struct evdns_request *ptr;
+               struct request *ptr;
                int found = 0;
                EVUTIL_ASSERT(*head != NULL);
 
@@ -2514,7 +2528,7 @@ evdns_request_remove(struct evdns_request *req, struct evdns_request **head)
 
 /* insert into the tail of the queue */
 static void
-evdns_request_insert(struct evdns_request *req, struct evdns_request **head) {
+evdns_request_insert(struct request *req, struct request **head) {
        ASSERT_LOCKED(req->base);
        if (!*head) {
                *head = req;
@@ -2538,9 +2552,10 @@ string_num_dots(const char *s) {
        return count;
 }
 
-static struct evdns_request *
-request_new(struct evdns_base *base, int type, const char *name, int flags,
-    evdns_callback_type callback, void *user_ptr) {
+static struct request *
+request_new(struct evdns_base *base, struct evdns_request *handle, int type,
+           const char *name, int flags, evdns_callback_type callback,
+           void *user_ptr) {
 
        const char issuing_now =
            (base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0;
@@ -2549,8 +2564,8 @@ request_new(struct evdns_base *base, int type, const char *name, int flags,
        const size_t request_max_len = evdns_request_len(name_len);
        const u16 trans_id = issuing_now ? transaction_id_pick(base) : 0xffff;
        /* the request data is alloced in a single block with the header */
-       struct evdns_request *const req =
-           mm_malloc(sizeof(struct evdns_request) + request_max_len);
+       struct request *const req =
+           mm_malloc(sizeof(struct request) + request_max_len);
        int rlen;
        char namebuf[256];
        (void) flags;
@@ -2564,7 +2579,7 @@ request_new(struct evdns_base *base, int type, const char *name, int flags,
                return NULL;
        }
 
-       memset(req, 0, sizeof(struct evdns_request));
+       memset(req, 0, sizeof(struct request));
        req->base = base;
 
        evtimer_assign(&req->timeout_event, req->base->event_base, evdns_request_timeout_callback, req);
@@ -2586,7 +2601,7 @@ request_new(struct evdns_base *base, int type, const char *name, int flags,
        }
 
        /* request data lives just after the header */
-       req->request = ((u8 *) req) + sizeof(struct evdns_request);
+       req->request = ((u8 *) req) + sizeof(struct request);
        /* denotes that the request data shouldn't be free()ed */
        req->request_appended = 1;
        rlen = evdns_request_data_build(name, name_len, trans_id,
@@ -2602,6 +2617,8 @@ request_new(struct evdns_base *base, int type, const char *name, int flags,
        req->user_callback = callback;
        req->ns = issuing_now ? nameserver_pick(base) : NULL;
        req->next = req->prev = NULL;
+       req->handle = handle;
+       handle->current_req = req;
 
        return req;
 err1:
@@ -2610,7 +2627,7 @@ err1:
 }
 
 static void
-request_submit(struct evdns_request *const req) {
+request_submit(struct request *const req) {
        struct evdns_base *base = req->base;
        ASSERT_LOCKED(base);
        if (req->ns) {
@@ -2627,8 +2644,10 @@ request_submit(struct evdns_request *const req) {
 
 /* exported function */
 void
-evdns_cancel_request(struct evdns_base *base, struct evdns_request *req)
+evdns_cancel_request(struct evdns_base *base, struct evdns_request *handle)
 {
+       struct request *req = handle->current_req;
+
        if (!base)
                base = req->base;
 
@@ -2636,10 +2655,10 @@ evdns_cancel_request(struct evdns_base *base, struct evdns_request *req)
        reply_schedule_callback(req, 0, DNS_ERR_CANCEL, NULL);
        if (req->ns) {
                /* remove from inflight queue */
-               request_finished(req, &REQ_HEAD(base, req->trans_id));
+               request_finished(req, &REQ_HEAD(base, req->trans_id), 1);
        } else {
                /* remove from global_waiting head */
-               request_finished(req, &base->req_waiting_head);
+               request_finished(req, &base->req_waiting_head, 1);
        }
        EVDNS_UNLOCK(base);
 }
@@ -2648,19 +2667,25 @@ evdns_cancel_request(struct evdns_base *base, struct evdns_request *req)
 struct evdns_request *
 evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags,
     evdns_callback_type callback, void *ptr) {
-       struct evdns_request *req;
+       struct evdns_request *handle;
+       struct request *req;
        log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+       handle = mm_calloc(1, sizeof(*handle));
+       if (handle == NULL)
+               return NULL;
        EVDNS_LOCK(base);
        if (flags & DNS_QUERY_NO_SEARCH) {
                req =
-                       request_new(base, TYPE_A, name, flags, callback, ptr);
+                       request_new(base, handle, TYPE_A, name, flags,
+                                   callback, ptr);
                if (req)
                        request_submit(req);
        } else {
-               req = search_request_new(base, TYPE_A, name, flags, callback, ptr);
+               req = search_request_new(base, handle, TYPE_A, name, flags,
+                                        callback, ptr);
        }
        EVDNS_UNLOCK(base);
-       return req;
+       return handle;
 }
 
 int evdns_resolve_ipv4(const char *name, int flags,
@@ -2677,18 +2702,24 @@ evdns_base_resolve_ipv6(struct evdns_base *base,
     const char *name, int flags,
     evdns_callback_type callback, void *ptr)
 {
-       struct evdns_request *req;
+       struct evdns_request *handle;
+       struct request *req;
        log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+       handle = mm_calloc(1, sizeof(*handle));
+       if (handle == NULL)
+               return NULL;
        EVDNS_LOCK(base);
        if (flags & DNS_QUERY_NO_SEARCH) {
-               req = request_new(base, TYPE_AAAA, name, flags, callback, ptr);
+               req = request_new(base, handle, TYPE_AAAA, name, flags,
+                                 callback, ptr);
                if (req)
                        request_submit(req);
        } else {
-               req = search_request_new(base,TYPE_AAAA, name, flags, callback, ptr);
+               req = search_request_new(base, handle, TYPE_AAAA, name, flags,
+                                        callback, ptr);
        }
        EVDNS_UNLOCK(base);
-       return req;
+       return handle;
 }
 
 int evdns_resolve_ipv6(const char *name, int flags,
@@ -2700,7 +2731,8 @@ int evdns_resolve_ipv6(const char *name, int flags,
 struct evdns_request *
 evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
        char buf[32];
-       struct evdns_request *req;
+       struct evdns_request *handle;
+       struct request *req;
        u32 a;
        EVUTIL_ASSERT(in);
        a = ntohl(in->s_addr);
@@ -2709,13 +2741,16 @@ evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, in
                        (int)(u8)((a>>8 )&0xff),
                        (int)(u8)((a>>16)&0xff),
                        (int)(u8)((a>>24)&0xff));
+       handle = mm_calloc(1, sizeof(*handle));
+       if (handle == NULL)
+               return NULL;
        log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
        EVDNS_LOCK(base);
-       req = request_new(base, TYPE_PTR, buf, flags, callback, ptr);
+       req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
        if (req)
                request_submit(req);
        EVDNS_UNLOCK(base);
-       return (req);
+       return (handle);
 }
 
 int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
@@ -2728,7 +2763,8 @@ evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *
        /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
        char buf[73];
        char *cp;
-       struct evdns_request *req;
+       struct evdns_request *handle;
+       struct request *req;
        int i;
        EVUTIL_ASSERT(in);
        cp = buf;
@@ -2741,13 +2777,16 @@ evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *
        }
        EVUTIL_ASSERT(cp + strlen("ip6.arpa") < buf+sizeof(buf));
        memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
+       handle = mm_calloc(1, sizeof(*handle));
+       if (handle == NULL)
+               return NULL;
        log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
        EVDNS_LOCK(base);
-       req = request_new(base, TYPE_PTR, buf, flags, callback, ptr);
+       req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
        if (req)
                request_submit(req);
        EVDNS_UNLOCK(base);
-       return (req);
+       return (handle);
 }
 
 int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
@@ -2931,23 +2970,25 @@ search_make_new(const struct search_state *const state, int n, const char *const
        return NULL; /* unreachable; stops warnings in some compilers. */
 }
 
-static struct evdns_request *
-search_request_new(struct evdns_base *base, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) {
+static struct request *
+search_request_new(struct evdns_base *base, struct evdns_request *handle,
+                  int type, const char *const name, int flags,
+                  evdns_callback_type user_callback, void *user_arg) {
        ASSERT_LOCKED(base);
        EVUTIL_ASSERT(type == TYPE_A || type == TYPE_AAAA);
        if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
             base->global_search_state &&
                 base->global_search_state->num_domains) {
                /* we have some domains to search */
-               struct evdns_request *req;
+               struct request *req;
                if (string_num_dots(name) >= base->global_search_state->ndots) {
-                       req = request_new(base, type, name, flags, user_callback, user_arg);
+                       req = request_new(base, handle, type, name, flags, user_callback, user_arg);
                        if (!req) return NULL;
                        req->search_index = -1;
                } else {
                        char *const new_name = search_make_new(base->global_search_state, 0, name);
                        if (!new_name) return NULL;
-                       req = request_new(base, type, new_name, flags, user_callback, user_arg);
+                       req = request_new(base, handle, type, new_name, flags, user_callback, user_arg);
                        mm_free(new_name);
                        if (!req) return NULL;
                        req->search_index = 0;
@@ -2959,7 +3000,7 @@ search_request_new(struct evdns_base *base, int type, const char *const name, in
                request_submit(req);
                return req;
        } else {
-               struct evdns_request *const req = request_new(base, type, name, flags, user_callback, user_arg);
+               struct request *const req = request_new(base, handle, type, name, flags, user_callback, user_arg);
                if (!req) return NULL;
                request_submit(req);
                return req;
@@ -2972,20 +3013,20 @@ search_request_new(struct evdns_base *base, int type, const char *const name, in
 /*   0 another request has been submitted */
 /*   1 no more requests needed */
 static int
-search_try_next(struct evdns_request *const req) {
+search_try_next(struct request *const req) {
        struct evdns_base *base = req->base;
        ASSERT_LOCKED(base);
        if (req->search_state) {
                /* it is part of a search */
                char *new_name;
-               struct evdns_request *newreq;
+               struct request *newreq;
                req->search_index++;
                if (req->search_index >= req->search_state->num_domains) {
                        /* no more postfixes to try, however we may need to try */
                        /* this name without a postfix */
                        if (string_num_dots(req->search_origname) < req->search_state->ndots) {
                                /* yep, we need to try it raw */
-                               newreq = request_new(base, req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
+                               newreq = request_new(base, req->handle, req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
                                log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
                                if (newreq) {
                                        request_submit(newreq);
@@ -2998,7 +3039,7 @@ search_try_next(struct evdns_request *const req) {
                new_name = search_make_new(req->search_state, req->search_index, req->search_origname);
                if (!new_name) return 1;
                log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
-               newreq = request_new(base, req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
+               newreq = request_new(base, req->handle, req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
                mm_free(new_name);
                if (!newreq) return 1;
                newreq->search_origname = req->search_origname;
@@ -3014,7 +3055,7 @@ search_try_next(struct evdns_request *const req) {
 }
 
 static void
-search_request_finished(struct evdns_request *const req) {
+search_request_finished(struct request *const req) {
        ASSERT_LOCKED(req->base);
        if (req->search_state) {
                search_state_decref(req->search_state);
@@ -3104,7 +3145,7 @@ static int
 evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
 {
        int old_n_heads = base->n_req_heads, n_heads;
-       struct evdns_request **old_heads = base->req_heads, **new_heads, *req;
+       struct request **old_heads = base->req_heads, **new_heads, *req;
        int i;
 
        ASSERT_LOCKED(base);
@@ -3112,7 +3153,7 @@ evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
                maxinflight = 1;
        n_heads = (maxinflight+4) / 5;
        EVUTIL_ASSERT(n_heads > 0);
-       new_heads = mm_calloc(n_heads, sizeof(struct evdns_request*));
+       new_heads = mm_calloc(n_heads, sizeof(struct request*));
        if (!new_heads)
                return (-1);
        if (old_heads) {
@@ -3737,13 +3778,13 @@ evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
                while (base->req_heads[i]) {
                        if (fail_requests)
                                reply_schedule_callback(base->req_heads[i], 0, DNS_ERR_SHUTDOWN, NULL);
-                       request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id));
+                       request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1);
                }
        }
        while (base->req_waiting_head) {
                if (fail_requests)
                        reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
-               request_finished(base->req_waiting_head, &base->req_waiting_head);
+               request_finished(base->req_waiting_head, &base->req_waiting_head, 1);
        }
        base->global_requests_inflight = base->global_requests_waiting = 0;
 
@@ -4346,7 +4387,7 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
                    nodename, 0, evdns_getaddrinfo_gotresolve,
                    &data->ipv4_request);
                if (want_cname)
-                       data->ipv4_request.r->put_cname_in_ptr =
+                       data->ipv4_request.r->current_req->put_cname_in_ptr =
                            &data->cname_result;
        }
        if (hints.ai_family != PF_INET) {
@@ -4357,7 +4398,7 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
                    nodename, 0, evdns_getaddrinfo_gotresolve,
                    &data->ipv6_request);
                if (want_cname)
-                       data->ipv6_request.r->put_cname_in_ptr =
+                       data->ipv6_request.r->current_req->put_cname_in_ptr =
                            &data->cname_result;
        }