--- src/core/ngx_resolver.c
+++ src/core/ngx_resolver.c	2016/02/05 11:58:28
@@ -54,15 +54,15 @@
 static void ngx_resolver_cleanup(void *data);
 static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
-    ngx_resolver_ctx_t *ctx);
+    ngx_resolver_ctx_t *ctx, ngx_str_t *name);
 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
     ngx_queue_t *queue);
 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
     ngx_resolver_node_t *rn);
-static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn,
-    ngx_resolver_ctx_t *ctx);
-static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn,
-    ngx_resolver_ctx_t *ctx);
+static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r,
+    ngx_resolver_node_t *rn, ngx_str_t *name);
+static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r,
+    ngx_resolver_node_t *rn, in_addr_t addr);
 static void ngx_resolver_resend_handler(ngx_event_t *ev);
 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
     ngx_queue_t *queue);
@@ -270,7 +270,7 @@
 
     /* lock name mutex */
 
-    rc = ngx_resolve_name_locked(r, ctx);
+    rc = ngx_resolve_name_locked(r, ctx, &ctx->name);
 
     if (rc == NGX_OK) {
         return NGX_OK;
@@ -297,7 +297,6 @@
 void
 ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
 {
-    uint32_t              hash;
     ngx_resolver_t       *r;
     ngx_resolver_ctx_t   *w, **p;
     ngx_resolver_node_t  *rn;
@@ -319,9 +318,7 @@
 
     if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
 
-        hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
-
-        rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
+        rn = ctx->node;
 
         if (rn) {
             p = &rn->waiting;
@@ -364,21 +361,26 @@
 /* NGX_RESOLVE_A only */
 
 static ngx_int_t
-ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
+ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx,
+    ngx_str_t *name)
 {
     uint32_t              hash;
     in_addr_t             addr, *addrs;
     ngx_int_t             rc;
+    ngx_str_t             cname;
     ngx_uint_t            naddrs;
-    ngx_resolver_ctx_t   *next;
+    ngx_resolver_ctx_t   *next, *last;
     ngx_resolver_node_t  *rn;
 
-    hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
+    hash = ngx_crc32_short(name->data, ctx->name.len);
 
-    rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
+    rn = ngx_resolver_lookup_name(r, name, hash);
 
     if (rn) {
 
+        /* ctx can be a list after NGX_RESOLVE_CNAME */
+        for (last = ctx; last->next; last = last->next);
+
         if (rn->valid >= ngx_time()) {
 
             ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
@@ -408,7 +410,7 @@
                     addrs = NULL;
                 }
 
-                ctx->next = rn->waiting;
+                last->next = rn->waiting;
                 rn->waiting = NULL;
 
                 /* unlock name mutex */
@@ -436,13 +438,13 @@
 
             if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
 
-                ctx->name.len = rn->cnlen;
-                ctx->name.data = rn->u.cname;
+                cname.len = rn->cnlen;
+                cname.data = rn->u.cname;
 
-                return ngx_resolve_name_locked(r, ctx);
+                return ngx_resolve_name_locked(r, ctx, &cname);
             }
 
-            ctx->next = rn->waiting;
+            last->next = rn->waiting;
             rn->waiting = NULL;
 
             /* unlock name mutex */
@@ -461,10 +463,29 @@
 
         if (rn->waiting) {
 
-            ctx->next = rn->waiting;
+            if (ctx->event == NULL) {
+                ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
+                if (ctx->event == NULL) {
+                    return NGX_ERROR;
+                }
+
+                ctx->event->handler = ngx_resolver_timeout_handler;
+                ctx->event->data = ctx;
+                ctx->event->log = r->log;
+                ctx->ident = -1;
+
+                ngx_add_timer(ctx->event, ctx->timeout);
+            }
+
+            last->next = rn->waiting;
             rn->waiting = ctx;
             ctx->state = NGX_AGAIN;
 
+            do {
+                ctx->node = rn;
+                ctx = ctx->next;
+            } while (ctx);
+
             return NGX_AGAIN;
         }
 
@@ -492,20 +513,20 @@
             return NGX_ERROR;
         }
 
-        rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len);
+        rn->name = ngx_resolver_dup(r, name->data, name->len);
         if (rn->name == NULL) {
             ngx_resolver_free(r, rn);
             return NGX_ERROR;
         }
 
         rn->node.key = hash;
-        rn->nlen = (u_short) ctx->name.len;
+        rn->nlen = (u_short) name->len;
         rn->query = NULL;
 
         ngx_rbtree_insert(&r->name_rbtree, &rn->node);
     }
 
-    rc = ngx_resolver_create_name_query(rn, ctx);
+    rc = ngx_resolver_create_name_query(r, rn, name);
 
     if (rc == NGX_ERROR) {
         goto failed;
@@ -518,8 +539,14 @@
         ngx_resolver_free(r, rn->name);
         ngx_resolver_free(r, rn);
 
-        ctx->state = NGX_RESOLVE_NXDOMAIN;
-        ctx->handler(ctx);
+        do {
+            ctx->state = NGX_RESOLVE_NXDOMAIN;
+            next = ctx->next;
+
+            ctx->handler(ctx);
+
+            ctx = next;
+        } while (ctx);
 
         return NGX_OK;
     }
@@ -557,6 +584,11 @@
 
     ctx->state = NGX_AGAIN;
 
