~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/core/ngx_resolver.c

Version: ~ [ nginx-0.6.26 ] ~ [ nginx-0.5.35 ] ~ [ nginx-0.5.20 ] ~ [ nginx-0.5.19 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  */
  5 
  6 
  7 #include <ngx_config.h>
  8 #include <ngx_core.h>
  9 #include <ngx_event.h>
 10 
 11 
 12 #define NGX_RESOLVER_UDP_SIZE   4096
 13 
 14 
 15 typedef struct {
 16     u_char  ident_hi;
 17     u_char  ident_lo;
 18     u_char  flags_hi;
 19     u_char  flags_lo;
 20     u_char  nqs_hi;
 21     u_char  nqs_lo;
 22     u_char  nan_hi;
 23     u_char  nan_lo;
 24     u_char  nns_hi;
 25     u_char  nns_lo;
 26     u_char  nar_hi;
 27     u_char  nar_lo;
 28 } ngx_resolver_query_t;
 29 
 30 
 31 typedef struct {
 32     u_char  type_hi;
 33     u_char  type_lo;
 34     u_char  class_hi;
 35     u_char  class_lo;
 36 } ngx_resolver_qs_t;
 37 
 38 
 39 typedef struct {
 40     u_char  type_hi;
 41     u_char  type_lo;
 42     u_char  class_hi;
 43     u_char  class_lo;
 44     u_char  ttl[4];
 45     u_char  len_hi;
 46     u_char  len_lo;
 47 } ngx_resolver_an_t;
 48 
 49 
 50 ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc);
 51 
 52 
 53 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
 54     ngx_resolver_ctx_t *ctx);
 55 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
 56     ngx_queue_t *queue);
 57 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
 58     ngx_resolver_node_t *rn);
 59 static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn,
 60     ngx_resolver_ctx_t *ctx);
 61 static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn,
 62     ngx_resolver_ctx_t *ctx);
 63 static void ngx_resolver_resend_handler(ngx_event_t *ev);
 64 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
 65     ngx_queue_t *queue);
 66 static void ngx_resolver_read_response(ngx_event_t *rev);
 67 static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
 68     size_t n);
 69 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
 70     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans);
 71 static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
 72     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
 73 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
 74     ngx_str_t *name, uint32_t hash);
 75 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
 76     in_addr_t addr);
 77 static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
 78     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 79 static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
 80     u_char *buf, u_char *src, u_char *last);
 81 static void ngx_resolver_timeout_handler(ngx_event_t *ev);
 82 static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
 83 static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
 84 static void ngx_resolver_free(ngx_resolver_t *r, void *p);
 85 static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
 86 static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
 87 
 88 
 89 /* STUB: ngx_peer_addr_t * */
 90 
 91 ngx_resolver_t *
 92 ngx_resolver_create(ngx_peer_addr_t *addr, ngx_log_t *log)
 93 {
 94     ngx_resolver_t        *r;
 95     ngx_udp_connection_t  *uc;
 96 
 97     r = ngx_calloc(sizeof(ngx_resolver_t), log);
 98     if (r == NULL) {
 99         return NULL;
100     }
101 
102     r->event = ngx_calloc(sizeof(ngx_event_t), log);
103     if (r->event == NULL) {
104         return NULL;
105     }
106 
107     ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel,
108                     ngx_resolver_rbtree_insert_value);
109 
110     ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
111                     ngx_rbtree_insert_value);
112 
113     ngx_queue_init(&r->name_resend_queue);
114     ngx_queue_init(&r->addr_resend_queue);
115 
116     ngx_queue_init(&r->name_expire_queue);
117     ngx_queue_init(&r->addr_expire_queue);
118 
119     r->event->handler = ngx_resolver_resend_handler;
120     r->event->data = r;
121     r->event->log = log;
122     r->ident = -1;
123 
124     r->resend_timeout = 5;
125     r->expire = 30;
126     r->valid = 300;
127 
128     r->log = log;
129     r->log_level = NGX_LOG_ALERT;
130 
131     if (addr) {
132         uc = ngx_calloc(sizeof(ngx_udp_connection_t), log);
133         if (uc == NULL) {
134             return NULL;
135         }
136 
137         r->udp_connection = uc;
138 
139         uc->sockaddr = addr->sockaddr;
140         uc->socklen = addr->socklen;
141         uc->server = addr->name;
142         uc->log = log;
143     }
144 
145     return r;
146 }
147 
148 
149 ngx_resolver_ctx_t *
150 ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
151 {
152     in_addr_t            addr;
153     ngx_resolver_ctx_t  *ctx;
154 
155     if (temp) {
156         addr = ngx_inet_addr(temp->name.data, temp->name.len);
157 
158         if (addr != INADDR_NONE) {
159             temp->resolver = r;
160             temp->state = NGX_OK;
161             temp->naddrs = 1;
162             temp->addrs = &temp->addr;
163             temp->addr = addr;
164             temp->quick = 1;
165 
166             return temp;
167         }
168     }
169 
170     if (r->udp_connection == NULL) {
171         return NGX_NO_RESOLVER;
172     }
173 
174     ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t));
175 
176     if (ctx) {
177         ctx->resolver = r;
178     }
179 
180     return ctx;
181 }
182 
183 
184 ngx_int_t
185 ngx_resolve_name(ngx_resolver_ctx_t *ctx)
186 {
187     ngx_int_t        rc;
188     ngx_resolver_t  *r;
189 
190     r = ctx->resolver;
191 
192     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
193                    "resolve: \"%V\"", &ctx->name);
194 
195     if (ctx->quick) {
196         ctx->handler(ctx);
197         return NGX_OK;
198     }
199 
200     /* lock name mutex */
201 
202     rc = ngx_resolve_name_locked(r, ctx);
203 
204     if (rc == NGX_OK) {
205         return NGX_OK;
206     }
207 
208     /* unlock name mutex */
209 
210     if (rc == NGX_AGAIN) {
211         return NGX_OK;
212     }
213 
214     /* lock alloc mutex */
215 
216     if (ctx->event) {
217         ngx_resolver_free_locked(r, ctx->event);
218         ctx->event = NULL;
219     }
220 
221     /* unlock alloc mutex */
222 
223     return NGX_ERROR;
224 }
225 
226 
227 void
228 ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
229 {
230     uint32_t              hash;
231     ngx_resolver_t       *r;
232     ngx_resolver_ctx_t   *w, **p;
233     ngx_resolver_node_t  *rn;
234 
235     r = ctx->resolver;
236 
237     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
238                    "resolve name done: %i", ctx->state);
239 
240     if (ctx->quick) {
241         return;
242     }
243 
244     if (ctx->event && ctx->event->timer_set) {
245         ngx_del_timer(ctx->event);
246     }
247 
248     /* lock name mutex */
249 
250     if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
251 
252         hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
253 
254         rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
255 
256         if (rn) {
257             p = &rn->waiting;
258             w = rn->waiting;
259 
260             while (w) {
261                 if (w == ctx) {
262                     *p = w->next;
263 
264                     goto done;
265                 }
266 
267                 p = &w->next;
268                 w = w->next;
269             }
270         }
271 
272         ngx_log_error(NGX_LOG_ALERT, r->log, 0,
273                       "could not cancel %V resolving", &ctx->name);
274     }
275 
276 done:
277 
278     ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue);
279 
280     /* unlock name mutex */
281 
282     ngx_resolver_free(r, ctx);
283 }
284 
285 
286 /* NGX_RESOLVE_A only */
287 
288 static ngx_int_t
289 ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
290 {
291     uint32_t              hash;
292     in_addr_t             addr, *addrs;
293     ngx_uint_t            naddrs;
294     ngx_resolver_ctx_t   *next;
295     ngx_resolver_node_t  *rn;
296 
297     hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
298 
299     rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
300 
301     if (rn) {
302 
303         if (rn->valid >= ngx_time()) {
304 
305             ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
306 
307             ngx_queue_remove(&rn->queue);
308 
309             rn->expire = ngx_time() + r->expire;
310 
311             ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
312 
313             naddrs = rn->naddrs;
314 
315             if (naddrs) {
316 
317                 /* NGX_RESOLVE_A answer */
318 
319                 if (naddrs != 1) {
320                     addr = 0;
321                     addrs = ngx_resolver_dup(r, rn->u.addrs,
322                                              naddrs * sizeof(in_addr_t));
323                     if (addrs == NULL) {
324                         return NGX_ERROR;
325                     }
326 
327                 } else {
328                     addr = rn->u.addr;
329                     addrs = NULL;
330                 }
331 
332                 ctx->next = rn->waiting;
333                 rn->waiting = NULL;
334 
335                 /* unlock name mutex */
336 
337                 do {
338                     ctx->state = NGX_OK;
339                     ctx->naddrs = naddrs;
340                     ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
341                     ctx->addr = addr;
342                     next = ctx->next;
343 
344                     ctx->handler(ctx);
345 
346                     ctx = next;
347                 } while (ctx);
348 
349                 if (addrs) {
350                     ngx_resolver_free(r, addrs);
351                 }
352 
353                 return NGX_OK;
354             }
355 
356             /* NGX_RESOLVE_CNAME */
357 
358             ctx->name.len = rn->cnlen;
359             ctx->name.data = rn->u.cname;
360 
361             return ngx_resolve_name_locked(r, ctx);
362         }
363 
364         if (rn->waiting) {
365 
366             ctx->next = rn->waiting;
367             rn->waiting = ctx;
368 
369             return NGX_AGAIN;
370         }
371 
372         ngx_queue_remove(&rn->queue);
373 
374         /* lock alloc mutex */
375 
376         ngx_resolver_free_locked(r, rn->query);
377 
378         if (rn->cnlen) {
379             ngx_resolver_free_locked(r, rn->u.cname);
380         }
381 
382         if (rn->naddrs > 1) {
383             ngx_resolver_free_locked(r, rn->u.addrs);
384         }
385 
386         /* unlock alloc mutex */
387 
388     } else {
389 
390         rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
391         if (rn == NULL) {
392             return NGX_ERROR;
393         }
394 
395         rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len);
396         if (rn->name == NULL) {
397             ngx_resolver_free(r, rn);
398             return NGX_ERROR;
399         }
400 
401         rn->node.key = hash;
402         rn->nlen = (u_short) ctx->name.len;
403 
404         ngx_rbtree_insert(&r->name_rbtree, &rn->node);
405     }
406 
407     if (ngx_resolver_create_name_query(rn, ctx) != NGX_OK) {
408         goto failed;
409     }
410 
411     if (ngx_resolver_send_query(r, rn) != NGX_OK) {
412         goto failed;
413     }
414 
415     if (ctx->event == NULL) {
416         ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
417         if (ctx->event == NULL) {
418             goto failed;
419         }
420 
421         ctx->event->handler = ngx_resolver_timeout_handler;
422         ctx->event->data = ctx;
423         ctx->event->log = r->log;
424         ctx->ident = -1;
425 
426         ngx_add_timer(ctx->event, ctx->timeout);
427     }
428 
429     if (ngx_queue_empty(&r->name_resend_queue)) {
430         ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
431     }
432 
433     rn->expire = ngx_time() + r->resend_timeout;
434 
435     ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
436 
437     rn->cnlen = 0;
438     rn->naddrs = 0;
439     rn->valid = 0;
440     rn->waiting = ctx;
441 
442     ctx->state = NGX_AGAIN;
443 
444     return NGX_AGAIN;
445 
446 failed:
447 
448     ngx_rbtree_delete(&r->name_rbtree, &rn->node);
449 
450     ngx_resolver_free(r, rn->name);
451 
452     ngx_resolver_free(r, rn);
453 
454     return NGX_ERROR;
455 }
456 
457 
458 ngx_int_t
459 ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
460 {
461     ngx_resolver_t       *r;
462     ngx_resolver_node_t  *rn;
463 
464     r = ctx->resolver;
465 
466     ctx->addr = ntohl(ctx->addr);
467 
468     /* lock addr mutex */
469 
470     rn = ngx_resolver_lookup_addr(r, ctx->addr);
471 
472     if (rn) {
473 
474         if (rn->valid >= ngx_time()) {
475 
476             ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
477 
478             ngx_queue_remove(&rn->queue);
479 
480             rn->expire = ngx_time() + r->expire;
481 
482             ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
483 
484             ctx->name.len = rn->nlen;
485             ctx->name.data = ngx_resolver_dup(r, rn->name, rn->nlen);
486             if (ctx->name.data == NULL) {
487                 goto failed;
488             }
489 
490             /* unlock addr mutex */
491 
492             ctx->state = NGX_OK;
493 
494             ctx->handler(ctx);
495 
496             ngx_resolver_free(r, ctx->name.data);
497 
498             return NGX_OK;
499         }
500 
501         if (rn->waiting) {
502 
503             ctx->next = rn->waiting;
504             rn->waiting = ctx;
505 
506             return NGX_AGAIN;
507         }
508 
509         ngx_queue_remove(&rn->queue);
510 
511         ngx_resolver_free(r, rn->query);
512 
513     } else {
514         rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
515         if (rn == NULL) {
516             goto failed;
517         }
518 
519         rn->node.key = ctx->addr;
520 
521         ngx_rbtree_insert(&r->addr_rbtree, &rn->node);
522     }
523 
524     if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
525         goto failed;
526     }
527 
528     if (ngx_resolver_send_query(r, rn) != NGX_OK) {
529         goto failed;
530     }
531 
532     ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
533     if (ctx->event == NULL) {
534         goto failed;
535     }
536 
537     ctx->event->handler = ngx_resolver_timeout_handler;
538     ctx->event->data = ctx;
539     ctx->event->log = r->log;
540     ctx->ident = -1;
541 
542     ngx_add_timer(ctx->event, ctx->timeout);
543 
544     if (ngx_queue_empty(&r->addr_resend_queue)) {
545         ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
546     }
547 
548     rn->expire = ngx_time() + r->resend_timeout;
549 
550     ngx_queue_insert_head(&r->addr_resend_queue, &rn->queue);
551 
552     rn->cnlen = 0;
553     rn->naddrs = 0;
554     rn->name = NULL;
555     rn->nlen = 0;
556     rn->valid = 0;
557     rn->waiting = ctx;
558 
559     /* unlock addr mutex */
560 
561     ctx->state = NGX_AGAIN;
562 
563     return NGX_OK;
564 
565 failed:
566 
567     if (rn) {
568         ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
569 
570         ngx_resolver_free(r, rn);
571     }
572 
573     /* unlock addr mutex */
574 
575     /* lock alloc mutex */
576 
577     if (ctx->event) {
578         ngx_resolver_free_locked(r, ctx->event);
579     }
580 
581     ngx_resolver_free_locked(r, ctx);
582 
583     /* unlock alloc mutex */
584 
585     return NGX_ERROR;
586 }
587 
588 
589 void
590 ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
591 {
592     in_addr_t             addr;
593     ngx_resolver_t       *r;
594     ngx_resolver_ctx_t   *w, **p;
595     ngx_resolver_node_t  *rn;
596 
597     r = ctx->resolver;
598 
599     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
600                    "resolve addr done: %i", ctx->state);
601 
602     if (ctx->event && ctx->event->timer_set) {
603         ngx_del_timer(ctx->event);
604     }
605 
606     /* lock addr mutex */
607 
608     if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
609 
610         rn = ngx_resolver_lookup_addr(r, ctx->addr);
611 
612         if (rn) {
613             p = &rn->waiting;
614             w = rn->waiting;
615 
616             while (w) {
617                 if (w == ctx) {
618                     *p = w->next;
619 
620                     goto done;
621                 }
622 
623                 p = &w->next;
624                 w = w->next;
625             }
626         }
627 
628         addr = ntohl(ctx->addr);
629 
630         ngx_log_error(NGX_LOG_ALERT, r->log, 0,
631                       "could not cancel %ud.%ud.%ud.%ud resolving",
632                       (addr >> 24) & 0xff, (addr >> 16) & 0xff,
633                       (addr >> 8) & 0xff, addr & 0xff);
634     }
635 
636 done:
637 
638     ngx_resolver_expire(r, &r->addr_rbtree, &r->addr_expire_queue);
639 
640     /* unlock addr mutex */
641 
642     ngx_resolver_free(r, ctx);
643 }
644 
645 
646 static void
647 ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
648 {
649     time_t                now;
650     ngx_uint_t            i;
651     ngx_queue_t          *q;
652     ngx_resolver_node_t  *rn;
653 
654     ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire");
655 
656     now = ngx_time();
657 
658     for (i = 0; i < 2; i++) {
659         if (ngx_queue_empty(queue)) {
660             return;
661         }
662 
663         q = ngx_queue_last(queue);
664 
665         rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
666 
667         if (now <= rn->expire) {
668             return;
669         }
670 
671         ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
672                        "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name);
673 
674         ngx_queue_remove(q);
675 
676         ngx_rbtree_delete(tree, &rn->node);
677 
678         ngx_resolver_free_node(r, rn);
679     }
680 }
681 
682 
683 static ngx_int_t
684 ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
685 {
686     ssize_t                n;
687     ngx_udp_connection_t  *uc;
688 
689     uc = r->udp_connection;
690 
691     if (uc->connection == NULL) {
692         if (ngx_udp_connect(uc) != NGX_OK) {
693             return NGX_ERROR;
694         }
695 
696         uc->connection->data = r;
697         uc->connection->read->handler = ngx_resolver_read_response;
698     }
699 
700     n = ngx_send(uc->connection, rn->query, rn->qlen);
701 
702     if (n == -1) {
703         return NGX_ERROR;
704     }
705 
706     if ((size_t) n != (size_t) rn->qlen) {
707         ngx_log_error(NGX_LOG_CRIT, uc->log, 0, "send() incomplete");
708         return NGX_ERROR;
709     }
710 
711     return NGX_OK;
712 }
713 
714 
715 static void
716 ngx_resolver_resend_handler(ngx_event_t *ev)
717 {
718     time_t           timer, atimer, ntimer;
719     ngx_resolver_t  *r;
720 
721     r = ev->data;
722 
723     ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0,
724                    "resolver resend handler");
725 
726     /* lock name mutex */
727 
728     ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue);
729 
730     /* unlock name mutex */
731 
732     /* lock addr mutex */
733 
734     atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue);
735 
736     /* unlock addr mutex */
737 
738     if (ntimer == 0) {
739         timer = atimer;
740 
741     } else if (atimer == 0) {
742         timer = ntimer;
743 
744     } else {
745         timer = (atimer < ntimer) ? atimer : ntimer;
746     }
747 
748     if (timer) {
749         ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
750     }
751 }
752 
753 
754 static time_t
755 ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
756 {
757     time_t                now;
758     ngx_queue_t          *q;
759     ngx_resolver_node_t  *rn;
760 
761     now = ngx_time();
762 
763     for ( ;; ) {
764         if (ngx_queue_empty(queue)) {
765             return 0;
766         }
767 
768         q = ngx_queue_last(queue);
769 
770         rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
771 
772         if (now < rn->expire) {
773             return rn->expire - now;
774         }
775 
776         ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
777                        "resolver resend \"%*s\" %p",
778                        (size_t) rn->nlen, rn->name, rn->waiting);
779 
780         ngx_queue_remove(q);
781 
782         if (rn->waiting) {
783 
784             if (ngx_resolver_send_query(r, rn) == NGX_OK) {
785 
786                 rn->expire = now + r->resend_timeout;
787 
788                 ngx_queue_insert_head(queue, &rn->queue);
789             }
790 
791             continue;
792         }
793 
794         ngx_rbtree_delete(tree, &rn->node);
795 
796         ngx_resolver_free_node(r, rn);
797     }
798 }
799 
800 
801 static void
802 ngx_resolver_read_response(ngx_event_t *rev)
803 {
804     ssize_t            n;
805     ngx_connection_t  *c;
806     u_char             buf[NGX_RESOLVER_UDP_SIZE];
807 
808     c = rev->data;
809 
810     do {
811         n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
812 
813         if (n < 0) {
814             return;
815         }
816 
817         ngx_resolver_process_response(c->data, buf, n);
818 
819     } while (rev->ready);
820 }
821 
822 
823 static void
824 ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
825 {
826     char                  *err;
827     size_t                 len;
828     ngx_uint_t             i, ident, flags, code, nqs, nan, qtype, qclass;
829     ngx_resolver_qs_t     *qs;
830     ngx_resolver_query_t  *query;
831 
832     if ((size_t) n < sizeof(ngx_resolver_query_t) + 1) {
833         goto short_response;
834     }
835 
836     query = (ngx_resolver_query_t *) buf;
837 
838     ident = (query->ident_hi << 8) + query->ident_lo;
839     flags = (query->flags_hi << 8) + query->flags_lo;
840     nqs = (query->nqs_hi << 8) + query->nqs_lo;
841     nan = (query->nan_hi << 8) + query->nan_lo;
842 
843     ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
844                    "resolver DNS response %d fl:%04Xud %d/%d/%d/%d",
845                    ident, flags, nqs, nan,
846                    (query->nns_hi << 8) + query->nns_lo,
847                    (query->nar_hi << 8) + query->nar_lo);
848 
849     if (!(flags & 0x8000)) {
850         ngx_log_error(r->log_level, r->log, 0,
851                       "invalid DNS response %d fl:%04Xud", ident, flags);
852         return;
853     }
854 
855     code = flags & 0x7f;
856 
857     if (code == NGX_RESOLVE_FORMERR || code > NGX_RESOLVE_REFUSED) {
858         ngx_log_error(r->log_level, r->log, 0,
859                       "DNS error (%d: %s), query id:%d",
860                       code, ngx_resolver_strerror(code), ident);
861         return;
862     }
863 
864     if (nqs != 1) {
865         err = "invalid number of questions in DNS response";
866         goto done;
867     }
868 
869     i = sizeof(ngx_resolver_query_t);
870 
871     while (i < (ngx_uint_t) n) {
872         if (buf[i] == '\0') {
873             goto found;
874         }
875 
876         len = buf[i];
877         i += 1 + len;
878     }
879 
880     goto short_response;
881 
882 found:
883 
884     if (i++ == 0) {
885         err = "zero-length domain name in DNS response";
886         goto done;
887     }
888 
889     if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t))
890         > (ngx_uint_t) n)
891     {
892         goto short_response;
893     }
894 
895     qs = (ngx_resolver_qs_t *) &buf[i];
896 
897     qtype = (qs->type_hi << 8) + qs->type_lo;
898     qclass = (qs->class_hi << 8) + qs->class_lo;
899 
900     ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
901                    "resolver DNS response qt:%d cl:%d", qtype, qclass);
902 
903     if (qclass != 1) {
904         ngx_log_error(r->log_level, r->log, 0,
905                       "unknown query class %d in DNS response", qclass);
906         return;
907     }
908 
909     switch (qtype) {
910 
911     case NGX_RESOLVE_A:
912 
913         ngx_resolver_process_a(r, buf, n, ident, code, nan,
914                                i + sizeof(ngx_resolver_qs_t));
915 
916         break;
917 
918     case NGX_RESOLVE_PTR:
919 
920         ngx_resolver_process_ptr(r, buf, n, ident, code, nan);
921 
922         break;
923 
924     default:
925         ngx_log_error(r->log_level, r->log, 0,
926                       "unknown query type %d in DNS response", qtype);
927         return;
928     }
929 
930     return;
931 
932 short_response:
933 
934     err = "short dns response";
935 
936 done:
937 
938     ngx_log_error(r->log_level, r->log, 0, err);
939 
940     return;
941 }
942 
943 
944 static void
945 ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
946     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans)
947 {
948     char                 *err;
949     u_char               *cname;
950     size_t                len;
951     uint32_t              hash;
952     in_addr_t             addr, *addrs;
953     ngx_str_t             name;
954     ngx_uint_t            qtype, qident, naddrs, a, i, n, start;
955     ngx_resolver_an_t    *an;
956     ngx_resolver_ctx_t   *ctx, *next;
957     ngx_resolver_node_t  *rn;
958 
959     if (ngx_resolver_copy(r, &name, buf, &buf[12], &buf[last]) != NGX_OK) {
960         return;
961     }
962 
963     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
964 
965     hash = ngx_crc32_short(name.data, name.len);
966 
967     /* lock name mutex */
968 
969     rn = ngx_resolver_lookup_name(r, &name, hash);
970 
971     if (rn == NULL || rn->query == NULL) {
972         ngx_log_error(r->log_level, r->log, 0,
973                       "unexpected response for %V", &name);
974         goto failed;
975     }
976 
977     qident = (rn->query[0] << 8) + rn->query[1];
978 
979     if (ident != qident) {
980         ngx_log_error(r->log_level, r->log, 0,
981                       "wrong ident %d response for %V, expect %d",
982                       ident, &name, qident);
983         goto failed;
984     }
985 
986     if (code == 0 && nan == 0) {
987         code = 3; /* NXDOMAIN */
988     }
989 
990     if (code) {
991         next = rn->waiting;
992         rn->waiting = NULL;
993 
994         ngx_queue_remove(&rn->queue);
995 
996         ngx_rbtree_delete(&r->name_rbtree, &rn->node);
997 
998         ngx_resolver_free_node(r, rn);
999 
1000         /* unlock name mutex */
1001 
1002         while (next) {
1003              ctx = next;
1004              ctx->state = code;
1005              next = ctx->next;
1006 
1007              ctx->handler(ctx);
1008         }
1009 
1010         return;
1011     }
1012 
1013     i = ans;
1014     naddrs = 0;
1015     addr = 0;
1016     addrs = NULL;
1017     cname = NULL;
1018     qtype = 0;
1019 
1020     for (a = 0; a < nan; a++) {
1021 
1022         start = i;
1023 
1024         while (i < last) {
1025 
1026             if (buf[i] & 0xc0) {
1027                 i += 2;
1028                 goto found;
1029             }
1030 
1031             if (buf[i] == 0) {
1032                 i++;
1033                 goto test_length;
1034             }
1035 
1036             i += 1 + buf[i];
1037         }
1038 
1039         goto short_response;
1040 
1041     test_length:
1042 
1043         if (i - start < 2) {
1044             err = "invalid name in dns response";
1045             goto invalid;
1046         }
1047 
1048     found:
1049 
1050         if (i + sizeof(ngx_resolver_an_t) >= last) {
1051             goto short_response;
1052         }
1053 
1054         an = (ngx_resolver_an_t *) &buf[i];
1055 
1056         qtype = (an->type_hi << 8) + an->type_lo;
1057         len = (an->len_hi << 8) + an->len_lo;
1058 
1059         if (qtype == NGX_RESOLVE_A) {
1060 
1061             i += sizeof(ngx_resolver_an_t);
1062 
1063             if (i + len > last) {
1064                 goto short_response;
1065             }
1066 
1067             addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
1068                          + (buf[i + 2] << 8) + (buf[i + 3]));
1069 
1070             naddrs++;
1071 
1072             i += len;
1073 
1074         } else if (qtype == NGX_RESOLVE_CNAME) {
1075             cname = &buf[i] + sizeof(ngx_resolver_an_t);
1076             i += sizeof(ngx_resolver_an_t) + len;
1077         }
1078     }
1079 
1080     ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1081                    "resolver naddrs:%ui cname:%p", naddrs, cname);
1082 
1083     if (naddrs) {
1084 
1085         if (naddrs == 1) {
1086             rn->u.addr = addr;
1087 
1088         } else {
1089 
1090             addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
1091             if (addrs == NULL) {
1092                 return;
1093             }
1094 
1095             n = 0;
1096             i = ans;
1097 
1098             for (a = 0; a < nan; a++) {
1099 
1100                 for ( ;; ) {
1101 
1102                     if (buf[i] & 0xc0) {
1103                         i += 2;
1104                         goto ok;
1105                     }
1106 
1107                     if (buf[i] == 0) {
1108                         i++;
1109                         goto ok;
1110                     }
1111 
1112                     i += 1 + buf[i];
1113                 }
1114 
1115             ok:
1116 
1117                 an = (ngx_resolver_an_t *) &buf[i];
1118 
1119                 qtype = (an->type_hi << 8) + an->type_lo;
1120                 len = (an->len_hi << 8) + an->len_lo;
1121 
1122                 i += sizeof(ngx_resolver_an_t);
1123 
1124                 if (qtype == NGX_RESOLVE_A) {
1125 
1126                     addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
1127                                        + (buf[i + 2] << 8) + (buf[i + 3]));
1128 
1129                     if (n == naddrs) {
1130                         break;
1131                     }
1132                 }
1133 
1134                 i += len;
1135             }
1136 
1137             rn->u.addrs = addrs;
1138 
1139             addrs = ngx_resolver_dup(r, rn->u.addrs,
1140                                      naddrs * sizeof(in_addr_t));
1141             if (addrs == NULL) {
1142                 return;
1143             }
1144         }
1145 
1146         rn->naddrs = (u_short) naddrs;
1147 
1148         ngx_queue_remove(&rn->queue);
1149 
1150         rn->valid = ngx_time() + r->valid;
1151         rn->expire = ngx_time() + r->expire;
1152 
1153         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
1154 
1155         next = rn->waiting;
1156         rn->waiting = NULL;
1157 
1158         /* unlock name mutex */
1159 
1160         while (next) {
1161              ctx = next;
1162              ctx->state = NGX_OK;
1163              ctx->naddrs = naddrs;
1164              ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
1165              ctx->addr = addr;
1166              next = ctx->next;
1167 
1168              ctx->handler(ctx);
1169         }
1170 
1171         if (naddrs) {
1172             ngx_resolver_free(r, addrs);
1173         }
1174 
1175         return;
1176 
1177     } else if (cname) {
1178 
1179         /* CNAME only */
1180 
1181         if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) {
1182             return;
1183         }
1184 
1185         ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
1186                        "resolver cname:\"%V\"", &name);
1187 
1188         ngx_queue_remove(&rn->queue);
1189 
1190         rn->cnlen = (u_short) name.len;
1191         rn->u.cname = name.data;
1192         rn-