upstream nginx-0.7.39
[nginx.git] / nginx / src / core / ngx_resolver.c
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 void ngx_resolver_cleanup(void *data);
54 static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
55 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
56     ngx_resolver_ctx_t *ctx);
57 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
58     ngx_queue_t *queue);
59 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
60     ngx_resolver_node_t *rn);
61 static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn,
62     ngx_resolver_ctx_t *ctx);
63 static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn,
64     ngx_resolver_ctx_t *ctx);
65 static void ngx_resolver_resend_handler(ngx_event_t *ev);
66 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
67     ngx_queue_t *queue);
68 static void ngx_resolver_read_response(ngx_event_t *rev);
69 static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
70     size_t n);
71 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
72     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans);
73 static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
74     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
75 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
76     ngx_str_t *name, uint32_t hash);
77 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
78     in_addr_t addr);
79 static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
80     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
81 static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
82     u_char *buf, u_char *src, u_char *last);
83 static void ngx_resolver_timeout_handler(ngx_event_t *ev);
84 static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
85 static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
86 static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
87 static void ngx_resolver_free(ngx_resolver_t *r, void *p);
88 static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
89 static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
90
91
92 /* STUB: ngx_peer_addr_t * */
93
94 ngx_resolver_t *
95 ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr)
96 {
97     ngx_resolver_t        *r;
98     ngx_pool_cleanup_t    *cln;
99     ngx_udp_connection_t  *uc;
100
101     cln = ngx_pool_cleanup_add(cf->pool, 0);
102     if (cln == NULL) {
103         return NULL;
104     }
105
106     cln->handler = ngx_resolver_cleanup;
107
108     r = ngx_calloc(sizeof(ngx_resolver_t), cf->log);
109     if (r == NULL) {
110         return NULL;
111     }
112
113     cln->data = r;
114
115     r->event = ngx_calloc(sizeof(ngx_event_t), cf->log);
116     if (r->event == NULL) {
117         return NULL;
118     }
119
120     ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel,
121                     ngx_resolver_rbtree_insert_value);
122
123     ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
124                     ngx_rbtree_insert_value);
125
126     ngx_queue_init(&r->name_resend_queue);
127     ngx_queue_init(&r->addr_resend_queue);
128
129     ngx_queue_init(&r->name_expire_queue);
130     ngx_queue_init(&r->addr_expire_queue);
131
132     r->event->handler = ngx_resolver_resend_handler;
133     r->event->data = r;
134     r->event->log = cf->cycle->new_log;
135     r->ident = -1;
136
137     r->resend_timeout = 5;
138     r->expire = 30;
139     r->valid = 300;
140
141     r->log = cf->cycle->new_log;
142     r->log_level = NGX_LOG_ALERT;
143
144     if (addr) {
145         uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log);
146         if (uc == NULL) {
147             return NULL;
148         }
149
150         r->udp_connection = uc;
151
152         uc->sockaddr = addr->sockaddr;
153         uc->socklen = addr->socklen;
154         uc->server = addr->name;
155         uc->log = cf->cycle->new_log;
156     }
157
158     return r;
159 }
160
161
162 static void
163 ngx_resolver_cleanup(void *data)
164 {
165     ngx_resolver_t  *r = data;
166
167     if (r) {
168         ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
169                        "cleanup resolver");
170
171         ngx_resolver_cleanup_tree(r, &r->name_rbtree);
172
173         ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
174
175         if (r->event) {
176             ngx_free(r->event);
177         }
178
179         if (r->udp_connection) {
180             if (r->udp_connection->connection) {
181                 ngx_close_connection(r->udp_connection->connection);
182             }
183
184             ngx_free(r->udp_connection);
185         }
186
187         ngx_free(r);
188     }
189 }
190
191
192 static void
193 ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree)
194 {
195     ngx_resolver_ctx_t   *ctx, *next;
196     ngx_resolver_node_t  *rn;
197
198     while (tree->root != tree->sentinel) {
199
200         rn = (ngx_resolver_node_t *) ngx_rbtree_min(tree->root, tree->sentinel);
201
202         ngx_queue_remove(&rn->queue);
203
204         for (ctx = rn->waiting; ctx; ctx = next) {
205             next = ctx->next;
206
207             if (ctx->event) {
208                 ngx_resolver_free(r, ctx->event);
209             }
210
211             ngx_resolver_free(r, ctx);
212         }
213
214         ngx_rbtree_delete(tree, &rn->node);
215
216         ngx_resolver_free_node(r, rn);
217     }
218 }
219
220
221 ngx_resolver_ctx_t *
222 ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
223 {
224     in_addr_t            addr;
225     ngx_resolver_ctx_t  *ctx;
226
227     if (temp) {
228         addr = ngx_inet_addr(temp->name.data, temp->name.len);
229
230         if (addr != INADDR_NONE) {
231             temp->resolver = r;
232             temp->state = NGX_OK;
233             temp->naddrs = 1;
234             temp->addrs = &temp->addr;
235             temp->addr = addr;
236             temp->quick = 1;
237
238             return temp;
239         }
240     }
241
242     if (r->udp_connection == NULL) {
243         return NGX_NO_RESOLVER;
244     }
245
246     ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t));
247
248     if (ctx) {
249         ctx->resolver = r;
250     }
251
252     return ctx;
253 }
254
255
256 ngx_int_t
257 ngx_resolve_name(ngx_resolver_ctx_t *ctx)
258 {
259     ngx_int_t        rc;
260     ngx_resolver_t  *r;
261
262     r = ctx->resolver;
263
264     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
265                    "resolve: \"%V\"", &ctx->name);
266
267     if (ctx->quick) {
268         ctx->handler(ctx);
269         return NGX_OK;
270     }
271
272     /* lock name mutex */
273
274     rc = ngx_resolve_name_locked(r, ctx);
275
276     if (rc == NGX_OK) {
277         return NGX_OK;
278     }
279
280     /* unlock name mutex */
281
282     if (rc == NGX_AGAIN) {
283         return NGX_OK;
284     }
285
286     /* NGX_ERROR */
287
288     if (ctx->event) {
289         ngx_resolver_free(r, ctx->event);
290     }
291
292     ngx_resolver_free(r, ctx);
293
294     return NGX_ERROR;
295 }
296
297
298 void
299 ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
300 {
301     uint32_t              hash;
302     ngx_resolver_t       *r;
303     ngx_resolver_ctx_t   *w, **p;
304     ngx_resolver_node_t  *rn;
305
306     r = ctx->resolver;
307
308     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
309                    "resolve name done: %i", ctx->state);
310
311     if (ctx->quick) {
312         return;
313     }
314
315     if (ctx->event && ctx->event->timer_set) {
316         ngx_del_timer(ctx->event);
317     }
318
319     /* lock name mutex */
320
321     if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
322
323         hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
324
325         rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
326
327         if (rn) {
328             p = &rn->waiting;
329             w = rn->waiting;
330
331             while (w) {
332                 if (w == ctx) {
333                     *p = w->next;
334
335                     goto done;
336                 }
337
338                 p = &w->next;
339                 w = w->next;
340             }
341         }
342
343         ngx_log_error(NGX_LOG_ALERT, r->log, 0,
344                       "could not cancel %V resolving", &ctx->name);
345     }
346
347 done:
348
349     ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue);
350
351     /* unlock name mutex */
352
353     /* lock alloc mutex */
354
355     if (ctx->event) {
356         ngx_resolver_free_locked(r, ctx->event);
357     }
358
359     ngx_resolver_free_locked(r, ctx);
360
361     /* unlock alloc mutex */
362 }
363
364
365 /* NGX_RESOLVE_A only */
366
367 static ngx_int_t
368 ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
369 {
370     uint32_t              hash;
371     in_addr_t             addr, *addrs;
372     ngx_int_t             rc;
373     ngx_uint_t            naddrs;
374     ngx_resolver_ctx_t   *next;
375     ngx_resolver_node_t  *rn;
376
377     hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
378
379     rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
380
381     if (rn) {
382
383         if (rn->valid >= ngx_time()) {
384
385             ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
386
387             ngx_queue_remove(&rn->queue);
388
389             rn->expire = ngx_time() + r->expire;
390
391             ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
392
393             naddrs = rn->naddrs;
394
395             if (naddrs) {
396
397                 /* NGX_RESOLVE_A answer */
398
399                 if (naddrs != 1) {
400                     addr = 0;
401                     addrs = ngx_resolver_dup(r, rn->u.addrs,
402                                              naddrs * sizeof(in_addr_t));
403                     if (addrs == NULL) {
404                         return NGX_ERROR;
405                     }
406
407                 } else {
408                     addr = rn->u.addr;
409                     addrs = NULL;
410                 }
411
412                 ctx->next = rn->waiting;
413                 rn->waiting = NULL;
414
415                 /* unlock name mutex */
416
417                 do {
418                     ctx->state = NGX_OK;
419                     ctx->naddrs = naddrs;
420                     ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
421                     ctx->addr = addr;
422                     next = ctx->next;
423
424                     ctx->handler(ctx);
425
426                     ctx = next;
427                 } while (ctx);
428
429                 if (addrs) {
430                     ngx_resolver_free(r, addrs);
431                 }
432
433                 return NGX_OK;
434             }
435
436             /* NGX_RESOLVE_CNAME */
437
438             if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
439
440                 ctx->name.len = rn->cnlen;
441                 ctx->name.data = rn->u.cname;
442
443                 return ngx_resolve_name_locked(r, ctx);
444             }
445
446             ctx->next = rn->waiting;
447             rn->waiting = NULL;
448
449             /* unlock name mutex */
450
451             do {
452                 ctx->state = NGX_RESOLVE_NXDOMAIN;
453                 next = ctx->next;
454
455                 ctx->handler(ctx);
456
457                 ctx = next;
458             } while (ctx);
459
460             return NGX_OK;
461         }
462
463         if (rn->waiting) {
464
465             ctx->next = rn->waiting;
466             rn->waiting = ctx;
467
468             return NGX_AGAIN;
469         }
470
471         ngx_queue_remove(&rn->queue);
472
473         /* lock alloc mutex */
474
475         ngx_resolver_free_locked(r, rn->query);
476         rn->query = NULL;
477
478         if (rn->cnlen) {
479             ngx_resolver_free_locked(r, rn->u.cname);
480         }
481
482         if (rn->naddrs > 1) {
483             ngx_resolver_free_locked(r, rn->u.addrs);
484         }
485
486         /* unlock alloc mutex */
487
488     } else {
489
490         rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
491         if (rn == NULL) {
492             return NGX_ERROR;
493         }
494
495         rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len);
496         if (rn->name == NULL) {
497             ngx_resolver_free(r, rn);
498             return NGX_ERROR;
499         }
500
501         rn->node.key = hash;
502         rn->nlen = (u_short) ctx->name.len;
503         rn->query = NULL;
504
505         ngx_rbtree_insert(&r->name_rbtree, &rn->node);
506     }
507
508     rc = ngx_resolver_create_name_query(rn, ctx);
509
510     if (rc == NGX_ERROR) {
511         goto failed;
512     }
513
514     if (rc == NGX_DECLINED) {
515         ngx_rbtree_delete(&r->name_rbtree, &rn->node);
516
517         ngx_resolver_free(r, rn->query);
518         ngx_resolver_free(r, rn->name);
519         ngx_resolver_free(r, rn);
520
521         ctx->state = NGX_RESOLVE_NXDOMAIN;
522         ctx->handler(ctx);
523
524         return NGX_OK;
525     }
526
527     if (ngx_resolver_send_query(r, rn) != NGX_OK) {
528         goto failed;
529     }
530
531     if (ctx->event == NULL) {
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
545     if (ngx_queue_empty(&r->name_resend_queue)) {
546         ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
547     }
548
549     rn->expire = ngx_time() + r->resend_timeout;
550
551     ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
552
553     rn->cnlen = 0;
554     rn->naddrs = 0;
555     rn->valid = 0;
556     rn->waiting = ctx;
557
558     ctx->state = NGX_AGAIN;
559
560     return NGX_AGAIN;
561
562 failed:
563
564     ngx_rbtree_delete(&r->name_rbtree, &rn->node);
565
566     if (rn->query) {
567         ngx_resolver_free(r, rn->query);
568     }
569
570     ngx_resolver_free(r, rn->name);
571
572     ngx_resolver_free(r, rn);
573
574     return NGX_ERROR;
575 }
576
577
578 ngx_int_t
579 ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
580 {
581     u_char               *name;
582     ngx_resolver_t       *r;
583     ngx_resolver_node_t  *rn;
584
585     r = ctx->resolver;
586
587     ctx->addr = ntohl(ctx->addr);
588
589     /* lock addr mutex */
590
591     rn = ngx_resolver_lookup_addr(r, ctx->addr);
592
593     if (rn) {
594
595         if (rn->valid >= ngx_time()) {
596
597             ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
598
599             ngx_queue_remove(&rn->queue);
600
601             rn->expire = ngx_time() + r->expire;
602
603             ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
604
605             name = ngx_resolver_dup(r, rn->name, rn->nlen);
606             if (name == NULL) {
607                 goto failed;
608             }
609
610             ctx->name.len = rn->nlen;
611             ctx->name.data = name;
612
613             /* unlock addr mutex */
614
615             ctx->state = NGX_OK;
616
617             ctx->handler(ctx);
618
619             ngx_resolver_free(r, name);
620
621             return NGX_OK;
622         }
623
624         if (rn->waiting) {
625
626             ctx->next = rn->waiting;
627             rn->waiting = ctx;
628
629             /* unlock addr mutex */
630
631             return NGX_OK;
632         }
633
634         ngx_queue_remove(&rn->queue);
635
636         ngx_resolver_free(r, rn->query);
637         rn->query = NULL;
638
639     } else {
640         rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
641         if (rn == NULL) {
642             goto failed;
643         }
644
645         rn->node.key = ctx->addr;
646         rn->query = NULL;
647
648         ngx_rbtree_insert(&r->addr_rbtree, &rn->node);
649     }
650
651     if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
652         goto failed;
653     }
654
655     if (ngx_resolver_send_query(r, rn) != NGX_OK) {
656         goto failed;
657     }
658
659     ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
660     if (ctx->event == NULL) {
661         goto failed;
662     }
663
664     ctx->event->handler = ngx_resolver_timeout_handler;
665     ctx->event->data = ctx;
666     ctx->event->log = r->log;
667     ctx->ident = -1;
668
669     ngx_add_timer(ctx->event, ctx->timeout);
670
671     if (ngx_queue_empty(&r->addr_resend_queue)) {
672         ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
673     }
674
675     rn->expire = ngx_time() + r->resend_timeout;
676
677     ngx_queue_insert_head(&r->addr_resend_queue, &rn->queue);
678
679     rn->cnlen = 0;
680     rn->naddrs = 0;
681     rn->name = NULL;
682     rn->nlen = 0;
683     rn->valid = 0;
684     rn->waiting = ctx;
685
686     /* unlock addr mutex */
687
688     ctx->state = NGX_AGAIN;
689
690     return NGX_OK;
691
692 failed:
693
694     if (rn) {
695         ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
696
697         if (rn->query) {
698             ngx_resolver_free(r, rn->query);
699         }
700
701         ngx_resolver_free(r, rn);
702     }
703
704     /* unlock addr mutex */
705
706     if (ctx->event) {
707         ngx_resolver_free(r, ctx->event);
708     }
709
710     ngx_resolver_free(r, ctx);
711
712     return NGX_ERROR;
713 }
714
715
716 void
717 ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
718 {
719     in_addr_t             addr;
720     ngx_resolver_t       *r;
721     ngx_resolver_ctx_t   *w, **p;
722     ngx_resolver_node_t  *rn;
723
724     r = ctx->resolver;
725
726     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
727                    "resolve addr done: %i", ctx->state);
728
729     if (ctx->event && ctx->event->timer_set) {
730         ngx_del_timer(ctx->event);
731     }
732
733     /* lock addr mutex */
734
735     if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
736
737         rn = ngx_resolver_lookup_addr(r, ctx->addr);
738
739         if (rn) {
740             p = &rn->waiting;
741             w = rn->waiting;
742
743             while (w) {
744                 if (w == ctx) {
745                     *p = w->next;
746
747                     goto done;
748                 }
749
750                 p = &w->next;
751                 w = w->next;
752             }
753         }
754
755         addr = ntohl(ctx->addr);
756
757         ngx_log_error(NGX_LOG_ALERT, r->log, 0,
758                       "could not cancel %ud.%ud.%ud.%ud resolving",
759                       (addr >> 24) & 0xff, (addr >> 16) & 0xff,
760                       (addr >> 8) & 0xff, addr & 0xff);
761     }
762
763 done:
764
765     ngx_resolver_expire(r, &r->addr_rbtree, &r->addr_expire_queue);
766
767     /* unlock addr mutex */
768
769     /* lock alloc mutex */
770
771     if (ctx->event) {
772         ngx_resolver_free_locked(r, ctx->event);
773     }
774
775     ngx_resolver_free_locked(r, ctx);
776
777     /* unlock alloc mutex */
778 }
779
780
781 static void
782 ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
783 {
784     time_t                now;
785     ngx_uint_t            i;
786     ngx_queue_t          *q;
787     ngx_resolver_node_t  *rn;
788
789     ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire");
790
791     now = ngx_time();
792
793     for (i = 0; i < 2; i++) {
794         if (ngx_queue_empty(queue)) {
795             return;
796         }
797
798         q = ngx_queue_last(queue);
799
800         rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
801
802         if (now <= rn->expire) {
803             return;
804         }
805
806         ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
807                        "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name);
808
809         ngx_queue_remove(q);
810
811         ngx_rbtree_delete(tree, &rn->node);
812
813         ngx_resolver_free_node(r, rn);
814     }
815 }
816
817
818 static ngx_int_t
819 ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
820 {
821     ssize_t                n;
822     ngx_udp_connection_t  *uc;
823
824     uc = r->udp_connection;
825
826     if (uc->connection == NULL) {
827         if (ngx_udp_connect(uc) != NGX_OK) {
828             return NGX_ERROR;
829         }
830
831         uc->connection->data = r;
832         uc->connection->read->handler = ngx_resolver_read_response;
833         uc->connection->read->resolver = 1;
834     }
835
836     n = ngx_send(uc->connection, rn->query, rn->qlen);
837
838     if (n == -1) {
839         return NGX_ERROR;
840     }
841
842     if ((size_t) n != (size_t) rn->qlen) {
843         ngx_log_error(NGX_LOG_CRIT, uc->log, 0, "send() incomplete");
844         return NGX_ERROR;
845     }
846
847     return NGX_OK;
848 }
849
850
851 static void
852 ngx_resolver_resend_handler(ngx_event_t *ev)
853 {
854     time_t           timer, atimer, ntimer;
855     ngx_resolver_t  *r;
856
857     r = ev->data;
858
859     ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0,
860                    "resolver resend handler");
861
862     /* lock name mutex */
863
864     ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue);
865
866     /* unlock name mutex */
867
868     /* lock addr mutex */
869
870     atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue);
871
872     /* unlock addr mutex */
873
874     if (ntimer == 0) {
875         timer = atimer;
876
877     } else if (atimer == 0) {
878         timer = ntimer;
879
880     } else {
881         timer = (atimer < ntimer) ? atimer : ntimer;
882     }
883
884     if (timer) {
885         ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
886     }
887 }
888
889
890 static time_t
891 ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
892 {
893     time_t                now;
894     ngx_queue_t          *q;
895     ngx_resolver_node_t  *rn;
896
897     now = ngx_time();
898
899     for ( ;; ) {
900         if (ngx_queue_empty(queue)) {
901             return 0;
902         }
903
904         q = ngx_queue_last(queue);
905
906         rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
907
908         if (now < rn->expire) {
909             return rn->expire - now;
910         }
911
912         ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
913                        "resolver resend \"%*s\" %p",
914                        (size_t) rn->nlen, rn->name, rn->waiting);
915
916         ngx_queue_remove(q);
917
918         if (rn->waiting) {
919
920             if (ngx_resolver_send_query(r, rn) == NGX_OK) {
921
922                 rn->expire = now + r->resend_timeout;
923
924                 ngx_queue_insert_head(queue, &rn->queue);
925             }
926
927             continue;
928         }
929
930         ngx_rbtree_delete(tree, &rn->node);
931
932         ngx_resolver_free_node(r, rn);
933     }
934 }
935
936
937 static void
938 ngx_resolver_read_response(ngx_event_t *rev)
939 {
940     ssize_t            n;
941     ngx_connection_t  *c;
942     u_char             buf[NGX_RESOLVER_UDP_SIZE];
943
944     c = rev->data;
945
946     do {
947         n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
948
949         if (n < 0) {
950             return;
951         }
952
953         ngx_resolver_process_response(c->data, buf, n);
954
955     } while (rev->ready);
956 }
957
958
959 static void
960 ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
961 {
962     char                  *err;
963     size_t                 len;
964     ngx_uint_t             i, times, ident, qident, flags, code, nqs, nan,
965                            qtype, qclass;
966     ngx_queue_t           *q;
967     ngx_resolver_qs_t     *qs;
968     ngx_resolver_node_t   *rn;
969     ngx_resolver_query_t  *query;
970
971     if ((size_t) n < sizeof(ngx_resolver_query_t)) {
972         goto short_response;
973     }
974
975     query = (ngx_resolver_query_t *) buf;
976
977     ident = (query->ident_hi << 8) + query->ident_lo;
978     flags = (query->flags_hi << 8) + query->flags_lo;
979     nqs = (query->nqs_hi << 8) + query->nqs_lo;
980     nan = (query->nan_hi << 8) + query->nan_lo;
981
982     ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
983                    "resolver DNS response %ui fl:%04Xui %ui/%ui/%ui/%ui",
984                    ident, flags, nqs, nan,
985                    (query->nns_hi << 8) + query->nns_lo,
986                    (query->nar_hi << 8) + query->nar_lo);
987
988     if (!(flags & 0x8000)) {
989         ngx_log_error(r->log_level, r->log, 0,
990                       "invalid DNS response %ui fl:%04Xui", ident, flags);
991         return;
992     }
993
994     code = flags & 0x7f;
995
996     if (code == NGX_RESOLVE_FORMERR) {
997
998         times = 0;
999
1000         for (q = ngx_queue_head(&r->name_resend_queue);
1001              q != ngx_queue_sentinel(&r->name_resend_queue) || times++ < 100;
1002              q = ngx_queue_next(q))
1003         {
1004             rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1005             qident = (rn->query[0] << 8) + rn->query[1];
1006
1007             if (qident == ident) {
1008                 ngx_log_error(r->log_level, r->log, 0,
1009                               "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
1010                               code, ngx_resolver_strerror(code), ident,
1011                               rn->nlen, rn->name);
1012                 return;
1013             }
1014         }
1015
1016         goto dns_error;
1017     }
1018
1019     if (code > NGX_RESOLVE_REFUSED) {
1020         goto dns_error;
1021     }
1022
1023     if (nqs != 1) {
1024         err = "invalid number of questions in DNS response";
1025         goto done;
1026     }
1027
1028     i = sizeof(ngx_resolver_query_t);
1029
1030     while (i < (ngx_uint_t) n) {
1031         if (buf[i] == '\0') {
1032             goto found;
1033         }
1034
1035         len = buf[i];
1036         i += 1 + len;
1037     }
1038
1039     goto short_response;
1040
1041 found:
1042
1043     if (i++ == 0) {
1044         err = "zero-length domain name in DNS response";
1045         goto done;
1046     }
1047
1048     if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t))
1049         > (ngx_uint_t) n)
1050     {
1051         goto short_response;
1052     }
1053
1054     qs = (ngx_resolver_qs_t *) &buf[i];
1055
1056     qtype = (qs->type_hi << 8) + qs->type_lo;
1057     qclass = (qs->class_hi << 8) + qs->class_lo;
1058
1059     ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1060                    "resolver DNS response qt:%ui cl:%ui", qtype, qclass);
1061
1062     if (qclass != 1) {
1063         ngx_log_error(r->log_level, r->log, 0,
1064                       "unknown query class %ui in DNS response", qclass);
1065         return;
1066     }
1067
1068     switch (qtype) {
1069
1070     case NGX_RESOLVE_A:
1071
1072         ngx_resolver_process_a(r, buf, n, ident, code, nan,
1073                                i + sizeof(ngx_resolver_qs_t));
1074
1075         break;
1076
1077     case NGX_RESOLVE_PTR:
1078
1079         ngx_resolver_process_ptr(r, buf, n, ident, code, nan);
1080
1081         break;
1082
1083     default:
1084         ngx_log_error(r->log_level, r->log, 0,
1085                       "unknown query type %ui in DNS response", qtype);
1086         return;
1087     }
1088
1089     return;
1090
1091 short_response:
1092
1093     err = "short dns response";
1094
1095 done:
1096
1097     ngx_log_error(r->log_level, r->log, 0, err);
1098
1099     return;
1100
1101 dns_error:
1102
1103     ngx_log_error(r->log_level, r->log, 0,
1104                   "DNS error (%ui: %s), query id:%ui",
1105                   code, ngx_resolver_strerror(code), ident);
1106     return;
1107 }
1108
1109
1110 static void
1111 ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
1112     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans)
1113 {
1114     char                 *err;
1115     u_char               *cname;
1116     size_t                len;
1117     uint32_t              hash;
1118     in_addr_t             addr, *addrs;
1119     ngx_str_t             name;
1120     ngx_uint_t            qtype, qident, naddrs, a, i, n, start;
1121     ngx_resolver_an_t    *an;
1122     ngx_resolver_ctx_t   *ctx, *next;
1123     ngx_resolver_node_t  *rn;
1124
1125     if (ngx_resolver_copy(r, &name, buf, &buf[12], &buf[last]) != NGX_OK) {
1126         return;
1127     }
1128
1129     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
1130
1131     hash = ngx_crc32_short(name.data, name.len);
1132
1133     /* lock name mutex */
1134
1135     rn = ngx_resolver_lookup_name(r, &name, hash);
1136
1137     if (rn == NULL || rn->query == NULL) {
1138         ngx_log_error(r->log_level, r->log, 0,
1139                       "unexpected response for %V", &name);
1140         goto failed;
1141     }
1142
1143     qident = (rn->query[0] << 8) + rn->query[1];
1144
1145     if (ident != qident) {
1146         ngx_log_error(r->log_level, r->log, 0,
1147                       "wrong ident %ui response for %V, expect %ui",
1148                       ident, &name, qident);
1149         goto failed;
1150     }
1151
1152     if (code == 0 && nan == 0) {
1153         code = 3; /* NXDOMAIN */
1154     }
1155
1156     if (code) {
1157         next = rn->waiting;
1158         rn->waiting = NULL;
1159
1160         ngx_queue_remove(&rn->queue);
1161
1162         ngx_rbtree_delete(&r->name_rbtree, &rn->node);
1163
1164         ngx_resolver_free_node(r, rn);
1165
1166         /* unlock name mutex */
1167
1168         while (next) {
1169              ctx = next;
1170              ctx->state = code;
1171              next = ctx->next;
1172
1173              ctx->handler(ctx);
1174         }
1175
1176         return;
1177     }
1178
1179     i = ans;
1180     naddrs = 0;
1181     addr = 0;
1182     addrs = NULL;
1183     cname = NULL;
1184     qtype = 0;
1185
1186     for (a = 0; a < nan; a++) {
1187
1188         start = i;
1189
1190         while (i < last) {
1191
1192             if (buf[i] & 0xc0) {
1193                 i += 2;
1194                 goto found;
1195             }
1196
1197             if (buf[i] == 0) {
1198                 i++;
1199                 goto test_length;
1200             }
1201
1202             i += 1 + buf[i];
1203         }
1204
1205         goto short_response;
1206
1207     test_length:
1208
1209         if (i - start < 2) {
1210             err = "invalid name in dns response";
1211             goto invalid;
1212         }
1213
1214     found:
1215
1216         if (i + sizeof(ngx_resolver_an_t) >= last) {
1217             goto short_response;
1218         }
1219
1220         an = (ngx_resolver_an_t *) &buf[i];
1221
1222         qtype = (an->type_hi << 8) + an->type_lo;
1223         len = (an->len_hi << 8) + an->len_lo;
1224
1225         if (qtype == NGX_RESOLVE_A) {
1226
1227             i += sizeof(ngx_resolver_an_t);
1228
1229             if (i + len > last) {
1230                 goto short_response;
1231             }
1232
1233             addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
1234                          + (buf[i + 2] << 8) + (buf[i + 3]));
1235
1236             naddrs++;
1237
1238             i += len;
1239
1240         } else if (qtype == NGX_RESOLVE_CNAME) {
1241             cname = &buf[i] + sizeof(ngx_resolver_an_t);
1242             i += sizeof(ngx_resolver_an_t) + len;
1243
1244         } else if (qtype == NGX_RESOLVE_DNAME) {
1245             i += sizeof(ngx_resolver_an_t) + len;
1246
1247         } else {
1248             ngx_log_error(r->log_level, r->log, 0,
1249                           "unexpected qtype %ui", qtype);
1250         }
1251     }
1252
1253     ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1254                    "resolver naddrs:%ui cname:%p", naddrs, cname);
1255
1256     if (naddrs) {
1257
1258         if (naddrs == 1) {
1259             rn->u.addr = addr;
1260
1261         } else {
1262
1263             addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
1264             if (addrs == NULL) {
1265                 return;
1266             }
1267
1268             n = 0;
1269             i = ans;
1270
1271             for (a = 0; a < nan; a++) {
1272
1273                 for ( ;; ) {
1274
1275                     if (buf[i] & 0xc0) {
1276                         i += 2;
1277                         goto ok;
1278                     }
1279
1280                     if (buf[i] == 0) {
1281                         i++;
1282                         goto ok;
1283                     }
1284
1285                     i += 1 + buf[i];
1286                 }
1287
1288             ok:
1289
1290                 an = (ngx_resolver_an_t *) &buf[i];
1291
1292                 qtype = (an->type_hi << 8) + an->type_lo;
1293                 len = (an->len_hi << 8) + an->len_lo;
1294
1295                 i += sizeof(ngx_resolver_an_t);
1296
1297                 if (qtype == NGX_RESOLVE_A) {
1298
1299                     addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
1300                                        + (buf[i + 2] << 8) + (buf[i + 3]));
1301
1302                     if (n == naddrs) {
1303                         break;
1304                     }
1305                 }
1306
1307                 i += len;
1308             }
1309
1310             rn->u.addrs = addrs;
1311
1312             addrs = ngx_resolver_dup(r, rn->u.addrs,
1313                                      naddrs * sizeof(in_addr_t));
1314             if (addrs == NULL) {
1315                 return;
1316             }
1317         }
1318
1319         rn->naddrs = (u_short) naddrs;
1320
1321         ngx_queue_remove(&rn->queue);
1322
1323         rn->valid = ngx_time() + r->valid;
1324         rn->expire = ngx_time() + r->expire;
1325
1326         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
1327
1328         next = rn->waiting;
1329         rn->waiting = NULL;
1330
1331         /* unlock name mutex */
1332
1333         while (next) {
1334              ctx = next;
1335              ctx->state = NGX_OK;
1336              ctx->naddrs = naddrs;
1337              ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
1338              ctx->addr = addr;
1339              next = ctx->next;
1340
1341              ctx->handler(ctx);
1342         }
1343
1344         if (naddrs > 1) {
1345             ngx_resolver_free(r, addrs);
1346         }
1347
1348         return;
1349
1350     } else if (cname) {
1351
1352         /* CNAME only */
1353
1354         if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) {
1355             return;
1356         }
1357
1358         ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
1359                        "resolver cname:\"%V\"", &name);
1360
1361         ngx_queue_remove(&rn->queue);
1362
1363         rn->cnlen = (u_short) name.len;
1364         rn->u.cname = name.data;
1365         rn->valid = ngx_time() + r->valid;
1366         rn->expire = ngx_time() + r->expire;
1367
1368         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
1369
1370         ctx = rn->waiting;
1371         rn->waiting = NULL;
1372
1373         if (ctx) {
1374             ctx->name = name;
1375
1376             (void) ngx_resolve_name_locked(r, ctx);
1377         }
1378
1379         return;
1380     }
1381
1382     ngx_log_error(r->log_level, r->log, 0,
1383                "no A or CNAME types in DNS responses, unknown query type: %ui",
1384                qtype);
1385     return;
1386
1387 short_response:
1388
1389     err = "short dns response";
1390
1391 invalid:
1392
1393     /* unlock name mutex */
1394
1395     ngx_log_error(r->log_level, r->log, 0, err);
1396
1397     return;
1398
1399 failed:
1400
1401     /* unlock name mutex */
1402
1403     return;
1404 }
1405
1406
1407 static void
1408 ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
1409     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
1410 {
1411     char                 *err;
1412     size_t                len;
1413     in_addr_t             addr;
1414     ngx_int_t             digit;
1415     ngx_str_t             name;
1416     ngx_uint_t            i, mask, qtype, qclass, qident;
1417     ngx_resolver_an_t    *an;
1418     ngx_resolver_ctx_t   *ctx, *next;
1419     ngx_resolver_node_t  *rn;
1420
1421     if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) {
1422         goto invalid_in_addr_arpa;
1423     }
1424
1425     addr = 0;
1426     i = 12;
1427
1428     for (mask = 0; mask < 32; mask += 8) {
1429         len = buf[i++];
1430
1431         digit = ngx_atoi(&buf[i], len);
1432         if (digit == NGX_ERROR || digit > 255) {
1433             goto invalid_in_addr_arpa;
1434         }
1435
1436         addr += digit << mask;
1437         i += len;
1438     }
1439
1440     if (ngx_strcmp(&buf[i], "\7in-addr\4arpa") != 0) {
1441         goto invalid_in_addr_arpa;
1442     }
1443
1444     /* lock addr mutex */
1445
1446     rn = ngx_resolver_lookup_addr(r, addr);
1447
1448     if (rn == NULL || rn->query == NULL) {
1449         ngx_log_error(r->log_level, r->log, 0,
1450                       "unexpected response for %ud.%ud.%ud.%ud",
1451                       (addr >> 24) & 0xff, (addr >> 16) & 0xff,
1452                       (addr >> 8) & 0xff, addr & 0xff);
1453         goto failed;
1454     }
1455
1456     qident = (rn->query[0] << 8) + rn->query[1];
1457
1458     if (ident != qident) {
1459         ngx_log_error(r->log_level, r->log, 0,
1460                     "wrong ident %ui response for %ud.%ud.%ud.%ud, expect %ui",
1461                     ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff,
1462                     (addr >> 8) & 0xff, addr & 0xff, qident);
1463         goto failed;
1464     }
1465
1466     if (code == 0 && nan == 0) {
1467         code = 3; /* NXDOMAIN */
1468     }
1469
1470     if (code) {
1471         next = rn->waiting;
1472         rn->waiting = NULL;
1473
1474         ngx_queue_remove(&rn->queue);
1475
1476         ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
1477
1478         ngx_resolver_free_node(r, rn);
1479
1480         /* unlock addr mutex */
1481
1482         while (next) {
1483              ctx = next;
1484              ctx->state = code;
1485              next = ctx->next;
1486
1487              ctx->handler(ctx);
1488         }
1489
1490         return;
1491     }
1492
1493     i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);
1494
1495     if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) {
1496         goto short_response;
1497     }
1498
1499     /* compression pointer to "XX.XX.XX.XX.in-addr.arpa */
1500
1501     if (buf[i] != 0xc0 || buf[i + 1] != 0x0c) {
1502         err = "invalid in-addr.arpa name in DNS response";
1503         goto invalid;
1504     }
1505
1506     an = (ngx_resolver_an_t *) &buf[i + 2];
1507
1508     qtype = (an->type_hi << 8) + an->type_lo;
1509     qclass = (an->class_hi << 8) + an->class_lo;
1510     len = (an->len_hi << 8) + an->len_lo;
1511
1512     ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
1513                   "resolver qt:%ui cl:%ui len:%uz", qtype, qclass, len);
1514
1515     i += 2 + sizeof(ngx_resolver_an_t);
1516
1517     if (i + len > (ngx_uint_t) n) {
1518         goto short_response;
1519     }
1520
1521     if (ngx_resolver_copy(r, &name, buf, &buf[i], &buf[n]) != NGX_OK) {
1522         return;
1523     }
1524
1525     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
1526
1527     if (name.len != (size_t) rn->nlen
1528         || ngx_strncmp(name.data, rn->name, name.len) != 0)
1529     {
1530         if (rn->nlen) {
1531             ngx_resolver_free(r, rn->name);
1532         }
1533
1534         rn->nlen = (u_short) name.len;
1535         rn->name = name.data;
1536
1537         name.data = ngx_resolver_dup(r, rn->name, name.len);
1538         if (name.data == NULL) {
1539             goto failed;
1540         }
1541     }
1542
1543     ngx_queue_remove(&rn->queue);
1544
1545     rn->valid = ngx_time() + r->valid;
1546     rn->expire = ngx_time() + r->expire;
1547
1548     ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
1549
1550     next = rn->waiting;
1551     rn->waiting = NULL;
1552
1553     /* unlock addr mutex */
1554
1555     while (next) {
1556          ctx = next;
1557          ctx->state = NGX_OK;
1558          ctx->name = name;
1559          next = ctx->next;
1560
1561          ctx->handler(ctx);
1562     }
1563
1564     ngx_resolver_free(r, name.data);
1565
1566     return;
1567
1568 invalid_in_addr_arpa:
1569
1570     ngx_log_error(r->log_level, r->log, 0,
1571                   "invalid in-addr.arpa name in DNS response");
1572     return;
1573
1574 short_response:
1575
1576     err = "short DNS response";
1577
1578 invalid:
1579
1580     /* unlock addr mutex */
1581
1582     ngx_log_error(r->log_level, r->log, 0, err);
1583
1584     return;
1585
1586 failed:
1587
1588     /* unlock addr mutex */
1589
1590     return;
1591 }
1592
1593
1594 static ngx_resolver_node_t *
1595 ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
1596 {
1597     ngx_int_t             rc;
1598     size_t                len;
1599     ngx_rbtree_node_t    *node, *sentinel;
1600     ngx_resolver_node_t  *rn;
1601
1602     node = r->name_rbtree.root;
1603     sentinel = r->name_rbtree.sentinel;
1604
1605     while (node != sentinel) {
1606
1607         if (hash < node->key) {
1608             node = node->left;
1609             continue;
1610         }
1611
1612         if (hash > node->key) {
1613             node = node->right;
1614             continue;
1615         }
1616
1617         /* hash == node->key */
1618
1619         do {
1620             rn = (ngx_resolver_node_t *) node;
1621
1622             len = (name->len > (size_t) rn->nlen) ? rn->nlen : name->len;
1623
1624             rc = ngx_strncmp(name->data, rn->name, len);
1625
1626             if (rc == 0) {
1627                 return rn;
1628             }
1629
1630             node = (rc < 0) ? node->left : node->right;
1631
1632         } while (node != sentinel && hash == node->key);
1633
1634         break;
1635     }
1636
1637     /* not found */
1638
1639     return NULL;
1640 }
1641
1642
1643 static ngx_resolver_node_t *
1644 ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
1645 {
1646     ngx_rbtree_node_t  *node, *sentinel;
1647
1648     node = r->addr_rbtree.root;
1649     sentinel = r->addr_rbtree.sentinel;
1650
1651     while (node != sentinel) {
1652
1653         if (addr < node->key) {
1654             node = node->left;
1655             continue;
1656         }
1657
1658         if (addr > node->key) {
1659             node = node->right;
1660             continue;
1661         }
1662
1663         /* addr == node->key */
1664
1665         return (ngx_resolver_node_t *) node;
1666     }
1667
1668     /* not found */
1669
1670     return NULL;
1671 }
1672
1673
1674 static void
1675 ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
1676     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
1677 {
1678     size_t                 len;
1679     ngx_rbtree_node_t    **p;
1680     ngx_resolver_node_t   *rn, *rn_temp;
1681
1682     for ( ;; ) {
1683
1684         if (node->key < temp->key) {
1685
1686             p = &temp->left;
1687
1688         } else if (node->key > temp->key) {
1689
1690             p = &temp->right;
1691
1692         } else { /* node->key == temp->key */
1693
1694             rn = (ngx_resolver_node_t *) node;
1695             rn_temp = (ngx_resolver_node_t *) temp;
1696
1697             len = (rn->nlen > rn_temp->nlen) ? rn_temp->nlen : rn->nlen;
1698
1699             p = (ngx_strncmp(rn->name, rn_temp->name, len) < 0)
1700                     ? &temp->left : &temp->right;
1701         }
1702
1703         if (*p == sentinel) {
1704             break;
1705         }
1706
1707         temp = *p;
1708     }
1709
1710     *p = node;
1711     node->parent = temp;
1712     node->left = sentinel;
1713     node->right = sentinel;
1714     ngx_rbt_red(node);
1715 }
1716
1717
1718 static ngx_int_t
1719 ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
1720 {
1721     u_char                *p, *s;
1722     size_t                 len;
1723     ngx_uint_t             ident;
1724     ngx_resolver_qs_t     *qs;
1725     ngx_resolver_query_t  *query;
1726
1727     len = sizeof(ngx_resolver_query_t)
1728           + 1 + ctx->name.len + 1 + sizeof(ngx_resolver_qs_t);
1729
1730     p = ngx_resolver_calloc(ctx->resolver, len);
1731     if (p == NULL) {
1732         return NGX_ERROR;
1733     }
1734
1735     rn->qlen = (u_short) len;
1736     rn->query = p;
1737
1738     query = (ngx_resolver_query_t *) p;
1739
1740     ident = ngx_random();
1741
1742     ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
1743                    "resolve: \"%V\" %i", &ctx->name, ident & 0xffff);
1744
1745     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
1746     query->ident_lo = (u_char) (ident & 0xff);
1747
1748     /* recursion query */
1749     query->flags_hi = 1; query->flags_lo = 0;
1750
1751     /* one question */
1752     query->nqs_hi = 0; query->nqs_lo = 1;
1753     query->nan_hi = 0; query->nan_lo = 0;
1754     query->nns_hi = 0; query->nns_lo = 0;
1755     query->nar_hi = 0; query->nar_lo = 0;
1756
1757     p += sizeof(ngx_resolver_query_t) + 1 + ctx->name.len + 1;
1758
1759     qs = (ngx_resolver_qs_t *) p;
1760
1761     /* query type */
1762     qs->type_hi = 0; qs->type_lo = (u_char) ctx->type;
1763
1764     /* IP query class */
1765     qs->class_hi = 0; qs->class_lo = 1;
1766
1767     /* convert "www.example.com" to "\3www\7example\3com\0" */
1768
1769     len = 0;
1770     p--;
1771     *p-- = '\0';
1772
1773     for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) {
1774         if (*s != '.') {
1775             *p = *s;
1776             len++;
1777
1778         } else {
1779             if (len == 0) {
1780                 return NGX_DECLINED;
1781             }
1782
1783             *p = (u_char) len;
1784             len = 0;
1785         }
1786
1787         p--;
1788     }
1789
1790     *p = (u_char) len;
1791
1792     return NGX_OK;
1793 }
1794
1795
1796 /* AF_INET only */
1797
1798 static ngx_int_t
1799 ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
1800 {
1801     u_char                *p, *d;
1802     size_t                 len;
1803     ngx_int_t              n;
1804     ngx_uint_t             ident;
1805     ngx_resolver_query_t  *query;
1806
1807     len = sizeof(ngx_resolver_query_t)
1808           + sizeof(".255.255.255.255.in-addr.arpa.") - 1
1809           + sizeof(ngx_resolver_qs_t);
1810
1811     p = ngx_resolver_calloc(ctx->resolver, len);
1812     if (p == NULL) {
1813         return NGX_ERROR;
1814     }
1815
1816     rn->query = p;
1817     query = (ngx_resolver_query_t *) p;
1818
1819     ident = ngx_random();
1820
1821     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
1822     query->ident_lo = (u_char) (ident & 0xff);
1823
1824     /* recursion query */
1825     query->flags_hi = 1; query->flags_lo = 0;
1826
1827     /* one question */
1828     query->nqs_hi = 0; query->nqs_lo = 1;
1829     query->nan_hi = 0; query->nan_lo = 0;
1830     query->nns_hi = 0; query->nns_lo = 0;
1831     query->nar_hi = 0; query->nar_lo = 0;
1832
1833     p += sizeof(ngx_resolver_query_t);
1834
1835     for (n = 0; n < 32; n += 8){
1836         d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff);
1837         *p = (u_char) (d - &p[1]);
1838         p = d;
1839     }
1840
1841     /* query type "PTR", IP query class */
1842     ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);
1843
1844     rn->qlen = (u_short)
1845                   (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t)
1846                    - rn->query);
1847
1848     return NGX_OK;
1849 }
1850
1851
1852 static ngx_int_t
1853 ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src,
1854     u_char *last)
1855 {
1856     char        *err;
1857     u_char      *p, *dst;
1858     ssize_t      len;
1859     ngx_uint_t   i, n;
1860
1861     p = src;
1862     len = -1;
1863
1864     /*
1865      * compression pointers allow to create endless loop, so we set limit;
1866      * 128 pointers should be enough to store 255-byte name
1867      */
1868
1869     for (i = 0; i < 128; i++) {
1870         n = *p++;
1871
1872         if (n == 0) {
1873             goto done;
1874         }
1875
1876         if (n & 0xc0) {
1877             n = ((n & 0x3f) << 8) + *p;
1878             p = &buf[n];
1879
1880         } else {
1881             len += 1 + n;
1882             p = &p[n];
1883         }
1884
1885         if (p >= last) {
1886             err = "name is out of response";
1887             goto invalid;
1888         }
1889     }
1890
1891     err = "compression pointers loop";
1892
1893 invalid:
1894
1895     ngx_log_error(r->log_level, r->log, 0, err);
1896
1897     return NGX_ERROR;
1898
1899 done:
1900
1901     if (name == NULL) {
1902         return NGX_OK;
1903     }
1904
1905     dst = ngx_resolver_alloc(r, len);
1906     if (dst == NULL) {
1907         return NGX_ERROR;
1908     }
1909
1910     name->data = dst;
1911
1912     n = *src++;
1913
1914     for ( ;; ) {
1915         if (n != 0xc0) {
1916             ngx_memcpy(dst, src, n);
1917             dst += n;
1918             src += n;
1919
1920             n = *src++;
1921
1922             if (n != 0) {
1923                 *dst++ = '.';
1924             }
1925
1926         } else {
1927             n = ((n & 0x3f) << 8) + *src;
1928             src = &buf[n];
1929
1930             n = *src++;
1931         }
1932
1933         if (n == 0) {
1934             name->len = dst - name->data;
1935             return NGX_OK;
1936         }
1937     }
1938 }
1939
1940
1941 static void
1942 ngx_resolver_timeout_handler(ngx_event_t *ev)
1943 {
1944     ngx_resolver_ctx_t  *ctx;
1945
1946     ctx = ev->data;
1947
1948     ctx->state = NGX_RESOLVE_TIMEDOUT;
1949
1950     ctx->handler(ctx);
1951 }
1952
1953
1954 static void
1955 ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
1956 {
1957     /* lock alloc mutex */
1958
1959     if (rn->query) {
1960         ngx_resolver_free_locked(r, rn->query);
1961     }
1962
1963     if (rn->name) {
1964         ngx_resolver_free_locked(r, rn->name);
1965     }
1966
1967     if (rn->cnlen) {
1968         ngx_resolver_free_locked(r, rn->u.cname);
1969     }
1970
1971     if (rn->naddrs > 1) {
1972         ngx_resolver_free_locked(r, rn->u.addrs);
1973     }
1974
1975     ngx_resolver_free_locked(r, rn);
1976
1977     /* unlock alloc mutex */
1978 }
1979
1980
1981 static void *
1982 ngx_resolver_alloc(ngx_resolver_t *r, size_t size)
1983 {
1984     u_char  *p;
1985
1986     /* lock alloc mutex */
1987
1988     p = ngx_alloc(size, r->log);
1989
1990     /* unlock alloc mutex */
1991
1992     return p;
1993 }
1994
1995
1996 static void *
1997 ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
1998 {
1999     u_char  *p;
2000
2001     p = ngx_resolver_alloc(r, size);
2002
2003     if (p) {
2004         ngx_memzero(p, size);
2005     }
2006
2007     return p;
2008 }
2009
2010
2011 static void
2012 ngx_resolver_free(ngx_resolver_t *r, void *p)
2013 {
2014     /* lock alloc mutex */
2015
2016     ngx_free(p);
2017
2018     /* unlock alloc mutex */
2019 }
2020
2021
2022 static void
2023 ngx_resolver_free_locked(ngx_resolver_t *r, void *p)
2024 {
2025     ngx_free(p);
2026 }
2027
2028
2029 static void *
2030 ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
2031 {
2032     void  *dst;
2033
2034     dst = ngx_resolver_alloc(r, size);
2035
2036     if (dst == NULL) {
2037         return dst;
2038     }
2039
2040     ngx_memcpy(dst, src, size);
2041
2042     return dst;
2043 }
2044
2045
2046 char *
2047 ngx_resolver_strerror(ngx_int_t err)
2048 {
2049     static char *errors[] = {
2050         "Format error",     /* FORMERR */
2051         "Server failure",   /* SERVFAIL */
2052         "Host not found",   /* NXDOMAIN */
2053         "Unimplemented",    /* NOTIMP */
2054         "Operation refused" /* REFUSED */
2055     };
2056
2057     if (err > 0 && err < 6) {
2058         return errors[err - 1];
2059     }
2060
2061     if (err == NGX_RESOLVE_TIMEDOUT) {
2062         return "Operation timed out";
2063     }
2064
2065     return "Unknown error";
2066 }
2067
2068
2069 ngx_int_t
2070 ngx_udp_connect(ngx_udp_connection_t *uc)
2071 {
2072     int                rc;
2073     ngx_int_t          event;
2074     ngx_event_t       *rev, *wev;
2075     ngx_socket_t       s;
2076     ngx_connection_t  *c;
2077
2078     s = ngx_socket(AF_INET, SOCK_DGRAM, 0);
2079
2080     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, uc->log, 0, "UDP socket %d", s);
2081
2082     if (s == -1) {
2083         ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
2084                       ngx_socket_n " failed");
2085         return NGX_ERROR;
2086     }
2087
2088     c = ngx_get_connection(s, uc->log);
2089
2090     if (c == NULL) {
2091         if (ngx_close_socket(s) == -1) {
2092             ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
2093                           ngx_close_socket_n "failed");
2094         }
2095
2096         return NGX_ERROR;
2097     }
2098
2099     if (ngx_nonblocking(s) == -1) {
2100         ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
2101                       ngx_nonblocking_n " failed");
2102
2103         ngx_free_connection(c);
2104
2105         if (ngx_close_socket(s) == -1) {
2106             ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
2107                           ngx_close_socket_n " failed");
2108         }
2109
2110         return NGX_ERROR;
2111     }
2112
2113     rev = c->read;
2114     wev = c->write;
2115
2116     rev->log = uc->log;
2117     wev->log = uc->log;
2118
2119     uc->connection = c;
2120
2121     c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
2122
2123 #if (NGX_THREADS)
2124
2125     /* TODO: lock event when call completion handler */
2126
2127     rev->lock = &c->lock;
2128     wev->lock = &c->lock;
2129     rev->own_lock = &c->lock;
2130     wev->own_lock = &c->lock;
2131
2132 #endif
2133
2134     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, uc->log, 0,
2135                    "connect to %V, fd:%d #%d", &uc->server, s, c->number);
2136
2137     rc = connect(s, uc->sockaddr, uc->socklen);
2138
2139     /* TODO: aio, iocp */
2140
2141     if (rc == -1) {
2142         ngx_log_error(NGX_LOG_CRIT, uc->log, ngx_socket_errno,
2143                       "connect() to %V failed", &uc->server);
2144
2145         return NGX_ERROR;
2146     }
2147
2148     /* UDP sockets are always ready to write */
2149     wev->ready = 1;
2150
2151     if (ngx_add_event) {
2152
2153         event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
2154                     /* kqueue, epoll */                 NGX_CLEAR_EVENT:
2155                     /* select, poll, /dev/poll */       NGX_LEVEL_EVENT;
2156                     /* eventport event type has no meaning: oneshot only */
2157
2158         if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
2159             return NGX_ERROR;
2160         }
2161
2162     } else {
2163         /* rtsig */
2164
2165         if (ngx_add_conn(c) == NGX_ERROR) {
2166             return NGX_ERROR;
2167         }
2168     }
2169
2170     return NGX_OK;
2171 }