+    do {
+        ctx->node = rn;
+        ctx = ctx->next;
+    } while (ctx);
+
     return NGX_AGAIN;
 
 failed:
@@ -623,9 +655,22 @@
 
         if (rn->waiting) {
 
+            ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
+            if (ctx->event == NULL) {
+                return NGX_ERROR;
+            }
+
+            ctx->event->handler = ngx_resolver_timeout_handler;
+            ctx->event->data = ctx;
+            ctx->event->log = r->log;
+            ctx->ident = -1;
+
+            ngx_add_timer(ctx->event, ctx->timeout);
+
             ctx->next = rn->waiting;
             rn->waiting = ctx;
             ctx->state = NGX_AGAIN;
+            ctx->node = rn;
 
             /* unlock addr mutex */
 
@@ -649,7 +694,7 @@
         ngx_rbtree_insert(&r->addr_rbtree, &rn->node);
     }
 
-    if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
+    if (ngx_resolver_create_addr_query(r, rn, ctx->addr) != NGX_OK) {
         goto failed;
     }
 
@@ -687,6 +732,7 @@
     /* unlock addr mutex */
 
     ctx->state = NGX_AGAIN;
+    ctx->node = rn;
 
     return NGX_OK;
 
@@ -1005,7 +1051,7 @@
         times = 0;
 
         for (q = ngx_queue_head(&r->name_resend_queue);
-             q != ngx_queue_sentinel(&r->name_resend_queue) || times++ < 100;
+             q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100;
              q = ngx_queue_next(q))
         {
             rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
@@ -1376,13 +1422,35 @@
 
         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
 
+        ngx_resolver_free(r, rn->query);
+        rn->query = NULL;
+
         ctx = rn->waiting;
         rn->waiting = NULL;
 
         if (ctx) {
-            ctx->name = name;
 
-            (void) ngx_resolve_name_locked(r, ctx);
+           if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
+
+                /* unlock name mutex */
+
+                do {
+                    ctx->state = NGX_RESOLVE_NXDOMAIN;
+                    next = ctx->next;
+
+                    ctx->handler(ctx);
+
+                    ctx = next;
+                } while (ctx);
+
+                return;
+            }
+
+            for (next = ctx; next; next = next->next) {
+                next->node = NULL;
+            }
+
+            (void) ngx_resolve_name_locked(r, ctx, &name);
         }
 
         return;
@@ -1409,8 +1477,6 @@
 
     /* unlock name mutex */
 
-    ngx_resolver_free(r, name.data);
-
     return;
 }
 
@@ -1716,7 +1782,8 @@
 
 
 static ngx_int_t
-ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
+ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
+    ngx_str_t *name)
 {
     u_char                *p, *s;
     size_t                 len, nlen;
@@ -1724,11 +1791,11 @@
     ngx_resolver_qs_t     *qs;
     ngx_resolver_query_t  *query;
 
-    nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1;
+    nlen = name->len ? (1 + name->len + 1) : 1;
 
     len = sizeof(ngx_resolver_query_t) + nlen + sizeof(ngx_resolver_qs_t);
 
-    p = ngx_resolver_alloc(ctx->resolver, len);
+    p = ngx_resolver_alloc(r, len);
     if (p == NULL) {
         return NGX_ERROR;
     }
@@ -1740,8 +1807,8 @@
 
     ident = ngx_random();
 
-    ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
-                   "resolve: \"%V\" %i", &ctx->name, ident & 0xffff);
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
+                   "resolve: \"%V\" A %i", name, ident & 0xffff);
 
     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
     query->ident_lo = (u_char) (ident & 0xff);
@@ -1760,7 +1827,7 @@
     qs = (ngx_resolver_qs_t *) p;
 
     /* query type */
-    qs->type_hi = 0; qs->type_lo = (u_char) ctx->type;
+    qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A;
 
     /* IP query class */
     qs->class_hi = 0; qs->class_lo = 1;
@@ -1771,7 +1838,7 @@
     p--;
     *p-- = '\0';
 
-    for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) {
+    for (s = name->data + name->len - 1; s >= name->data; s--) {
         if (*s != '.') {
             *p = *s;
             len++;
@@ -1797,7 +1864,8 @@
 /* AF_INET only */
 
 static ngx_int_t
-ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
+ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
+    in_addr_t addr)
 {
     u_char                *p, *d;
     size_t                 len;
@@ -1809,7 +1877,7 @@
           + sizeof(".255.255.255.255.in-addr.arpa.") - 1
           + sizeof(ngx_resolver_qs_t);
 
-    p = ngx_resolver_alloc(ctx->resolver, len);
+    p = ngx_resolver_alloc(r, len);
     if (p == NULL) {
         return NGX_ERROR;
     }
@@ -1834,7 +1902,7 @@
     p += sizeof(ngx_resolver_query_t);
 
     for (n = 0; n < 32; n += 8) {
-        d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff);
+        d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff);
         *p = (u_char) (d - &p[1]);
         p = d;
     }
--- src/core/ngx_resolver.h
+++ src/core/ngx_resolver.h	2016/02/04 13:45:19
@@ -133,6 +133,8 @@
     ngx_uint_t                quick;  /* unsigned  quick:1; */
     ngx_uint_t                recursion;
     ngx_event_t              *event;
+
+    ngx_resolver_node_t      *node;
 };
 
 
