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

Linux Cross Reference
Nginx/core/ngx_resolver.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  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     ngx_resolver_free(r, name.data);
1153 
1154     if (code == 0 && nan == 0) {
1155         code = 3; /* NXDOMAIN */
1156     }
1157 
1158     if (code) {
1159         next = rn->waiting;
1160         rn->waiting = NULL;
1161 
1162         ngx_queue_remove(&rn->queue);
1163 
1164         ngx_rbtree_delete(&r->name_rbtree, &rn->node);
1165 
1166         ngx_resolver_free_node(r, rn);
1167 
1168         /* unlock name mutex */
1169 
1170         while (next) {
1171              ctx = next;
1172              ctx->state = code;
1173              next = ctx->next;
1174 
1175              ctx->handler(ctx);
1176         }
1177 
1178         return;
1179     }
1180 
1181     i = ans;
1182     naddrs = 0;
1183     addr = 0;
1184     addrs = NULL;
1185     cname = NULL;
1186     qtype = 0;
1187 
1188     for (a = 0; a < nan; a++) {
1189 
1190         start = i;
1191 
1192         while (i < last) {
1193 
1194             if (buf[i] & 0xc0) {
1195                 i += 2;
1196                 goto found;
1197             }
1198 
1199             if (buf[i] == 0) {
1200                 i++;
1201                 goto test_length;
1202             }
1203 
1204             i += 1 + buf[i];
1205         }
1206 
1207         goto short_response;
1208 
1209     test_length:
1210 
1211         if (i - start < 2) {
1212             err = "invalid name in dns response";
1213             goto invalid;
1214         }
1215 
1216     found:
1217 
1218         if (i + sizeof(ngx_resolver_an_t) >= last) {
1219             goto short_response;
1220         }
1221 
1222         an = (ngx_resolver_an_t *) &buf[i];
1223 
1224         qtype = (an->type_hi << 8) + an->type_lo;
1225         len = (an->len_hi << 8) + an->len_lo;
1226 
1227         if (qtype == NGX_RESOLVE_A) {
1228 
1229             i += sizeof(ngx_resolver_an_t);
1230 
1231             if (i + len > last) {
1232                 goto short_response;
1233             }
1234 
1235             addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
1236                          + (buf[i + 2] << 8) + (buf[i + 3]));
1237 
1238             naddrs++;
1239 
1240             i += len;
1241 
1242         } else if (qtype == NGX_RESOLVE_CNAME) {
1243             cname = &buf[i] + sizeof(ngx_resolver_an_t);
1244             i += sizeof(ngx_resolver_an_t) + len;
1245 
1246         } else if (qtype == NGX_RESOLVE_DNAME) {
1247             i += sizeof(ngx_resolver_an_t) + len;
1248 
1249         } else {
1250             ngx_log_error(r->log_level, r->log, 0,
1251                           "unexpected qtype %ui", qtype);
1252         }
1253     }
1254 
1255     ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1256                    "resolver naddrs:%ui cname:%p", naddrs, cname);
1257 
1258     if (naddrs) {
1259 
1260         if (naddrs == 1) {
1261             rn->u.addr = addr;
1262 
1263         } else {
1264 
1265             addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
1266             if (addrs == NULL) {
1267                 return;
1268             }
1269 
1270             n = 0;
1271             i = ans;
1272 
1273             for (a = 0; a < nan; a++) {
1274 
1275                 for ( ;; ) {
1276 
1277                     if (buf[i] & 0xc0) {
1278                         i += 2;
1279                         goto ok;
1280                     }
1281 
1282                     if (buf[i] == 0) {
1283                         i++;
1284                         goto ok;
1285                     }
1286 
1287                     i += 1 + buf[i];
1288                 }
1289 
1290             ok:
1291 
1292                 an = (ngx_resolver_an_t *) &buf[i];
1293 
1294                 qtype = (an->type_hi << 8) + an->type_lo;
1295                 len = (an->len_hi << 8) + an->len_lo;
1296 
1297                 i += sizeof(ngx_resolver_an_t);
1298 
1299                 if (qtype == NGX_RESOLVE_A) {
1300 
1301                     addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
1302                                        + (buf[i + 2] << 8) + (buf[i + 3]));
1303 
1304                     if (n == naddrs) {
1305                         break;
1306                     }
1307                 }
1308 
1309                 i += len;
1310             }
1311 
1312             rn->u.addrs = addrs;
1313 
1314             addrs = ngx_resolver_dup(r, rn->u.addrs,
1315                                      naddrs * sizeof(in_addr_t));
1316             if (addrs == NULL) {
1317                 return;
1318             }
1319         }
1320 
1321         rn->naddrs = (u_short) naddrs;
1322 
1323         ngx_queue_remove(&rn->queue);
1324 
1325         rn->valid = ngx_time() + r->valid;
1326         rn->expire = ngx_time() + r->expire;
1327 
1328         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
1329 
1330         next = rn->waiting;
1331         rn->waiting = NULL;
1332 
1333         /* unlock name mutex */
1334 
1335         while (next) {
1336              ctx = next;
1337              ctx->state = NGX_OK;
1338              ctx->naddrs = naddrs;
1339              ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
1340              ctx->addr = addr;
1341              next = ctx->next;
1342 
1343              ctx->handler(ctx);
1344         }
1345 
1346         if (naddrs > 1) {
1347             ngx_resolver_free(r, addrs);
1348         }
1349 
1350         return;
1351 
1352     } else if (cname) {
1353 
1354         /* CNAME only */
1355 
1356         if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) {
1357             return;
1358         }
1359 
1360         ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
1361                        "resolver cname:\"%V\"", &name);
1362 
1363         ngx_queue_remove(&rn->queue);
1364 
1365         rn->cnlen = (u_short) name.len;
1366         rn->u.cname = name.data;
1367         rn->valid = ngx_time() + r->valid;
1368         rn->expire = ngx_time() + r->expire;
1369 
1370         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
1371 
1372         ctx = rn->waiting;
1373         rn->waiting = NULL;
1374 
1375         if (ctx) {
1376             ctx->name = name;
1377 
1378             (void) ngx_resolve_name_locked(r, ctx);
1379         }
1380 
1381         return;
1382     }
1383 
1384     ngx_log_error(r->log_level, r->log, 0,
1385                "no A or CNAME types in DNS responses, unknown query type: %ui",
1386                qtype);
1387     return;
1388 
1389 short_response:
1390 
1391     err = "short dns response";
1392 
1393 invalid:
1394 
1395     /* unlock name mutex */
1396 
1397     ngx_log_error(r->log_level, r->log, 0, err);
1398 
1399     return;
1400 
1401 failed:
1402 
1403     /* unlock name mutex */
1404 
1405     ngx_resolver_free(r, name.data);
1406 
1407     return;
1408 }
1409 
1410 
1411 static void
1412 ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
1413     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
1414 {
1415     char                 *err;
1416     size_t                len;
1417     in_addr_t             addr;
1418     ngx_int_t             digit;
1419     ngx_str_t             name;
1420     ngx_uint_t            i, mask, qtype, qclass, qident;
1421     ngx_resolver_an_t    *an;
1422     ngx_resolver_ctx_t   *ctx, *next;
1423     ngx_resolver_node_t  *rn;
1424 
1425     if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) {
1426         goto invalid_in_addr_arpa;
1427     }
1428 
1429     addr = 0;
1430     i = 12;
1431 
1432     for (mask = 0; mask < 32; mask += 8) {
1433         len = buf[i++];
1434 
1435         digit = ngx_atoi(&buf[i], len);
1436         if (digit == NGX_ERROR || digit > 255) {
1437             goto invalid_in_addr_arpa;
1438         }
1439 
1440         addr += digit << mask;
1441         i += len;
1442     }
1443 
1444     if (ngx_strcmp(&buf[i], "\7in-addr\4arpa") != 0) {
1445         goto invalid_in_addr_arpa;
1446     }
1447 
1448     /* lock addr mutex */
1449 
1450     rn = ngx_resolver_lookup_addr(r, addr);
1451 
1452     if (rn == NULL || rn->query == NULL) {
1453         ngx_log_error(r->log_level, r->log, 0,
1454                       "unexpected response for %ud.%ud.%ud.%ud",
1455                       (addr >> 24) & 0xff, (addr >> 16) & 0xff,
1456                       (addr >> 8) & 0xff, addr & 0xff);
1457         goto failed;
1458     }
1459 
1460     qident = (rn->query[0] << 8) + rn->query[1];
1461 
1462     if (ident != qident) {
1463         ngx_log_error(r->log_level, r->log, 0,
1464                     "wrong ident %ui response for %ud.%ud.%ud.%ud, expect %ui",
1465                     ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff,
1466                     (addr >> 8) & 0xff, addr & 0xff, qident);
1467         goto failed;
1468     }
1469 
1470     if (code == 0 && nan == 0) {
1471         code = 3; /* NXDOMAIN */
1472     }
1473 
1474     if (code) {
1475         next = rn->waiting;
1476         rn->waiting = NULL;
1477 
1478         ngx_queue_remove(&rn->queue);
1479 
1480         ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
1481 
1482         ngx_resolver_free_node(r, rn);
1483 
1484         /* unlock addr mutex */
1485 
1486         while (next) {
1487              ctx = next;
1488              ctx->state = code;
1489              next = ctx->next;
1490 
1491              ctx->handler(ctx);
1492         }
1493 
1494         return;
1495     }
1496 
1497     i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);
1498 
1499     if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) {
1500         goto short_response;
1501     }
1502 
1503     /* compression pointer to "XX.XX.XX.XX.in-addr.arpa */
1504 
1505     if (buf[i] != 0xc0 || buf[i + 1] != 0x0c) {
1506         err = "invalid in-addr.arpa name in DNS response";
1507         goto invalid;
1508     }
1509 
1510     an = (ngx_resolver_an_t *) &buf[i + 2];
1511 
1512     qtype = (an->type_hi << 8) + an->type_lo;
1513     qclass = (an->class_hi << 8) + an->class_lo;
1514     len = (an->len_hi << 8) + an->len_lo;
1515 
1516     ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
1517                   "resolver qt:%ui cl:%ui len:%uz", qtype, qclass, len);
1518 
1519     i += 2 + sizeof(ngx_resolver_an_t);
1520 
1521     if (i + len > (ngx_uint_t) n) {
1522         goto short_response;
1523     }
1524 
1525     if (ngx_resolver_copy(r, &name, buf, &buf[i], &buf[n]) != NGX_OK) {
1526         return;
1527     }
1528 
1529     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
1530 
1531     if (name.len != (size_t) rn->nlen
1532         || ngx_strncmp(name.data, rn->name, name.len) != 0)
1533     {
1534         if (rn->nlen) {
1535             ngx_resolver_free(r, rn->name);
1536         }
1537 
1538         rn->nlen = (u_short) name.len;
1539         rn->name = name.data;
1540 
1541         name.data = ngx_resolver_dup(r, rn->name, name.len);
1542         if (name.data == NULL) {
1543             goto failed;
1544         }
1545     }
1546 
1547     ngx_queue_remove(&rn->queue);
1548 
1549     rn->valid = ngx_time() + r->valid;
1550     rn->expire = ngx_time() + r->expire;
1551 
1552     ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
1553 
1554     next = rn->waiting;
1555     rn->waiting = NULL;
1556 
1557     /* unlock addr mutex */
1558 
1559     while (next) {
1560          ctx = next;
1561          ctx->state = NGX_OK;
1562          ctx->name = name;
1563          next = ctx->next;
1564 
1565          ctx->handler(ctx);
1566     }
1567 
1568     ngx_resolver_free(r, name.data);
1569 
1570     return;
1571 
1572 invalid_in_addr_arpa:
1573 
1574     ngx_log_error(r->log_level, r->log, 0,
1575                   "invalid in-addr.arpa name in DNS response");
1576     return;
1577 
1578 short_response:
1579 
1580     err = "short DNS response";
1581 
1582 invalid:
1583 
1584     /* unlock addr mutex */
1585 
1586     ngx_log_error(r->log_level, r->log, 0, err);
1587 
1588     return;
1589 
1590 failed:
1591 
1592     /* unlock addr mutex */
1593 
1594     return;
1595 }
1596 
1597 
1598 static ngx_resolver_node_t *
1599 ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
1600 {
1601     ngx_int_t             rc;
1602     ngx_rbtree_node_t    *node, *sentinel;
1603     ngx_resolver_node_t  *rn;
1604 
1605     node = r->name_rbtree.root;
1606     sentinel = r->name_rbtree.sentinel;
1607 
1608     while (node != sentinel) {
1609 
1610         if (hash < node->key) {
1611             node = node->left;
1612             continue;
1613         }
1614 
1615         if (hash > node->key) {
1616             node = node->right;
1617             continue;
1618         }
1619 
1620         /* hash == node->key */
1621 
1622         do {
1623             rn = (ngx_resolver_node_t *) node;
1624 
1625             rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
1626 
1627             if (rc == 0) {
1628                 return rn;
1629             }
1630 
1631             node = (rc < 0) ? node->left : node->right;
1632 
1633         } while (node != sentinel && hash == node->key);
1634 
1635         break;
1636     }
1637 
1638     /* not found */
1639 
1640     return NULL;
1641 }
1642 
1643 
1644 static ngx_resolver_node_t *
1645 ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
1646 {
1647     ngx_rbtree_node_t  *node, *sentinel;
1648 
1649     node = r->addr_rbtree.root;
1650     sentinel = r->addr_rbtree.sentinel;
1651 
1652     while (node != sentinel) {
1653 
1654         if (addr < node->key) {
1655             node = node->left;
1656             continue;
1657         }
1658 
1659         if (addr > node->key) {
1660             node = node->right;
1661             continue;
1662         }
1663 
1664         /* addr == node->key */
1665 
1666         return (ngx_resolver_node_t *) node;
1667     }
1668 
1669     /* not found */
1670 
1671     return NULL;
1672 }
1673 
1674 
1675 static void
1676 ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
1677     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
1678 {
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             p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)
1698                  < 0) ? &temp->left : &temp->right;
1699         }
1700 
1701         if (*p == sentinel) {
1702             break;
1703         }
1704 
1705         temp = *p;
1706     }
1707 
1708     *p = node;
1709     node->parent = temp;
1710     node->left = sentinel;
1711     node->right = sentinel;
1712     ngx_rbt_red(node);
1713 }
1714 
1715 
1716 static ngx_int_t
1717 ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
1718 {
1719     u_char                *p, *s;
1720     size_t                 len;
1721     ngx_uint_t             ident;
1722     ngx_resolver_qs_t     *qs;
1723     ngx_resolver_query_t  *query;
1724 
1725     len = sizeof(ngx_resolver_query_t)
1726           + 1 + ctx->name.len + 1 + sizeof(ngx_resolver_qs_t);
1727 
1728     p = ngx_resolver_calloc(ctx->resolver, len);
1729     if (p == NULL) {
1730         return NGX_ERROR;
1731     }
1732 
1733     rn->qlen = (u_short) len;
1734     rn->query = p;
1735 
1736     query = (ngx_resolver_query_t *) p;
1737 
1738     ident = ngx_random();
1739 
1740     ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
1741                    "resolve: \"%V\" %i", &ctx->name, ident & 0xffff);
1742 
1743     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
1744     query->ident_lo = (u_char) (ident & 0xff);
1745 
1746     /* recursion query */
1747     query->flags_hi = 1; query->flags_lo = 0;
1748 
1749     /* one question */
1750     query->nqs_hi = 0; query->nqs_lo = 1;
1751     query->nan_hi = 0; query->nan_lo = 0;
1752     query->nns_hi = 0; query->nns_lo = 0;
1753     query->nar_hi = 0; query->nar_lo = 0;
1754 
1755     p += sizeof(ngx_resolver_query_t) + 1 + ctx->name.len + 1;
1756 
1757     qs = (ngx_resolver_qs_t *) p;
1758 
1759     /* query type */
1760     qs->type_hi = 0; qs->type_lo = (u_char) ctx->type;
1761 
1762     /* IP query class */
1763     qs->class_hi = 0; qs->class_lo = 1;
1764 
1765     /* convert "www.example.com" to "\3www\7example\3com\0" */
1766 
1767     len = 0;
1768     p--;
1769     *p-- = '\0';
1770 
1771     for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) {
1772         if (*s != '.') {
1773             *p = *s;
1774             len++;
1775 
1776         } else {
1777             if (len == 0) {
1778                 return NGX_DECLINED;
1779             }
1780 
1781             *p = (u_char) len;
1782             len = 0;
1783         }
1784 
1785         p--;
1786     }
1787 
1788     *p = (u_char) len;
1789 
1790     return NGX_OK;
1791 }
1792 
1793 
1794 /* AF_INET only */
1795 
1796 static ngx_int_t
1797 ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
1798 {
1799     u_char                *p, *d;
1800     size_t                 len;
1801     ngx_int_t              n;
1802     ngx_uint_t             ident;
1803     ngx_resolver_query_t  *query;
1804 
1805     len = sizeof(ngx_resolver_query_t)
1806           + sizeof(".255.255.255.255.in-addr.arpa.") - 1
1807           + sizeof(ngx_resolver_qs_t);
1808 
1809     p = ngx_resolver_calloc(ctx->resolver, len);
1810     if (p == NULL) {
1811         return NGX_ERROR;
1812     }
1813 
1814     rn->query = p;
1815     query = (ngx_resolver_query_t *) p;
1816 
1817     ident = ngx_random();
1818 
1819     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
1820     query->ident_lo = (u_char) (ident & 0xff);
1821 
1822     /* recursion query */
1823     query->flags_hi = 1; query->flags_lo = 0;
1824 
1825     /* one question */
1826     query->nqs_hi = 0; query->nqs_lo = 1;
1827     query->nan_hi = 0; query->nan_lo = 0;
1828     query->nns_hi = 0; query->nns_lo = 0;
1829     query->nar_hi = 0; query->nar_lo = 0;
1830 
1831     p += sizeof(ngx_resolver_query_t);
1832 
1833     for (n = 0; n < 32; n += 8){
1834         d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff);
1835         *p = (u_char) (d - &p[1]);
1836         p = d;
1837     }
1838 
1839     /* query type "PTR", IP query class */
1840     ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);
1841 
1842     rn->qlen = (u_short)
1843                   (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t)
1844                    - rn->query);
1845 
1846     return NGX_OK;
1847 }
1848 
1849 
1850 static ngx_int_t
1851 ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src,
1852     u_char *last)
1853 {
1854     char        *err;
1855     u_char      *p, *dst;
1856     ssize_t      len;
1857     ngx_uint_t   i, n;
1858 
1859     p = src;
1860     len = -1;
1861 
1862     /*
1863      * compression pointers allow to create endless loop, so we set limit;
1864      * 128 pointers should be enough to store 255-byte name
1865      */
1866 
1867     for (i = 0; i < 128; i++) {
1868         n = *p++;
1869 
1870         if (n == 0) {
1871             goto done;
1872         }
1873 
1874         if (n & 0xc0) {
1875             n = ((n & 0x3f) << 8) + *p;
1876             p = &buf[n];
1877 
1878         } else {
1879             len += 1 + n;
1880             p = &p[n];
1881         }
1882 
1883         if (p >= last) {
1884             err = "name is out of response";
1885             goto invalid;
1886         }
1887     }
1888 
1889     err = "compression pointers loop";
1890 
1891 invalid:
1892 
1893     ngx_log_error(r->log_level, r->log, 0, err);
1894 
1895     return NGX_ERROR;
1896 
1897 done:
1898 
1899     if (name == NULL) {
1900         return NGX_OK;
1901     }
1902 
1903     dst = ngx_resolver_alloc(r, len);
1904     if (dst == NULL) {
1905         return NGX_ERROR;
1906     }
1907 
1908     name->data = dst;
1909 
1910     n = *src++;
1911 
1912     for ( ;; ) {
1913         if (n != 0xc0) {
1914             ngx_memcpy(dst, src, n);
1915             dst += n;
1916             src += n;
1917 
1918             n = *src++;
1919 
1920             if (n != 0) {
1921                 *dst++ = '.';
1922             }
1923 
1924         } else {
1925             n = ((n & 0x3f) << 8) + *src;
1926             src = &buf[n];
1927 
1928             n = *src++;
1929         }
1930 
1931         if (n == 0) {
1932             name->len = dst - name->data;
1933             return NGX_OK;
1934         }
1935     }
1936 }
1937 
1938 
1939 static void
1940 ngx_resolver_timeout_handler(ngx_event_t *ev)
1941 {
1942     ngx_resolver_ctx_t  *ctx;
1943 
1944     ctx = ev->data;
1945 
1946     ctx->state = NGX_RESOLVE_TIMEDOUT;
1947 
1948     ctx->handler(ctx);
1949 }
1950 
1951 
1952 static void
1953 ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
1954 {
1955     /* lock alloc mutex */
1956 
1957     if (rn->query) {
1958         ngx_resolver_free_locked(r, rn->query);
1959     }
1960 
1961     if (rn->name) {
1962         ngx_resolver_free_locked(r, rn->name);
1963     }
1964 
1965     if (rn->cnlen) {
1966         ngx_resolver_free_locked(r, rn->u.cname);
1967     }
1968 
1969     if (rn->naddrs > 1) {
1970         ngx_resolver_free_locked(r, rn->u.addrs);
1971     }
1972 
1973     ngx_resolver_free_locked(r, rn);
1974 
1975     /* unlock alloc mutex */
1976 }
1977 
1978 
1979 static void *
1980 ngx_resolver_alloc(ngx_resolver_t *r, size_t size)
1981 {
1982     u_char  *p;
1983 
1984     /* lock alloc mutex */
1985 
1986     p = ngx_alloc(size, r->log);
1987 
1988     /* unlock alloc mutex */
1989 
1990     return p;
1991 }
1992 
1993 
1994 static void *
1995 ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
1996 {
1997     u_char  *p;
1998 
1999     p = ngx_resolver_alloc(r, size);
2000 
2001     if (p) {
2002         ngx_memzero(p, size);
2003     }
2004 
2005     return p;
2006 }
2007 
2008 
2009 static void
2010 ngx_resolver_free(ngx_resolver_t *r, void *p)
2011 {
2012     /* lock alloc mutex */
2013 
2014     ngx_free(p);
2015 
2016     /* unlock alloc mutex */
2017 }
2018 
2019 
2020 static void
2021 ngx_resolver_free_locked(ngx_resolver_t *r, void *p)
2022 {
2023     ngx_free(p);
2024 }
2025 
2026 
2027 static void *
2028 ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
2029 {
2030     void  *dst;
2031 
2032     dst = ngx_resolver_alloc(r, size);
2033 
2034     if (dst == NULL) {
2035         return dst;
2036     }
2037 
2038     ngx_memcpy(dst, src, size);
2039 
2040     return dst;
2041 }
2042 
2043 
2044 char *
2045 ngx_resolver_strerror(ngx_int_t err)
2046 {
2047     static char *errors[] = {
2048         "Format error",     /* FORMERR */
2049         "Server failure",   /* SERVFAIL */
2050         "Host not found",   /* NXDOMAIN */
2051         "Unimplemented",    /* NOTIMP */
2052         "Operation refused" /* REFUSED */
2053     };
2054 
2055     if (err > 0 && err < 6) {
2056         return errors[err - 1];
2057     }
2058 
2059     if (err == NGX_RESOLVE_TIMEDOUT) {
2060         return "Operation timed out";
2061     }
2062 
2063     return "Unknown error";
2064 }
2065 
2066 
2067 ngx_int_t
2068 ngx_udp_connect(ngx_udp_connection_t *uc)
2069 {
2070     int                rc;
2071     ngx_int_t          event;
2072     ngx_event_t       *rev, *wev;
2073     ngx_socket_t       s;
2074     ngx_connection_t  *c;
2075 
2076     s = ngx_socket(AF_INET, SOCK_DGRAM, 0);
2077 
2078     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, uc->log, 0, "UDP socket %d", s);
2079 
2080     if (s == -1) {
2081         ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
2082                       ngx_socket_n " failed");
2083         return NGX_ERROR;
2084     }
2085 
2086     c = ngx_get_connection(s, uc->log);
2087 
2088     if (c == NULL) {
2089         if (ngx_close_socket(s) == -1) {
2090             ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
2091                           ngx_close_socket_n "failed");
2092         }
2093 
2094         return NGX_ERROR;
2095     }
2096 
2097     if (ngx_nonblocking(s) == -1) {
2098         ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
2099                       ngx_nonblocking_n " failed");
2100 
2101         ngx_free_connection(c);
2102 
2103         if (ngx_close_socket(s) == -1) {
2104             ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
2105                           ngx_close_socket_n " failed");
2106         }
2107 
2108         return NGX_ERROR;
2109     }
2110 
2111     rev = c->read;
2112     wev = c->write;
2113 
2114     rev->log = uc->log;
2115     wev->log = uc->log;
2116 
2117     uc->connection = c;
2118 
2119     c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
2120 
2121 #if (NGX_THREADS)
2122 
2123     /* TODO: lock event when call completion handler */
2124 
2125     rev->lock = &c->lock;
2126     wev->lock = &c->lock;
2127     rev->own_lock = &c->lock;
2128     wev->own_lock = &c->lock;
2129 
2130 #endif
2131 
2132     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, uc->log, 0,
2133                    "connect to %V, fd:%d #%d", &uc->server, s, c->number);
2134 
2135     rc = connect(s, uc->sockaddr, uc->socklen);
2136 
2137     /* TODO: aio, iocp */
2138 
2139     if (rc == -1) {
2140         ngx_log_error(NGX_LOG_CRIT, uc->log, ngx_socket_errno,
2141                       "connect() to %V failed", &uc->server);
2142 
2143         return NGX_ERROR;
2144     }
2145 
2146     /* UDP sockets are always ready to write */
2147     wev->ready = 1;
2148 
2149     if (ngx_add_event) {
2150 
2151         event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
2152                     /* kqueue, epoll */                 NGX_CLEAR_EVENT:
2153                     /* select, poll, /dev/poll */       NGX_LEVEL_EVENT;
2154                     /* eventport event type has no meaning: oneshot only */
2155 
2156         if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
2157             return NGX_ERROR;
2158         }
2159 
2160     } else {
2161         /* rtsig */
2162 
2163         if (ngx_add_conn(c) == NGX_ERROR) {
2164             return NGX_ERROR;
2165         }
2166     }
2167 
2168     return NGX_OK;
2169 }
2170 

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

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.