Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 
0012 
0013 #define NGX_RESOLVER_UDP_SIZE   4096
0014 
0015 #define NGX_RESOLVER_TCP_RSIZE  (2 + 65535)
0016 #define NGX_RESOLVER_TCP_WSIZE  8192
0017 
0018 
0019 typedef struct {
0020     u_char  ident_hi;
0021     u_char  ident_lo;
0022     u_char  flags_hi;
0023     u_char  flags_lo;
0024     u_char  nqs_hi;
0025     u_char  nqs_lo;
0026     u_char  nan_hi;
0027     u_char  nan_lo;
0028     u_char  nns_hi;
0029     u_char  nns_lo;
0030     u_char  nar_hi;
0031     u_char  nar_lo;
0032 } ngx_resolver_hdr_t;
0033 
0034 
0035 typedef struct {
0036     u_char  type_hi;
0037     u_char  type_lo;
0038     u_char  class_hi;
0039     u_char  class_lo;
0040 } ngx_resolver_qs_t;
0041 
0042 
0043 typedef struct {
0044     u_char  type_hi;
0045     u_char  type_lo;
0046     u_char  class_hi;
0047     u_char  class_lo;
0048     u_char  ttl[4];
0049     u_char  len_hi;
0050     u_char  len_lo;
0051 } ngx_resolver_an_t;
0052 
0053 
0054 #define ngx_resolver_node(n)                                                 \
0055     (ngx_resolver_node_t *)                                                  \
0056         ((u_char *) (n) - offsetof(ngx_resolver_node_t, node))
0057 
0058 
0059 static ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec);
0060 static ngx_int_t ngx_tcp_connect(ngx_resolver_connection_t *rec);
0061 
0062 
0063 static void ngx_resolver_cleanup(void *data);
0064 static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
0065 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
0066     ngx_resolver_ctx_t *ctx, ngx_str_t *name);
0067 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
0068     ngx_queue_t *queue);
0069 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
0070     ngx_resolver_node_t *rn);
0071 static ngx_int_t ngx_resolver_send_udp_query(ngx_resolver_t *r,
0072     ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
0073 static ngx_int_t ngx_resolver_send_tcp_query(ngx_resolver_t *r,
0074     ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
0075 static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r,
0076     ngx_resolver_node_t *rn, ngx_str_t *name);
0077 static ngx_int_t ngx_resolver_create_srv_query(ngx_resolver_t *r,
0078     ngx_resolver_node_t *rn, ngx_str_t *name);
0079 static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r,
0080     ngx_resolver_node_t *rn, ngx_resolver_addr_t *addr);
0081 static void ngx_resolver_resend_handler(ngx_event_t *ev);
0082 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
0083     ngx_queue_t *queue);
0084 static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r);
0085 static void ngx_resolver_udp_read(ngx_event_t *rev);
0086 static void ngx_resolver_tcp_write(ngx_event_t *wev);
0087 static void ngx_resolver_tcp_read(ngx_event_t *rev);
0088 static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
0089     size_t n, ngx_uint_t tcp);
0090 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
0091     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
0092     ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans);
0093 static void ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n,
0094     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan,
0095     ngx_uint_t trunc, ngx_uint_t ans);
0096 static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
0097     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
0098 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
0099     ngx_str_t *name, uint32_t hash);
0100 static ngx_resolver_node_t *ngx_resolver_lookup_srv(ngx_resolver_t *r,
0101     ngx_str_t *name, uint32_t hash);
0102 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
0103     in_addr_t addr);
0104 static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
0105     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
0106 static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
0107     u_char *buf, u_char *src, u_char *last);
0108 static ngx_int_t ngx_resolver_set_timeout(ngx_resolver_t *r,
0109     ngx_resolver_ctx_t *ctx);
0110 static void ngx_resolver_timeout_handler(ngx_event_t *ev);
0111 static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
0112 static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
0113 static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
0114 static void ngx_resolver_free(ngx_resolver_t *r, void *p);
0115 static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
0116 static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
0117 static ngx_resolver_addr_t *ngx_resolver_export(ngx_resolver_t *r,
0118     ngx_resolver_node_t *rn, ngx_uint_t rotate);
0119 static void ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx);
0120 static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
0121 static void ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx,
0122     ngx_resolver_node_t *rn);
0123 static void ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *ctx);
0124 static ngx_int_t ngx_resolver_cmp_srvs(const void *one, const void *two);
0125 
0126 #if (NGX_HAVE_INET6)
0127 static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
0128     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
0129 static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r,
0130     struct in6_addr *addr, uint32_t hash);
0131 #endif
0132 
0133 
0134 ngx_resolver_t *
0135 ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
0136 {
0137     ngx_str_t                   s;
0138     ngx_url_t                   u;
0139     ngx_uint_t                  i, j;
0140     ngx_resolver_t             *r;
0141     ngx_pool_cleanup_t         *cln;
0142     ngx_resolver_connection_t  *rec;
0143 
0144     cln = ngx_pool_cleanup_add(cf->pool, 0);
0145     if (cln == NULL) {
0146         return NULL;
0147     }
0148 
0149     cln->handler = ngx_resolver_cleanup;
0150 
0151     r = ngx_calloc(sizeof(ngx_resolver_t), cf->log);
0152     if (r == NULL) {
0153         return NULL;
0154     }
0155 
0156     cln->data = r;
0157 
0158     r->event = ngx_calloc(sizeof(ngx_event_t), cf->log);
0159     if (r->event == NULL) {
0160         return NULL;
0161     }
0162 
0163     ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel,
0164                     ngx_resolver_rbtree_insert_value);
0165 
0166     ngx_rbtree_init(&r->srv_rbtree, &r->srv_sentinel,
0167                     ngx_resolver_rbtree_insert_value);
0168 
0169     ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
0170                     ngx_rbtree_insert_value);
0171 
0172     ngx_queue_init(&r->name_resend_queue);
0173     ngx_queue_init(&r->srv_resend_queue);
0174     ngx_queue_init(&r->addr_resend_queue);
0175 
0176     ngx_queue_init(&r->name_expire_queue);
0177     ngx_queue_init(&r->srv_expire_queue);
0178     ngx_queue_init(&r->addr_expire_queue);
0179 
0180 #if (NGX_HAVE_INET6)
0181     r->ipv6 = 1;
0182 
0183     ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel,
0184                     ngx_resolver_rbtree_insert_addr6_value);
0185 
0186     ngx_queue_init(&r->addr6_resend_queue);
0187 
0188     ngx_queue_init(&r->addr6_expire_queue);
0189 #endif
0190 
0191     r->event->handler = ngx_resolver_resend_handler;
0192     r->event->data = r;
0193     r->event->log = &cf->cycle->new_log;
0194     r->event->cancelable = 1;
0195     r->ident = -1;
0196 
0197     r->resend_timeout = 5;
0198     r->tcp_timeout = 5;
0199     r->expire = 30;
0200     r->valid = 0;
0201 
0202     r->log = &cf->cycle->new_log;
0203     r->log_level = NGX_LOG_ERR;
0204 
0205     if (n) {
0206         if (ngx_array_init(&r->connections, cf->pool, n,
0207                            sizeof(ngx_resolver_connection_t))
0208             != NGX_OK)
0209         {
0210             return NULL;
0211         }
0212     }
0213 
0214     for (i = 0; i < n; i++) {
0215         if (ngx_strncmp(names[i].data, "valid=", 6) == 0) {
0216             s.len = names[i].len - 6;
0217             s.data = names[i].data + 6;
0218 
0219             r->valid = ngx_parse_time(&s, 1);
0220 
0221             if (r->valid == (time_t) NGX_ERROR) {
0222                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0223                                    "invalid parameter: %V", &names[i]);
0224                 return NULL;
0225             }
0226 
0227             continue;
0228         }
0229 
0230 #if (NGX_HAVE_INET6)
0231         if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) {
0232 
0233             if (ngx_strcmp(&names[i].data[5], "on") == 0) {
0234                 r->ipv6 = 1;
0235 
0236             } else if (ngx_strcmp(&names[i].data[5], "off") == 0) {
0237                 r->ipv6 = 0;
0238 
0239             } else {
0240                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0241                                    "invalid parameter: %V", &names[i]);
0242                 return NULL;
0243             }
0244 
0245             continue;
0246         }
0247 #endif
0248 
0249         ngx_memzero(&u, sizeof(ngx_url_t));
0250 
0251         u.url = names[i];
0252         u.default_port = 53;
0253 
0254         if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
0255             if (u.err) {
0256                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0257                                    "%s in resolver \"%V\"",
0258                                    u.err, &u.url);
0259             }
0260 
0261             return NULL;
0262         }
0263 
0264         rec = ngx_array_push_n(&r->connections, u.naddrs);
0265         if (rec == NULL) {
0266             return NULL;
0267         }
0268 
0269         ngx_memzero(rec, u.naddrs * sizeof(ngx_resolver_connection_t));
0270 
0271         for (j = 0; j < u.naddrs; j++) {
0272             rec[j].sockaddr = u.addrs[j].sockaddr;
0273             rec[j].socklen = u.addrs[j].socklen;
0274             rec[j].server = u.addrs[j].name;
0275             rec[j].resolver = r;
0276         }
0277     }
0278 
0279     return r;
0280 }
0281 
0282 
0283 static void
0284 ngx_resolver_cleanup(void *data)
0285 {
0286     ngx_resolver_t  *r = data;
0287 
0288     ngx_uint_t                  i;
0289     ngx_resolver_connection_t  *rec;
0290 
0291     if (r) {
0292         ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
0293                        "cleanup resolver");
0294 
0295         ngx_resolver_cleanup_tree(r, &r->name_rbtree);
0296 
0297         ngx_resolver_cleanup_tree(r, &r->srv_rbtree);
0298 
0299         ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
0300 
0301 #if (NGX_HAVE_INET6)
0302         ngx_resolver_cleanup_tree(r, &r->addr6_rbtree);
0303 #endif
0304 
0305         if (r->event) {
0306             if (r->event->timer_set) {
0307                 ngx_del_timer(r->event);
0308             }
0309 
0310             ngx_free(r->event);
0311         }
0312 
0313 
0314         rec = r->connections.elts;
0315 
0316         for (i = 0; i < r->connections.nelts; i++) {
0317             if (rec[i].udp) {
0318                 ngx_close_connection(rec[i].udp);
0319             }
0320 
0321             if (rec[i].tcp) {
0322                 ngx_close_connection(rec[i].tcp);
0323             }
0324 
0325             if (rec[i].read_buf) {
0326                 ngx_resolver_free(r, rec[i].read_buf->start);
0327                 ngx_resolver_free(r, rec[i].read_buf);
0328             }
0329 
0330             if (rec[i].write_buf) {
0331                 ngx_resolver_free(r, rec[i].write_buf->start);
0332                 ngx_resolver_free(r, rec[i].write_buf);
0333             }
0334         }
0335 
0336         ngx_free(r);
0337     }
0338 }
0339 
0340 
0341 static void
0342 ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree)
0343 {
0344     ngx_resolver_ctx_t   *ctx, *next;
0345     ngx_resolver_node_t  *rn;
0346 
0347     while (tree->root != tree->sentinel) {
0348 
0349         rn = ngx_resolver_node(ngx_rbtree_min(tree->root, tree->sentinel));
0350 
0351         ngx_queue_remove(&rn->queue);
0352 
0353         for (ctx = rn->waiting; ctx; ctx = next) {
0354             next = ctx->next;
0355 
0356             if (ctx->event) {
0357                 if (ctx->event->timer_set) {
0358                     ngx_del_timer(ctx->event);
0359                 }
0360 
0361                 ngx_resolver_free(r, ctx->event);
0362             }
0363 
0364             ngx_resolver_free(r, ctx);
0365         }
0366 
0367         ngx_rbtree_delete(tree, &rn->node);
0368 
0369         ngx_resolver_free_node(r, rn);
0370     }
0371 }
0372 
0373 
0374 ngx_resolver_ctx_t *
0375 ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
0376 {
0377     in_addr_t            addr;
0378     ngx_resolver_ctx_t  *ctx;
0379 
0380     if (temp) {
0381         addr = ngx_inet_addr(temp->name.data, temp->name.len);
0382 
0383         if (addr != INADDR_NONE) {
0384             temp->resolver = r;
0385             temp->state = NGX_OK;
0386             temp->naddrs = 1;
0387             temp->addrs = &temp->addr;
0388             temp->addr.sockaddr = (struct sockaddr *) &temp->sin;
0389             temp->addr.socklen = sizeof(struct sockaddr_in);
0390             ngx_memzero(&temp->sin, sizeof(struct sockaddr_in));
0391             temp->sin.sin_family = AF_INET;
0392             temp->sin.sin_addr.s_addr = addr;
0393             temp->quick = 1;
0394 
0395             return temp;
0396         }
0397     }
0398 
0399     if (r->connections.nelts == 0) {
0400         return NGX_NO_RESOLVER;
0401     }
0402 
0403     ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t));
0404 
0405     if (ctx) {
0406         ctx->resolver = r;
0407     }
0408 
0409     return ctx;
0410 }
0411 
0412 
0413 ngx_int_t
0414 ngx_resolve_name(ngx_resolver_ctx_t *ctx)
0415 {
0416     size_t           slen;
0417     ngx_int_t        rc;
0418     ngx_str_t        name;
0419     ngx_resolver_t  *r;
0420 
0421     r = ctx->resolver;
0422 
0423     if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') {
0424         ctx->name.len--;
0425     }
0426 
0427     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
0428                    "resolve: \"%V\"", &ctx->name);
0429 
0430     if (ctx->quick) {
0431         ctx->handler(ctx);
0432         return NGX_OK;
0433     }
0434 
0435     if (ctx->service.len) {
0436         slen = ctx->service.len;
0437 
0438         if (ngx_strlchr(ctx->service.data,
0439                         ctx->service.data + ctx->service.len, '.')
0440             == NULL)
0441         {
0442             slen += sizeof("_._tcp") - 1;
0443         }
0444 
0445         name.len = slen + 1 + ctx->name.len;
0446 
0447         name.data = ngx_resolver_alloc(r, name.len);
0448         if (name.data == NULL) {
0449             goto failed;
0450         }
0451 
0452         if (slen == ctx->service.len) {
0453             ngx_sprintf(name.data, "%V.%V", &ctx->service, &ctx->name);
0454 
0455         } else {
0456             ngx_sprintf(name.data, "_%V._tcp.%V", &ctx->service, &ctx->name);
0457         }
0458 
0459         /* lock name mutex */
0460 
0461         rc = ngx_resolve_name_locked(r, ctx, &name);
0462 
0463         ngx_resolver_free(r, name.data);
0464 
0465     } else {
0466         /* lock name mutex */
0467 
0468         rc = ngx_resolve_name_locked(r, ctx, &ctx->name);
0469     }
0470 
0471     if (rc == NGX_OK) {
0472         return NGX_OK;
0473     }
0474 
0475     /* unlock name mutex */
0476 
0477     if (rc == NGX_AGAIN) {
0478         return NGX_OK;
0479     }
0480 
0481     /* NGX_ERROR */
0482 
0483     if (ctx->event) {
0484         ngx_resolver_free(r, ctx->event);
0485     }
0486 
0487 failed:
0488 
0489     ngx_resolver_free(r, ctx);
0490 
0491     return NGX_ERROR;
0492 }
0493 
0494 
0495 void
0496 ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
0497 {
0498     ngx_uint_t            i;
0499     ngx_resolver_t       *r;
0500     ngx_resolver_ctx_t   *w, **p;
0501     ngx_resolver_node_t  *rn;
0502 
0503     r = ctx->resolver;
0504 
0505     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
0506                    "resolve name done: %i", ctx->state);
0507 
0508     if (ctx->quick) {
0509         return;
0510     }
0511 
0512     if (ctx->event && ctx->event->timer_set) {
0513         ngx_del_timer(ctx->event);
0514     }
0515 
0516     /* lock name mutex */
0517 
0518     if (ctx->nsrvs) {
0519         for (i = 0; i < ctx->nsrvs; i++) {
0520             if (ctx->srvs[i].ctx) {
0521                 ngx_resolve_name_done(ctx->srvs[i].ctx);
0522             }
0523 
0524             if (ctx->srvs[i].addrs) {
0525                 ngx_resolver_free(r, ctx->srvs[i].addrs->sockaddr);
0526                 ngx_resolver_free(r, ctx->srvs[i].addrs);
0527             }
0528 
0529             ngx_resolver_free(r, ctx->srvs[i].name.data);
0530         }
0531 
0532         ngx_resolver_free(r, ctx->srvs);
0533     }
0534 
0535     if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
0536 
0537         rn = ctx->node;
0538 
0539         if (rn) {
0540             p = &rn->waiting;
0541             w = rn->waiting;
0542 
0543             while (w) {
0544                 if (w == ctx) {
0545                     *p = w->next;
0546 
0547                     goto done;
0548                 }
0549 
0550                 p = &w->next;
0551                 w = w->next;
0552             }
0553 
0554             ngx_log_error(NGX_LOG_ALERT, r->log, 0,
0555                           "could not cancel %V resolving", &ctx->name);
0556         }
0557     }
0558 
0559 done:
0560 
0561     if (ctx->service.len) {
0562         ngx_resolver_expire(r, &r->srv_rbtree, &r->srv_expire_queue);
0563 
0564     } else {
0565         ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue);
0566     }
0567 
0568     /* unlock name mutex */
0569 
0570     /* lock alloc mutex */
0571 
0572     if (ctx->event) {
0573         ngx_resolver_free_locked(r, ctx->event);
0574     }
0575 
0576     ngx_resolver_free_locked(r, ctx);
0577 
0578     /* unlock alloc mutex */
0579 
0580     if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
0581         ngx_del_timer(r->event);
0582     }
0583 }
0584 
0585 
0586 static ngx_int_t
0587 ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx,
0588     ngx_str_t *name)
0589 {
0590     uint32_t              hash;
0591     ngx_int_t             rc;
0592     ngx_str_t             cname;
0593     ngx_uint_t            i, naddrs;
0594     ngx_queue_t          *resend_queue, *expire_queue;
0595     ngx_rbtree_t         *tree;
0596     ngx_resolver_ctx_t   *next, *last;
0597     ngx_resolver_addr_t  *addrs;
0598     ngx_resolver_node_t  *rn;
0599 
0600     ngx_strlow(name->data, name->data, name->len);
0601 
0602     hash = ngx_crc32_short(name->data, name->len);
0603 
0604     if (ctx->service.len) {
0605         rn = ngx_resolver_lookup_srv(r, name, hash);
0606 
0607         tree = &r->srv_rbtree;
0608         resend_queue = &r->srv_resend_queue;
0609         expire_queue = &r->srv_expire_queue;
0610 
0611     } else {
0612         rn = ngx_resolver_lookup_name(r, name, hash);
0613 
0614         tree = &r->name_rbtree;
0615         resend_queue = &r->name_resend_queue;
0616         expire_queue = &r->name_expire_queue;
0617     }
0618 
0619     if (rn) {
0620 
0621         /* ctx can be a list after NGX_RESOLVE_CNAME */
0622         for (last = ctx; last->next; last = last->next);
0623 
0624         if (rn->valid >= ngx_time()) {
0625 
0626             ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
0627 
0628             ngx_queue_remove(&rn->queue);
0629 
0630             rn->expire = ngx_time() + r->expire;
0631 
0632             ngx_queue_insert_head(expire_queue, &rn->queue);
0633 
0634             naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs;
0635 #if (NGX_HAVE_INET6)
0636             naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6;
0637 #endif
0638 
0639             if (naddrs) {
0640 
0641                 if (naddrs == 1 && rn->naddrs == 1) {
0642                     addrs = NULL;
0643 
0644                 } else {
0645                     addrs = ngx_resolver_export(r, rn, 1);
0646                     if (addrs == NULL) {
0647                         return NGX_ERROR;
0648                     }
0649                 }
0650 
0651                 last->next = rn->waiting;
0652                 rn->waiting = NULL;
0653 
0654                 /* unlock name mutex */
0655 
0656                 do {
0657                     ctx->state = NGX_OK;
0658                     ctx->valid = rn->valid;
0659                     ctx->naddrs = naddrs;
0660 
0661                     if (addrs == NULL) {
0662                         ctx->addrs = &ctx->addr;
0663                         ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
0664                         ctx->addr.socklen = sizeof(struct sockaddr_in);
0665                         ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
0666                         ctx->sin.sin_family = AF_INET;
0667                         ctx->sin.sin_addr.s_addr = rn->u.addr;
0668 
0669                     } else {
0670                         ctx->addrs = addrs;
0671                     }
0672 
0673                     next = ctx->next;
0674 
0675                     ctx->handler(ctx);
0676 
0677                     ctx = next;
0678                 } while (ctx);
0679 
0680                 if (addrs != NULL) {
0681                     ngx_resolver_free(r, addrs->sockaddr);
0682                     ngx_resolver_free(r, addrs);
0683                 }
0684 
0685                 return NGX_OK;
0686             }
0687 
0688             if (rn->nsrvs) {
0689                 last->next = rn->waiting;
0690                 rn->waiting = NULL;
0691 
0692                 /* unlock name mutex */
0693 
0694                 do {
0695                     next = ctx->next;
0696 
0697                     ngx_resolver_resolve_srv_names(ctx, rn);
0698 
0699                     ctx = next;
0700                 } while (ctx);
0701 
0702                 return NGX_OK;
0703             }
0704 
0705             /* NGX_RESOLVE_CNAME */
0706 
0707             if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
0708 
0709                 cname.len = rn->cnlen;
0710                 cname.data = rn->u.cname;
0711 
0712                 return ngx_resolve_name_locked(r, ctx, &cname);
0713             }
0714 
0715             last->next = rn->waiting;
0716             rn->waiting = NULL;
0717 
0718             /* unlock name mutex */
0719 
0720             do {
0721                 ctx->state = NGX_RESOLVE_NXDOMAIN;
0722                 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
0723                 next = ctx->next;
0724 
0725                 ctx->handler(ctx);
0726 
0727                 ctx = next;
0728             } while (ctx);
0729 
0730             return NGX_OK;
0731         }
0732 
0733         if (rn->waiting) {
0734             if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
0735                 return NGX_ERROR;
0736             }
0737 
0738             last->next = rn->waiting;
0739             rn->waiting = ctx;
0740             ctx->state = NGX_AGAIN;
0741             ctx->async = 1;
0742 
0743             do {
0744                 ctx->node = rn;
0745                 ctx = ctx->next;
0746             } while (ctx);
0747 
0748             return NGX_AGAIN;
0749         }
0750 
0751         ngx_queue_remove(&rn->queue);
0752 
0753         /* lock alloc mutex */
0754 
0755         if (rn->query) {
0756             ngx_resolver_free_locked(r, rn->query);
0757             rn->query = NULL;
0758 #if (NGX_HAVE_INET6)
0759             rn->query6 = NULL;
0760 #endif
0761         }
0762 
0763         if (rn->cnlen) {
0764             ngx_resolver_free_locked(r, rn->u.cname);
0765         }
0766 
0767         if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
0768             ngx_resolver_free_locked(r, rn->u.addrs);
0769         }
0770 
0771 #if (NGX_HAVE_INET6)
0772         if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
0773             ngx_resolver_free_locked(r, rn->u6.addrs6);
0774         }
0775 #endif
0776 
0777         if (rn->nsrvs) {
0778             for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
0779                 if (rn->u.srvs[i].name.data) {
0780                     ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
0781                 }
0782             }
0783 
0784             ngx_resolver_free_locked(r, rn->u.srvs);
0785         }
0786 
0787         /* unlock alloc mutex */
0788 
0789     } else {
0790 
0791         rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
0792         if (rn == NULL) {
0793             return NGX_ERROR;
0794         }
0795 
0796         rn->name = ngx_resolver_dup(r, name->data, name->len);
0797         if (rn->name == NULL) {
0798             ngx_resolver_free(r, rn);
0799             return NGX_ERROR;
0800         }
0801 
0802         rn->node.key = hash;
0803         rn->nlen = (u_short) name->len;
0804         rn->query = NULL;
0805 #if (NGX_HAVE_INET6)
0806         rn->query6 = NULL;
0807 #endif
0808 
0809         ngx_rbtree_insert(tree, &rn->node);
0810     }
0811 
0812     if (ctx->service.len) {
0813         rc = ngx_resolver_create_srv_query(r, rn, name);
0814 
0815     } else {
0816         rc = ngx_resolver_create_name_query(r, rn, name);
0817     }
0818 
0819     if (rc == NGX_ERROR) {
0820         goto failed;
0821     }
0822 
0823     if (rc == NGX_DECLINED) {
0824         ngx_rbtree_delete(tree, &rn->node);
0825 
0826         ngx_resolver_free(r, rn->query);
0827         ngx_resolver_free(r, rn->name);
0828         ngx_resolver_free(r, rn);
0829 
0830         do {
0831             ctx->state = NGX_RESOLVE_NXDOMAIN;
0832             next = ctx->next;
0833 
0834             ctx->handler(ctx);
0835 
0836             ctx = next;
0837         } while (ctx);
0838 
0839         return NGX_OK;
0840     }
0841 
0842     rn->last_connection = r->last_connection++;
0843     if (r->last_connection == r->connections.nelts) {
0844         r->last_connection = 0;
0845     }
0846 
0847     rn->naddrs = (u_short) -1;
0848     rn->tcp = 0;
0849 #if (NGX_HAVE_INET6)
0850     rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0;
0851     rn->tcp6 = 0;
0852 #endif
0853     rn->nsrvs = 0;
0854 
0855     if (ngx_resolver_send_query(r, rn) != NGX_OK) {
0856         goto failed;
0857     }
0858 
0859     if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
0860         goto failed;
0861     }
0862 
0863     if (ngx_resolver_resend_empty(r)) {
0864         ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
0865     }
0866 
0867     rn->expire = ngx_time() + r->resend_timeout;
0868 
0869     ngx_queue_insert_head(resend_queue, &rn->queue);
0870 
0871     rn->code = 0;
0872     rn->cnlen = 0;
0873     rn->valid = 0;
0874     rn->ttl = NGX_MAX_UINT32_VALUE;
0875     rn->waiting = ctx;
0876 
0877     ctx->state = NGX_AGAIN;
0878     ctx->async = 1;
0879 
0880     do {
0881         ctx->node = rn;
0882         ctx = ctx->next;
0883     } while (ctx);
0884 
0885     return NGX_AGAIN;
0886 
0887 failed:
0888 
0889     ngx_rbtree_delete(tree, &rn->node);
0890 
0891     if (rn->query) {
0892         ngx_resolver_free(r, rn->query);
0893     }
0894 
0895     ngx_resolver_free(r, rn->name);
0896 
0897     ngx_resolver_free(r, rn);
0898 
0899     return NGX_ERROR;
0900 }
0901 
0902 
0903 ngx_int_t
0904 ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
0905 {
0906     u_char               *name;
0907     in_addr_t             addr;
0908     ngx_queue_t          *resend_queue, *expire_queue;
0909     ngx_rbtree_t         *tree;
0910     ngx_resolver_t       *r;
0911     struct sockaddr_in   *sin;
0912     ngx_resolver_node_t  *rn;
0913 #if (NGX_HAVE_INET6)
0914     uint32_t              hash;
0915     struct sockaddr_in6  *sin6;
0916 #endif
0917 
0918 #if (NGX_SUPPRESS_WARN)
0919     addr = 0;
0920 #if (NGX_HAVE_INET6)
0921     hash = 0;
0922     sin6 = NULL;
0923 #endif
0924 #endif
0925 
0926     r = ctx->resolver;
0927 
0928     switch (ctx->addr.sockaddr->sa_family) {
0929 
0930 #if (NGX_HAVE_INET6)
0931     case AF_INET6:
0932         sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
0933         hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
0934 
0935         /* lock addr mutex */
0936 
0937         rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
0938 
0939         tree = &r->addr6_rbtree;
0940         resend_queue = &r->addr6_resend_queue;
0941         expire_queue = &r->addr6_expire_queue;
0942 
0943         break;
0944 #endif
0945 
0946     default: /* AF_INET */
0947         sin = (struct sockaddr_in *) ctx->addr.sockaddr;
0948         addr = ntohl(sin->sin_addr.s_addr);
0949 
0950         /* lock addr mutex */
0951 
0952         rn = ngx_resolver_lookup_addr(r, addr);
0953 
0954         tree = &r->addr_rbtree;
0955         resend_queue = &r->addr_resend_queue;
0956         expire_queue = &r->addr_expire_queue;
0957     }
0958 
0959     if (rn) {
0960 
0961         if (rn->valid >= ngx_time()) {
0962 
0963             ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
0964 
0965             ngx_queue_remove(&rn->queue);
0966 
0967             rn->expire = ngx_time() + r->expire;
0968 
0969             ngx_queue_insert_head(expire_queue, &rn->queue);
0970 
0971             name = ngx_resolver_dup(r, rn->name, rn->nlen);
0972             if (name == NULL) {
0973                 goto failed;
0974             }
0975 
0976             ctx->name.len = rn->nlen;
0977             ctx->name.data = name;
0978 
0979             /* unlock addr mutex */
0980 
0981             ctx->state = NGX_OK;
0982             ctx->valid = rn->valid;
0983 
0984             ctx->handler(ctx);
0985 
0986             ngx_resolver_free(r, name);
0987 
0988             return NGX_OK;
0989         }
0990 
0991         if (rn->waiting) {
0992             if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
0993                 return NGX_ERROR;
0994             }
0995 
0996             ctx->next = rn->waiting;
0997             rn->waiting = ctx;
0998             ctx->state = NGX_AGAIN;
0999             ctx->async = 1;
1000             ctx->node = rn;
1001 
1002             /* unlock addr mutex */
1003 
1004             return NGX_OK;
1005         }
1006 
1007         ngx_queue_remove(&rn->queue);
1008 
1009         ngx_resolver_free(r, rn->query);
1010         rn->query = NULL;
1011 #if (NGX_HAVE_INET6)
1012         rn->query6 = NULL;
1013 #endif
1014 
1015     } else {
1016         rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
1017         if (rn == NULL) {
1018             goto failed;
1019         }
1020 
1021         switch (ctx->addr.sockaddr->sa_family) {
1022 
1023 #if (NGX_HAVE_INET6)
1024         case AF_INET6:
1025             rn->addr6 = sin6->sin6_addr;
1026             rn->node.key = hash;
1027             break;
1028 #endif
1029 
1030         default: /* AF_INET */
1031             rn->node.key = addr;
1032         }
1033 
1034         rn->query = NULL;
1035 #if (NGX_HAVE_INET6)
1036         rn->query6 = NULL;
1037 #endif
1038 
1039         ngx_rbtree_insert(tree, &rn->node);
1040     }
1041 
1042     if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) {
1043         goto failed;
1044     }
1045 
1046     rn->last_connection = r->last_connection++;
1047     if (r->last_connection == r->connections.nelts) {
1048         r->last_connection = 0;
1049     }
1050 
1051     rn->naddrs = (u_short) -1;
1052     rn->tcp = 0;
1053 #if (NGX_HAVE_INET6)
1054     rn->naddrs6 = (u_short) -1;
1055     rn->tcp6 = 0;
1056 #endif
1057     rn->nsrvs = 0;
1058 
1059     if (ngx_resolver_send_query(r, rn) != NGX_OK) {
1060         goto failed;
1061     }
1062 
1063     if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
1064         goto failed;
1065     }
1066 
1067     if (ngx_resolver_resend_empty(r)) {
1068         ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
1069     }
1070 
1071     rn->expire = ngx_time() + r->resend_timeout;
1072 
1073     ngx_queue_insert_head(resend_queue, &rn->queue);
1074 
1075     rn->code = 0;
1076     rn->cnlen = 0;
1077     rn->name = NULL;
1078     rn->nlen = 0;
1079     rn->valid = 0;
1080     rn->ttl = NGX_MAX_UINT32_VALUE;
1081     rn->waiting = ctx;
1082 
1083     /* unlock addr mutex */
1084 
1085     ctx->state = NGX_AGAIN;
1086     ctx->async = 1;
1087     ctx->node = rn;
1088 
1089     return NGX_OK;
1090 
1091 failed:
1092 
1093     if (rn) {
1094         ngx_rbtree_delete(tree, &rn->node);
1095 
1096         if (rn->query) {
1097             ngx_resolver_free(r, rn->query);
1098         }
1099 
1100         ngx_resolver_free(r, rn);
1101     }
1102 
1103     /* unlock addr mutex */
1104 
1105     if (ctx->event) {
1106         ngx_resolver_free(r, ctx->event);
1107     }
1108 
1109     ngx_resolver_free(r, ctx);
1110 
1111     return NGX_ERROR;
1112 }
1113 
1114 
1115 void
1116 ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
1117 {
1118     ngx_queue_t          *expire_queue;
1119     ngx_rbtree_t         *tree;
1120     ngx_resolver_t       *r;
1121     ngx_resolver_ctx_t   *w, **p;
1122     ngx_resolver_node_t  *rn;
1123 
1124     r = ctx->resolver;
1125 
1126     switch (ctx->addr.sockaddr->sa_family) {
1127 
1128 #if (NGX_HAVE_INET6)
1129     case AF_INET6:
1130         tree = &r->addr6_rbtree;
1131         expire_queue = &r->addr6_expire_queue;
1132         break;
1133 #endif
1134 
1135     default: /* AF_INET */
1136         tree = &r->addr_rbtree;
1137         expire_queue = &r->addr_expire_queue;
1138     }
1139 
1140     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
1141                    "resolve addr done: %i", ctx->state);
1142 
1143     if (ctx->event && ctx->event->timer_set) {
1144         ngx_del_timer(ctx->event);
1145     }
1146 
1147     /* lock addr mutex */
1148 
1149     if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
1150 
1151         rn = ctx->node;
1152 
1153         if (rn) {
1154             p = &rn->waiting;
1155             w = rn->waiting;
1156 
1157             while (w) {
1158                 if (w == ctx) {
1159                     *p = w->next;
1160 
1161                     goto done;
1162                 }
1163 
1164                 p = &w->next;
1165                 w = w->next;
1166             }
1167         }
1168 
1169         {
1170             u_char     text[NGX_SOCKADDR_STRLEN];
1171             ngx_str_t  addrtext;
1172 
1173             addrtext.data = text;
1174             addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen,
1175                                          text, NGX_SOCKADDR_STRLEN, 0);
1176 
1177             ngx_log_error(NGX_LOG_ALERT, r->log, 0,
1178                           "could not cancel %V resolving", &addrtext);
1179         }
1180     }
1181 
1182 done:
1183 
1184     ngx_resolver_expire(r, tree, expire_queue);
1185 
1186     /* unlock addr mutex */
1187 
1188     /* lock alloc mutex */
1189 
1190     if (ctx->event) {
1191         ngx_resolver_free_locked(r, ctx->event);
1192     }
1193 
1194     ngx_resolver_free_locked(r, ctx);
1195 
1196     /* unlock alloc mutex */
1197 
1198     if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
1199         ngx_del_timer(r->event);
1200     }
1201 }
1202 
1203 
1204 static void
1205 ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
1206 {
1207     time_t                now;
1208     ngx_uint_t            i;
1209     ngx_queue_t          *q;
1210     ngx_resolver_node_t  *rn;
1211 
1212     ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire");
1213 
1214     now = ngx_time();
1215 
1216     for (i = 0; i < 2; i++) {
1217         if (ngx_queue_empty(queue)) {
1218             return;
1219         }
1220 
1221         q = ngx_queue_last(queue);
1222 
1223         rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1224 
1225         if (now <= rn->expire) {
1226             return;
1227         }
1228 
1229         ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1230                        "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name);
1231 
1232         ngx_queue_remove(q);
1233 
1234         ngx_rbtree_delete(tree, &rn->node);
1235 
1236         ngx_resolver_free_node(r, rn);
1237     }
1238 }
1239 
1240 
1241 static ngx_int_t
1242 ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
1243 {
1244     ngx_int_t                   rc;
1245     ngx_resolver_connection_t  *rec;
1246 
1247     rec = r->connections.elts;
1248     rec = &rec[rn->last_connection];
1249 
1250     if (rec->log.handler == NULL) {
1251         rec->log = *r->log;
1252         rec->log.handler = ngx_resolver_log_error;
1253         rec->log.data = rec;
1254         rec->log.action = "resolving";
1255     }
1256 
1257     if (rn->naddrs == (u_short) -1) {
1258         rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen)
1259                      : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen);
1260 
1261         if (rc != NGX_OK) {
1262             return rc;
1263         }
1264     }
1265 
1266 #if (NGX_HAVE_INET6)
1267 
1268     if (rn->query6 && rn->naddrs6 == (u_short) -1) {
1269         rc = rn->tcp6
1270                     ? ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen)
1271                     : ngx_resolver_send_udp_query(r, rec, rn->query6, rn->qlen);
1272 
1273         if (rc != NGX_OK) {
1274             return rc;
1275         }
1276     }
1277 
1278 #endif
1279 
1280     return NGX_OK;
1281 }
1282 
1283 
1284 static ngx_int_t
1285 ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t  *rec,
1286     u_char *query, u_short qlen)
1287 {
1288     ssize_t  n;
1289 
1290     if (rec->udp == NULL) {
1291         if (ngx_udp_connect(rec) != NGX_OK) {
1292             return NGX_ERROR;
1293         }
1294 
1295         rec->udp->data = rec;
1296         rec->udp->read->handler = ngx_resolver_udp_read;
1297         rec->udp->read->resolver = 1;
1298     }
1299 
1300     n = ngx_send(rec->udp, query, qlen);
1301 
1302     if (n == -1) {
1303         return NGX_ERROR;
1304     }
1305 
1306     if ((size_t) n != (size_t) qlen) {
1307         ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete");
1308         return NGX_ERROR;
1309     }
1310 
1311     return NGX_OK;
1312 }
1313 
1314 
1315 static ngx_int_t
1316 ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
1317     u_char *query, u_short qlen)
1318 {
1319     ngx_buf_t  *b;
1320     ngx_int_t   rc;
1321 
1322     rc = NGX_OK;
1323 
1324     if (rec->tcp == NULL) {
1325         b = rec->read_buf;
1326 
1327         if (b == NULL) {
1328             b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1329             if (b == NULL) {
1330                 return NGX_ERROR;
1331             }
1332 
1333             b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_RSIZE);
1334             if (b->start == NULL) {
1335                 ngx_resolver_free(r, b);
1336                 return NGX_ERROR;
1337             }
1338 
1339             b->end = b->start + NGX_RESOLVER_TCP_RSIZE;
1340 
1341             rec->read_buf = b;
1342         }
1343 
1344         b->pos = b->start;
1345         b->last = b->start;
1346 
1347         b = rec->write_buf;
1348 
1349         if (b == NULL) {
1350             b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1351             if (b == NULL) {
1352                 return NGX_ERROR;
1353             }
1354 
1355             b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_WSIZE);
1356             if (b->start == NULL) {
1357                 ngx_resolver_free(r, b);
1358                 return NGX_ERROR;
1359             }
1360 
1361             b->end = b->start + NGX_RESOLVER_TCP_WSIZE;
1362 
1363             rec->write_buf = b;
1364         }
1365 
1366         b->pos = b->start;
1367         b->last = b->start;
1368 
1369         rc = ngx_tcp_connect(rec);
1370         if (rc == NGX_ERROR) {
1371             return NGX_ERROR;
1372         }
1373 
1374         rec->tcp->data = rec;
1375         rec->tcp->write->handler = ngx_resolver_tcp_write;
1376         rec->tcp->read->handler = ngx_resolver_tcp_read;
1377         rec->tcp->read->resolver = 1;
1378 
1379         ngx_add_timer(rec->tcp->write, (ngx_msec_t) (r->tcp_timeout * 1000));
1380     }
1381 
1382     b = rec->write_buf;
1383 
1384     if (b->end - b->last <  2 + qlen) {
1385         ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "buffer overflow");
1386         return NGX_ERROR;
1387     }
1388 
1389     *b->last++ = (u_char) (qlen >> 8);
1390     *b->last++ = (u_char) qlen;
1391     b->last = ngx_cpymem(b->last, query, qlen);
1392 
1393     if (rc == NGX_OK) {
1394         ngx_resolver_tcp_write(rec->tcp->write);
1395     }
1396 
1397     return NGX_OK;
1398 }
1399 
1400 
1401 static void
1402 ngx_resolver_resend_handler(ngx_event_t *ev)
1403 {
1404     time_t           timer, atimer, stimer, ntimer;
1405 #if (NGX_HAVE_INET6)
1406     time_t           a6timer;
1407 #endif
1408     ngx_resolver_t  *r;
1409 
1410     r = ev->data;
1411 
1412     ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0,
1413                    "resolver resend handler");
1414 
1415     /* lock name mutex */
1416 
1417     ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue);
1418 
1419     stimer = ngx_resolver_resend(r, &r->srv_rbtree, &r->srv_resend_queue);
1420 
1421     /* unlock name mutex */
1422 
1423     /* lock addr mutex */
1424 
1425     atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue);
1426 
1427     /* unlock addr mutex */
1428 
1429 #if (NGX_HAVE_INET6)
1430 
1431     /* lock addr6 mutex */
1432 
1433     a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue);
1434 
1435     /* unlock addr6 mutex */
1436 
1437 #endif
1438 
1439     timer = ntimer;
1440 
1441     if (timer == 0) {
1442         timer = atimer;
1443 
1444     } else if (atimer) {
1445         timer = ngx_min(timer, atimer);
1446     }
1447 
1448     if (timer == 0) {
1449         timer = stimer;
1450 
1451     } else if (stimer) {
1452         timer = ngx_min(timer, stimer);
1453     }
1454 
1455 #if (NGX_HAVE_INET6)
1456 
1457     if (timer == 0) {
1458         timer = a6timer;
1459 
1460     } else if (a6timer) {
1461         timer = ngx_min(timer, a6timer);
1462     }
1463 
1464 #endif
1465 
1466     if (timer) {
1467         ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
1468     }
1469 }
1470 
1471 
1472 static time_t
1473 ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
1474 {
1475     time_t                now;
1476     ngx_queue_t          *q;
1477     ngx_resolver_node_t  *rn;
1478 
1479     now = ngx_time();
1480 
1481     for ( ;; ) {
1482         if (ngx_queue_empty(queue)) {
1483             return 0;
1484         }
1485 
1486         q = ngx_queue_last(queue);
1487 
1488         rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1489 
1490         if (now < rn->expire) {
1491             return rn->expire - now;
1492         }
1493 
1494         ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
1495                        "resolver resend \"%*s\" %p",
1496                        (size_t) rn->nlen, rn->name, rn->waiting);
1497 
1498         ngx_queue_remove(q);
1499 
1500         if (rn->waiting) {
1501 
1502             if (++rn->last_connection == r->connections.nelts) {
1503                 rn->last_connection = 0;
1504             }
1505 
1506             (void) ngx_resolver_send_query(r, rn);
1507 
1508             rn->expire = now + r->resend_timeout;
1509 
1510             ngx_queue_insert_head(queue, q);
1511 
1512             continue;
1513         }
1514 
1515         ngx_rbtree_delete(tree, &rn->node);
1516 
1517         ngx_resolver_free_node(r, rn);
1518     }
1519 }
1520 
1521 
1522 static ngx_uint_t
1523 ngx_resolver_resend_empty(ngx_resolver_t *r)
1524 {
1525     return ngx_queue_empty(&r->name_resend_queue)
1526            && ngx_queue_empty(&r->srv_resend_queue)
1527 #if (NGX_HAVE_INET6)
1528            && ngx_queue_empty(&r->addr6_resend_queue)
1529 #endif
1530            && ngx_queue_empty(&r->addr_resend_queue);
1531 }
1532 
1533 
1534 static void
1535 ngx_resolver_udp_read(ngx_event_t *rev)
1536 {
1537     ssize_t                     n;
1538     ngx_connection_t           *c;
1539     ngx_resolver_connection_t  *rec;
1540     u_char                      buf[NGX_RESOLVER_UDP_SIZE];
1541 
1542     c = rev->data;
1543     rec = c->data;
1544 
1545     do {
1546         n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
1547 
1548         if (n < 0) {
1549             return;
1550         }
1551 
1552         ngx_resolver_process_response(rec->resolver, buf, n, 0);
1553 
1554     } while (rev->ready);
1555 }
1556 
1557 
1558 static void
1559 ngx_resolver_tcp_write(ngx_event_t *wev)
1560 {
1561     off_t                       sent;
1562     ssize_t                     n;
1563     ngx_buf_t                  *b;
1564     ngx_resolver_t             *r;
1565     ngx_connection_t           *c;
1566     ngx_resolver_connection_t  *rec;
1567 
1568     c = wev->data;
1569     rec = c->data;
1570     b = rec->write_buf;
1571     r = rec->resolver;
1572 
1573     if (wev->timedout) {
1574         goto failed;
1575     }
1576 
1577     sent = c->sent;
1578 
1579     while (wev->ready && b->pos < b->last) {
1580         n = ngx_send(c, b->pos, b->last - b->pos);
1581 
1582         if (n == NGX_AGAIN) {
1583             break;
1584         }
1585 
1586         if (n == NGX_ERROR) {
1587             goto failed;
1588         }
1589 
1590         b->pos += n;
1591     }
1592 
1593     if (b->pos != b->start) {
1594         b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1595         b->pos = b->start;
1596     }
1597 
1598     if (c->sent != sent) {
1599         ngx_add_timer(wev, (ngx_msec_t) (r->tcp_timeout * 1000));
1600     }
1601 
1602     if (ngx_handle_write_event(wev, 0) != NGX_OK) {
1603         goto failed;
1604     }
1605 
1606     return;
1607 
1608 failed:
1609 
1610     ngx_close_connection(c);
1611     rec->tcp = NULL;
1612 }
1613 
1614 
1615 static void
1616 ngx_resolver_tcp_read(ngx_event_t *rev)
1617 {
1618     u_char                     *p;
1619     size_t                      size;
1620     ssize_t                     n;
1621     u_short                     qlen;
1622     ngx_buf_t                  *b;
1623     ngx_resolver_t             *r;
1624     ngx_connection_t           *c;
1625     ngx_resolver_connection_t  *rec;
1626 
1627     c = rev->data;
1628     rec = c->data;
1629     b = rec->read_buf;
1630     r = rec->resolver;
1631 
1632     while (rev->ready) {
1633         n = ngx_recv(c, b->last, b->end - b->last);
1634 
1635         if (n == NGX_AGAIN) {
1636             break;
1637         }
1638 
1639         if (n == NGX_ERROR || n == 0) {
1640             goto failed;
1641         }
1642 
1643         b->last += n;
1644 
1645         for ( ;; ) {
1646             p = b->pos;
1647             size = b->last - p;
1648 
1649             if (size < 2) {
1650                 break;
1651             }
1652 
1653             qlen = (u_short) *p++ << 8;
1654             qlen += *p++;
1655 
1656             if (size < (size_t) (2 + qlen)) {
1657                 break;
1658             }
1659 
1660             ngx_resolver_process_response(r, p, qlen, 1);
1661 
1662             b->pos += 2 + qlen;
1663         }
1664 
1665         if (b->pos != b->start) {
1666             b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1667             b->pos = b->start;
1668         }
1669     }
1670 
1671     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1672         goto failed;
1673     }
1674 
1675     return;
1676 
1677 failed:
1678 
1679     ngx_close_connection(c);
1680     rec->tcp = NULL;
1681 }
1682 
1683 
1684 static void
1685 ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n,
1686     ngx_uint_t tcp)
1687 {
1688     char                 *err;
1689     ngx_uint_t            i, times, ident, qident, flags, code, nqs, nan, trunc,
1690                           qtype, qclass;
1691 #if (NGX_HAVE_INET6)
1692     ngx_uint_t            qident6;
1693 #endif
1694     ngx_queue_t          *q;
1695     ngx_resolver_qs_t    *qs;
1696     ngx_resolver_hdr_t   *response;
1697     ngx_resolver_node_t  *rn;
1698 
1699     if (n < sizeof(ngx_resolver_hdr_t)) {
1700         goto short_response;
1701     }
1702 
1703     response = (ngx_resolver_hdr_t *) buf;
1704 
1705     ident = (response->ident_hi << 8) + response->ident_lo;
1706     flags = (response->flags_hi << 8) + response->flags_lo;
1707     nqs = (response->nqs_hi << 8) + response->nqs_lo;
1708     nan = (response->nan_hi << 8) + response->nan_lo;
1709     trunc = flags & 0x0200;
1710 
1711     ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
1712                    "resolver DNS response %ui fl:%04Xi %ui/%ui/%ud/%ud",
1713                    ident, flags, nqs, nan,
1714                    (response->nns_hi << 8) + response->nns_lo,
1715                    (response->nar_hi << 8) + response->nar_lo);
1716 
1717     /* response to a standard query */
1718     if ((flags & 0xf870) != 0x8000 || (trunc && tcp)) {
1719         ngx_log_error(r->log_level, r->log, 0,
1720                       "invalid %s DNS response %ui fl:%04Xi",
1721                       tcp ? "TCP" : "UDP", ident, flags);
1722         return;
1723     }
1724 
1725     code = flags & 0xf;
1726 
1727     if (code == NGX_RESOLVE_FORMERR) {
1728 
1729         times = 0;
1730 
1731         for (q = ngx_queue_head(&r->name_resend_queue);
1732              q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100;
1733              q = ngx_queue_next(q))
1734         {
1735             rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1736             qident = (rn->query[0] << 8) + rn->query[1];
1737 
1738             if (qident == ident) {
1739                 goto dns_error_name;
1740             }
1741 
1742 #if (NGX_HAVE_INET6)
1743             if (rn->query6) {
1744                 qident6 = (rn->query6[0] << 8) + rn->query6[1];
1745 
1746                 if (qident6 == ident) {
1747                     goto dns_error_name;
1748                 }
1749             }
1750 #endif
1751         }
1752 
1753         goto dns_error;
1754     }
1755 
1756     if (code > NGX_RESOLVE_REFUSED) {
1757         goto dns_error;
1758     }
1759 
1760     if (nqs != 1) {
1761         err = "invalid number of questions in DNS response";
1762         goto done;
1763     }
1764 
1765     i = sizeof(ngx_resolver_hdr_t);
1766 
1767     while (i < (ngx_uint_t) n) {
1768         if (buf[i] == '\0') {
1769             goto found;
1770         }
1771 
1772         i += 1 + buf[i];
1773     }
1774 
1775     goto short_response;
1776 
1777 found:
1778 
1779     if (i++ == sizeof(ngx_resolver_hdr_t)) {
1780         err = "zero-length domain name in DNS response";
1781         goto done;
1782     }
1783 
1784     if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t))
1785         > (ngx_uint_t) n)
1786     {
1787         goto short_response;
1788     }
1789 
1790     qs = (ngx_resolver_qs_t *) &buf[i];
1791 
1792     qtype = (qs->type_hi << 8) + qs->type_lo;
1793     qclass = (qs->class_hi << 8) + qs->class_lo;
1794 
1795     ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1796                    "resolver DNS response qt:%ui cl:%ui", qtype, qclass);
1797 
1798     if (qclass != 1) {
1799         ngx_log_error(r->log_level, r->log, 0,
1800                       "unknown query class %ui in DNS response", qclass);
1801         return;
1802     }
1803 
1804     switch (qtype) {
1805 
1806     case NGX_RESOLVE_A:
1807 #if (NGX_HAVE_INET6)
1808     case NGX_RESOLVE_AAAA:
1809 #endif
1810 
1811         ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, trunc,
1812                                i + sizeof(ngx_resolver_qs_t));
1813 
1814         break;
1815 
1816     case NGX_RESOLVE_SRV:
1817 
1818         ngx_resolver_process_srv(r, buf, n, ident, code, nan, trunc,
1819                                  i + sizeof(ngx_resolver_qs_t));
1820 
1821         break;
1822 
1823     case NGX_RESOLVE_PTR:
1824 
1825         ngx_resolver_process_ptr(r, buf, n, ident, code, nan);
1826 
1827         break;
1828 
1829     default:
1830         ngx_log_error(r->log_level, r->log, 0,
1831                       "unknown query type %ui in DNS response", qtype);
1832         return;
1833     }
1834 
1835     return;
1836 
1837 short_response:
1838 
1839     err = "short DNS response";
1840 
1841 done:
1842 
1843     ngx_log_error(r->log_level, r->log, 0, err);
1844 
1845     return;
1846 
1847 dns_error_name:
1848 
1849     ngx_log_error(r->log_level, r->log, 0,
1850                   "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
1851                   code, ngx_resolver_strerror(code), ident,
1852                   (size_t) rn->nlen, rn->name);
1853     return;
1854 
1855 dns_error:
1856 
1857     ngx_log_error(r->log_level, r->log, 0,
1858                   "DNS error (%ui: %s), query id:%ui",
1859                   code, ngx_resolver_strerror(code), ident);
1860     return;
1861 }
1862 
1863 
1864 static void
1865 ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
1866     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
1867     ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans)
1868 {
1869     char                       *err;
1870     u_char                     *cname;
1871     size_t                      len;
1872     int32_t                     ttl;
1873     uint32_t                    hash;
1874     in_addr_t                  *addr;
1875     ngx_str_t                   name;
1876     ngx_uint_t                  type, class, qident, naddrs, a, i, j, start;
1877 #if (NGX_HAVE_INET6)
1878     struct in6_addr            *addr6;
1879 #endif
1880     ngx_resolver_an_t          *an;
1881     ngx_resolver_ctx_t         *ctx, *next;
1882     ngx_resolver_node_t        *rn;
1883     ngx_resolver_addr_t        *addrs;
1884     ngx_resolver_connection_t  *rec;
1885 
1886     if (ngx_resolver_copy(r, &name, buf,
1887                           buf + sizeof(ngx_resolver_hdr_t), buf + n)
1888         != NGX_OK)
1889     {
1890         return;
1891     }
1892 
1893     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
1894 
1895     hash = ngx_crc32_short(name.data, name.len);
1896 
1897     /* lock name mutex */
1898 
1899     rn = ngx_resolver_lookup_name(r, &name, hash);
1900 
1901     if (rn == NULL) {
1902         ngx_log_error(r->log_level, r->log, 0,
1903                       "unexpected response for %V", &name);
1904         ngx_resolver_free(r, name.data);
1905         goto failed;
1906     }
1907 
1908     switch (qtype) {
1909 
1910 #if (NGX_HAVE_INET6)
1911     case NGX_RESOLVE_AAAA:
1912 
1913         if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) {
1914             ngx_log_error(r->log_level, r->log, 0,
1915                           "unexpected response for %V", &name);
1916             ngx_resolver_free(r, name.data);
1917             goto failed;
1918         }
1919 
1920         if (trunc && rn->tcp6) {
1921             ngx_resolver_free(r, name.data);
1922             goto failed;
1923         }
1924 
1925         qident = (rn->query6[0] << 8) + rn->query6[1];
1926 
1927         break;
1928 #endif
1929 
1930     default: /* NGX_RESOLVE_A */
1931 
1932         if (rn->query == NULL || rn->naddrs != (u_short) -1) {
1933             ngx_log_error(r->log_level, r->log, 0,
1934                           "unexpected response for %V", &name);
1935             ngx_resolver_free(r, name.data);
1936             goto failed;
1937         }
1938 
1939         if (trunc && rn->tcp) {
1940             ngx_resolver_free(r, name.data);
1941             goto failed;
1942         }
1943 
1944         qident = (rn->query[0] << 8) + rn->query[1];
1945     }
1946 
1947     if (ident != qident) {
1948         ngx_log_error(r->log_level, r->log, 0,
1949                       "wrong ident %ui response for %V, expect %ui",
1950                       ident, &name, qident);
1951         ngx_resolver_free(r, name.data);
1952         goto failed;
1953     }
1954 
1955     ngx_resolver_free(r, name.data);
1956 
1957     if (trunc) {
1958 
1959         ngx_queue_remove(&rn->queue);
1960 
1961         if (rn->waiting == NULL) {
1962             ngx_rbtree_delete(&r->name_rbtree, &rn->node);
1963             ngx_resolver_free_node(r, rn);
1964             goto next;
1965         }
1966 
1967         rec = r->connections.elts;
1968         rec = &rec[rn->last_connection];
1969 
1970         switch (qtype) {
1971 
1972 #if (NGX_HAVE_INET6)
1973         case NGX_RESOLVE_AAAA:
1974 
1975             rn->tcp6 = 1;
1976 
1977             (void) ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen);
1978 
1979             break;
1980 #endif
1981 
1982         default: /* NGX_RESOLVE_A */
1983 
1984             rn->tcp = 1;
1985 
1986             (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
1987         }
1988 
1989         rn->expire = ngx_time() + r->resend_timeout;
1990 
1991         ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
1992 
1993         goto next;
1994     }
1995 
1996     if (code == 0 && rn->code) {
1997         code = rn->code;
1998     }
1999 
2000     if (code == 0 && nan == 0) {
2001 
2002 #if (NGX_HAVE_INET6)
2003         switch (qtype) {
2004 
2005         case NGX_RESOLVE_AAAA:
2006 
2007             rn->naddrs6 = 0;
2008 
2009             if (rn->naddrs == (u_short) -1) {
2010                 goto next;
2011             }
2012 
2013             if (rn->naddrs) {
2014                 goto export;
2015             }
2016 
2017             break;
2018 
2019         default: /* NGX_RESOLVE_A */
2020 
2021             rn->naddrs = 0;
2022 
2023             if (rn->naddrs6 == (u_short) -1) {
2024                 goto next;
2025             }
2026 
2027             if (rn->naddrs6) {
2028                 goto export;
2029             }
2030         }
2031 #endif
2032 
2033         code = NGX_RESOLVE_NXDOMAIN;
2034     }
2035 
2036     if (code) {
2037 
2038 #if (NGX_HAVE_INET6)
2039         switch (qtype) {
2040 
2041         case NGX_RESOLVE_AAAA:
2042 
2043             rn->naddrs6 = 0;
2044 
2045             if (rn->naddrs == (u_short) -1) {
2046                 rn->code = (u_char) code;
2047                 goto next;
2048             }
2049 
2050             break;
2051 
2052         default: /* NGX_RESOLVE_A */
2053 
2054             rn->naddrs = 0;
2055 
2056             if (rn->naddrs6 == (u_short) -1) {
2057                 rn->code = (u_char) code;
2058                 goto next;
2059             }
2060         }
2061 #endif
2062 
2063         next = rn->waiting;
2064         rn->waiting = NULL;
2065 
2066         ngx_queue_remove(&rn->queue);
2067 
2068         ngx_rbtree_delete(&r->name_rbtree, &rn->node);
2069 
2070         /* unlock name mutex */
2071 
2072         while (next) {
2073             ctx = next;
2074             ctx->state = code;
2075             ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
2076             next = ctx->next;
2077 
2078             ctx->handler(ctx);
2079         }
2080 
2081         ngx_resolver_free_node(r, rn);
2082 
2083         return;
2084     }
2085 
2086     i = ans;
2087     naddrs = 0;
2088     cname = NULL;
2089 
2090     for (a = 0; a < nan; a++) {
2091 
2092         start = i;
2093 
2094         while (i < n) {
2095 
2096             if (buf[i] & 0xc0) {
2097                 i += 2;
2098                 goto found;
2099             }
2100 
2101             if (buf[i] == 0) {
2102                 i++;
2103                 goto test_length;
2104             }
2105 
2106             i += 1 + buf[i];
2107         }
2108 
2109         goto short_response;
2110 
2111     test_length:
2112 
2113         if (i - start < 2) {
2114             err = "invalid name in DNS response";
2115             goto invalid;
2116         }
2117 
2118     found:
2119 
2120         if (i + sizeof(ngx_resolver_an_t) >= n) {
2121             goto short_response;
2122         }
2123 
2124         an = (ngx_resolver_an_t *) &buf[i];
2125 
2126         type = (an->type_hi << 8) + an->type_lo;
2127         class = (an->class_hi << 8) + an->class_lo;
2128         len = (an->len_hi << 8) + an->len_lo;
2129         ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
2130             + (an->ttl[2] << 8) + (an->ttl[3]);
2131 
2132         if (class != 1) {
2133             ngx_log_error(r->log_level, r->log, 0,
2134                           "unexpected RR class %ui", class);
2135             goto failed;
2136         }
2137 
2138         if (ttl < 0) {
2139             ttl = 0;
2140         }
2141 
2142         rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
2143 
2144         i += sizeof(ngx_resolver_an_t);
2145 
2146         switch (type) {
2147 
2148         case NGX_RESOLVE_A:
2149 
2150             if (qtype != NGX_RESOLVE_A) {
2151                 err = "unexpected A record in DNS response";
2152                 goto invalid;
2153             }
2154 
2155             if (len != 4) {
2156                 err = "invalid A record in DNS response";
2157                 goto invalid;
2158             }
2159 
2160             if (i + 4 > n) {
2161                 goto short_response;
2162             }
2163 
2164             naddrs++;
2165 
2166             break;
2167 
2168 #if (NGX_HAVE_INET6)
2169         case NGX_RESOLVE_AAAA:
2170 
2171             if (qtype != NGX_RESOLVE_AAAA) {
2172                 err = "unexpected AAAA record in DNS response";
2173                 goto invalid;
2174             }
2175 
2176             if (len != 16) {
2177                 err = "invalid AAAA record in DNS response";
2178                 goto invalid;
2179             }
2180 
2181             if (i + 16 > n) {
2182                 goto short_response;
2183             }
2184 
2185             naddrs++;
2186 
2187             break;
2188 #endif
2189 
2190         case NGX_RESOLVE_CNAME:
2191 
2192             cname = &buf[i];
2193 
2194             break;
2195 
2196         case NGX_RESOLVE_DNAME:
2197 
2198             break;
2199 
2200         default:
2201 
2202             ngx_log_error(r->log_level, r->log, 0,
2203                           "unexpected RR type %ui", type);
2204         }
2205 
2206         i += len;
2207     }
2208 
2209     ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
2210                    "resolver naddrs:%ui cname:%p ttl:%uD",
2211                    naddrs, cname, rn->ttl);
2212 
2213     if (naddrs) {
2214 
2215         switch (qtype) {
2216 
2217 #if (NGX_HAVE_INET6)
2218         case NGX_RESOLVE_AAAA:
2219 
2220             if (naddrs == 1) {
2221                 addr6 = &rn->u6.addr6;
2222                 rn->naddrs6 = 1;
2223 
2224             } else {
2225                 addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr));
2226                 if (addr6 == NULL) {
2227                     goto failed;
2228                 }
2229 
2230                 rn->u6.addrs6 = addr6;
2231                 rn->naddrs6 = (u_short) naddrs;
2232             }
2233 
2234 #if (NGX_SUPPRESS_WARN)
2235             addr = NULL;
2236 #endif
2237 
2238             break;
2239 #endif
2240 
2241         default: /* NGX_RESOLVE_A */
2242 
2243             if (naddrs == 1) {
2244                 addr = &rn->u.addr;
2245                 rn->naddrs = 1;
2246 
2247             } else {
2248                 addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
2249                 if (addr == NULL) {
2250                     goto failed;
2251                 }
2252 
2253                 rn->u.addrs = addr;
2254                 rn->naddrs = (u_short) naddrs;
2255             }
2256 
2257 #if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN)
2258             addr6 = NULL;
2259 #endif
2260         }
2261 
2262         j = 0;
2263         i = ans;
2264 
2265         for (a = 0; a < nan; a++) {
2266 
2267             for ( ;; ) {
2268 
2269                 if (buf[i] & 0xc0) {
2270                     i += 2;
2271                     break;
2272                 }
2273 
2274                 if (buf[i] == 0) {
2275                     i++;
2276                     break;
2277                 }
2278 
2279                 i += 1 + buf[i];
2280             }
2281 
2282             an = (ngx_resolver_an_t *) &buf[i];
2283 
2284             type = (an->type_hi << 8) + an->type_lo;
2285             len = (an->len_hi << 8) + an->len_lo;
2286 
2287             i += sizeof(ngx_resolver_an_t);
2288 
2289             if (type == NGX_RESOLVE_A) {
2290 
2291                 addr[j] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
2292                                 + (buf[i + 2] << 8) + (buf[i + 3]));
2293 
2294                 if (++j == naddrs) {
2295 
2296 #if (NGX_HAVE_INET6)
2297                     if (rn->naddrs6 == (u_short) -1) {
2298                         goto next;
2299                     }
2300 #endif
2301 
2302                     break;
2303                 }
2304             }
2305 
2306 #if (NGX_HAVE_INET6)
2307             else if (type == NGX_RESOLVE_AAAA) {
2308 
2309                 ngx_memcpy(addr6[j].s6_addr, &buf[i], 16);
2310 
2311                 if (++j == naddrs) {
2312 
2313                     if (rn->naddrs == (u_short) -1) {
2314                         goto next;
2315                     }
2316 
2317                     break;
2318                 }
2319             }
2320 #endif
2321 
2322             i += len;
2323         }
2324     }
2325 
2326     switch (qtype) {
2327 
2328 #if (NGX_HAVE_INET6)
2329     case NGX_RESOLVE_AAAA:
2330 
2331         if (rn->naddrs6 == (u_short) -1) {
2332             rn->naddrs6 = 0;
2333         }
2334 
2335         break;
2336 #endif
2337 
2338     default: /* NGX_RESOLVE_A */
2339 
2340         if (rn->naddrs == (u_short) -1) {
2341             rn->naddrs = 0;
2342         }
2343     }
2344 
2345     if (rn->naddrs != (u_short) -1
2346 #if (NGX_HAVE_INET6)
2347         && rn->naddrs6 != (u_short) -1
2348 #endif
2349         && rn->naddrs
2350 #if (NGX_HAVE_INET6)
2351            + rn->naddrs6
2352 #endif
2353            > 0)
2354     {
2355 
2356 #if (NGX_HAVE_INET6)
2357     export:
2358 #endif
2359 
2360         naddrs = rn->naddrs;
2361 #if (NGX_HAVE_INET6)
2362         naddrs += rn->naddrs6;
2363 #endif
2364 
2365         if (naddrs == 1 && rn->naddrs == 1) {
2366             addrs = NULL;
2367 
2368         } else {
2369             addrs = ngx_resolver_export(r, rn, 0);
2370             if (addrs == NULL) {
2371                 goto failed;
2372             }
2373         }
2374 
2375         ngx_queue_remove(&rn->queue);
2376 
2377         rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2378         rn->expire = ngx_time() + r->expire;
2379 
2380         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
2381 
2382         next = rn->waiting;
2383         rn->waiting = NULL;
2384 
2385         /* unlock name mutex */
2386 
2387         while (next) {
2388             ctx = next;
2389             ctx->state = NGX_OK;
2390             ctx->valid = rn->valid;
2391             ctx->naddrs = naddrs;
2392 
2393             if (addrs == NULL) {
2394                 ctx->addrs = &ctx->addr;
2395                 ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
2396                 ctx->addr.socklen = sizeof(struct sockaddr_in);
2397                 ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
2398                 ctx->sin.sin_family = AF_INET;
2399                 ctx->sin.sin_addr.s_addr = rn->u.addr;
2400 
2401             } else {
2402                 ctx->addrs = addrs;
2403             }
2404 
2405             next = ctx->next;
2406 
2407             ctx->handler(ctx);
2408         }
2409 
2410         if (addrs != NULL) {
2411             ngx_resolver_free(r, addrs->sockaddr);
2412             ngx_resolver_free(r, addrs);
2413         }
2414 
2415         ngx_resolver_free(r, rn->query);
2416         rn->query = NULL;
2417 #if (NGX_HAVE_INET6)
2418         rn->query6 = NULL;
2419 #endif
2420 
2421         return;
2422     }
2423 
2424     if (cname) {
2425 
2426         /* CNAME only */
2427 
2428         if (rn->naddrs == (u_short) -1
2429 #if (NGX_HAVE_INET6)
2430             || rn->naddrs6 == (u_short) -1
2431 #endif
2432             )
2433         {
2434             goto next;
2435         }
2436 
2437         if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) {
2438             goto failed;
2439         }
2440 
2441         ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
2442                        "resolver cname:\"%V\"", &name);
2443 
2444         ngx_queue_remove(&rn->queue);
2445 
2446         rn->cnlen = (u_short) name.len;
2447         rn->u.cname = name.data;
2448 
2449         rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2450         rn->expire = ngx_time() + r->expire;
2451 
2452         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
2453 
2454         ngx_resolver_free(r, rn->query);
2455         rn->query = NULL;
2456 #if (NGX_HAVE_INET6)
2457         rn->query6 = NULL;
2458 #endif
2459 
2460         ctx = rn->waiting;
2461         rn->waiting = NULL;
2462 
2463         if (ctx) {
2464 
2465             if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
2466 
2467                 /* unlock name mutex */
2468 
2469                 do {
2470                     ctx->state = NGX_RESOLVE_NXDOMAIN;
2471                     next = ctx->next;
2472 
2473                     ctx->handler(ctx);
2474 
2475                     ctx = next;
2476                 } while (ctx);
2477 
2478                 return;
2479             }
2480 
2481             for (next = ctx; next; next = next->next) {
2482                 next->node = NULL;
2483             }
2484 
2485             (void) ngx_resolve_name_locked(r, ctx, &name);
2486         }
2487 
2488         /* unlock name mutex */
2489 
2490         return;
2491     }
2492 
2493     ngx_log_error(r->log_level, r->log, 0,
2494                   "no A or CNAME types in DNS response");
2495     return;
2496 
2497 short_response:
2498 
2499     err = "short DNS response";
2500 
2501 invalid:
2502 
2503     /* unlock name mutex */
2504 
2505     ngx_log_error(r->log_level, r->log, 0, err);
2506 
2507     return;
2508 
2509 failed:
2510 
2511 next:
2512 
2513     /* unlock name mutex */
2514 
2515     return;
2516 }
2517 
2518 
2519 static void
2520 ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n,
2521     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan,
2522     ngx_uint_t trunc, ngx_uint_t ans)
2523 {
2524     char                       *err;
2525     u_char                     *cname;
2526     size_t                      len;
2527     int32_t                     ttl;
2528     uint32_t                    hash;
2529     ngx_str_t                   name;
2530     ngx_uint_t                  type, qident, class, start, nsrvs, a, i, j;
2531     ngx_resolver_an_t          *an;
2532     ngx_resolver_ctx_t         *ctx, *next;
2533     ngx_resolver_srv_t         *srvs;
2534     ngx_resolver_node_t        *rn;
2535     ngx_resolver_connection_t  *rec;
2536 
2537     if (ngx_resolver_copy(r, &name, buf,
2538                           buf + sizeof(ngx_resolver_hdr_t), buf + n)
2539         != NGX_OK)
2540     {
2541         return;
2542     }
2543 
2544     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
2545 
2546     hash = ngx_crc32_short(name.data, name.len);
2547 
2548     rn = ngx_resolver_lookup_srv(r, &name, hash);
2549 
2550     if (rn == NULL || rn->query == NULL) {
2551         ngx_log_error(r->log_level, r->log, 0,
2552                       "unexpected response for %V", &name);
2553         ngx_resolver_free(r, name.data);
2554         goto failed;
2555     }
2556 
2557     if (trunc && rn->tcp) {
2558         ngx_resolver_free(r, name.data);
2559         goto failed;
2560     }
2561 
2562     qident = (rn->query[0] << 8) + rn->query[1];
2563 
2564     if (ident != qident) {
2565         ngx_log_error(r->log_level, r->log, 0,
2566                       "wrong ident %ui response for %V, expect %ui",
2567                       ident, &name, qident);
2568         ngx_resolver_free(r, name.data);
2569         goto failed;
2570     }
2571 
2572     ngx_resolver_free(r, name.data);
2573 
2574     if (trunc) {
2575 
2576         ngx_queue_remove(&rn->queue);
2577 
2578         if (rn->waiting == NULL) {
2579             ngx_rbtree_delete(&r->srv_rbtree, &rn->node);
2580             ngx_resolver_free_node(r, rn);
2581             return;
2582         }
2583 
2584         rec = r->connections.elts;
2585         rec = &rec[rn->last_connection];
2586 
2587         rn->tcp = 1;
2588 
2589         (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
2590 
2591         rn->expire = ngx_time() + r->resend_timeout;
2592 
2593         ngx_queue_insert_head(&r->srv_resend_queue, &rn->queue);
2594 
2595         return;
2596     }
2597 
2598     if (code == 0 && rn->code) {
2599         code = rn->code;
2600     }
2601 
2602     if (code == 0 && nan == 0) {
2603         code = NGX_RESOLVE_NXDOMAIN;
2604     }
2605 
2606     if (code) {
2607         next = rn->waiting;
2608         rn->waiting = NULL;
2609 
2610         ngx_queue_remove(&rn->queue);
2611 
2612         ngx_rbtree_delete(&r->srv_rbtree, &rn->node);
2613 
2614         while (next) {
2615             ctx = next;
2616             ctx->state = code;
2617             ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
2618             next = ctx->next;
2619 
2620             ctx->handler(ctx);
2621         }
2622 
2623         ngx_resolver_free_node(r, rn);
2624 
2625         return;
2626     }
2627 
2628     i = ans;
2629     nsrvs = 0;
2630     cname = NULL;
2631 
2632     for (a = 0; a < nan; a++) {
2633 
2634         start = i;
2635 
2636         while (i < n) {
2637 
2638             if (buf[i] & 0xc0) {
2639                 i += 2;
2640                 goto found;
2641             }
2642 
2643             if (buf[i] == 0) {
2644                 i++;
2645                 goto test_length;
2646             }
2647 
2648             i += 1 + buf[i];
2649         }
2650 
2651         goto short_response;
2652 
2653     test_length:
2654 
2655         if (i - start < 2) {
2656             err = "invalid name DNS response";
2657             goto invalid;
2658         }
2659 
2660     found:
2661 
2662         if (i + sizeof(ngx_resolver_an_t) >= n) {
2663             goto short_response;
2664         }
2665 
2666         an = (ngx_resolver_an_t *) &buf[i];
2667 
2668         type = (an->type_hi << 8) + an->type_lo;
2669         class = (an->class_hi << 8) + an->class_lo;
2670         len = (an->len_hi << 8) + an->len_lo;
2671         ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
2672             + (an->ttl[2] << 8) + (an->ttl[3]);
2673 
2674         if (class != 1) {
2675             ngx_log_error(r->log_level, r->log, 0,
2676                           "unexpected RR class %ui", class);
2677             goto failed;
2678         }
2679 
2680         if (ttl < 0) {
2681             ttl = 0;
2682         }
2683 
2684         rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
2685 
2686         i += sizeof(ngx_resolver_an_t);
2687 
2688         switch (type) {
2689 
2690         case NGX_RESOLVE_SRV:
2691 
2692             if (i + 6 > n) {
2693                 goto short_response;
2694             }
2695 
2696             if (ngx_resolver_copy(r, NULL, buf, &buf[i + 6], buf + n)
2697                 != NGX_OK)
2698             {
2699                 goto failed;
2700             }
2701 
2702             nsrvs++;
2703 
2704             break;
2705 
2706         case NGX_RESOLVE_CNAME:
2707 
2708             cname = &buf[i];
2709 
2710             break;
2711 
2712         case NGX_RESOLVE_DNAME:
2713 
2714             break;
2715 
2716         default:
2717 
2718             ngx_log_error(r->log_level, r->log, 0,
2719                           "unexpected RR type %ui", type);
2720         }
2721 
2722         i += len;
2723     }
2724 
2725     ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
2726                    "resolver nsrvs:%ui cname:%p ttl:%uD",
2727                    nsrvs, cname, rn->ttl);
2728 
2729     if (nsrvs) {
2730 
2731         srvs = ngx_resolver_calloc(r, nsrvs * sizeof(ngx_resolver_srv_t));
2732         if (srvs == NULL) {
2733             goto failed;
2734         }
2735 
2736         rn->u.srvs = srvs;
2737         rn->nsrvs = (u_short) nsrvs;
2738 
2739         j = 0;
2740         i = ans;
2741 
2742         for (a = 0; a < nan; a++) {
2743 
2744             for ( ;; ) {
2745 
2746                 if (buf[i] & 0xc0) {
2747                     i += 2;
2748                     break;
2749                 }
2750 
2751                 if (buf[i] == 0) {
2752                     i++;
2753                     break;
2754                 }
2755 
2756                 i += 1 + buf[i];
2757             }
2758 
2759             an = (ngx_resolver_an_t *) &buf[i];
2760 
2761             type = (an->type_hi << 8) + an->type_lo;
2762             len = (an->len_hi << 8) + an->len_lo;
2763 
2764             i += sizeof(ngx_resolver_an_t);
2765 
2766             if (type == NGX_RESOLVE_SRV) {
2767 
2768                 srvs[j].priority = (buf[i] << 8) + buf[i + 1];
2769                 srvs[j].weight = (buf[i + 2] << 8) + buf[i + 3];
2770 
2771                 if (srvs[j].weight == 0) {
2772                     srvs[j].weight = 1;
2773                 }
2774 
2775                 srvs[j].port = (buf[i + 4] << 8) + buf[i + 5];
2776 
2777                 if (ngx_resolver_copy(r, &srvs[j].name, buf, &buf[i + 6],
2778                                       buf + n)
2779                     != NGX_OK)
2780                 {
2781                     goto failed;
2782                 }
2783 
2784                 j++;
2785             }
2786 
2787             i += len;
2788         }
2789 
2790         ngx_sort(srvs, nsrvs, sizeof(ngx_resolver_srv_t),
2791                  ngx_resolver_cmp_srvs);
2792 
2793         ngx_resolver_free(r, rn->query);
2794         rn->query = NULL;
2795 
2796         ngx_queue_remove(&rn->queue);
2797 
2798         rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2799         rn->expire = ngx_time() + r->expire;
2800 
2801         ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue);
2802 
2803         next = rn->waiting;
2804         rn->waiting = NULL;
2805 
2806         while (next) {
2807             ctx = next;
2808             next = ctx->next;
2809 
2810             ngx_resolver_resolve_srv_names(ctx, rn);
2811         }
2812 
2813         return;
2814     }
2815 
2816     rn->nsrvs = 0;
2817 
2818     if (cname) {
2819 
2820         /* CNAME only */
2821 
2822         if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) {
2823             goto failed;
2824         }
2825 
2826         ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
2827                        "resolver cname:\"%V\"", &name);
2828 
2829         ngx_queue_remove(&rn->queue);
2830 
2831         rn->cnlen = (u_short) name.len;
2832         rn->u.cname = name.data;
2833 
2834         rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2835         rn->expire = ngx_time() + r->expire;
2836 
2837         ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue);
2838 
2839         ngx_resolver_free(r, rn->query);
2840         rn->query = NULL;
2841 #if (NGX_HAVE_INET6)
2842         rn->query6 = NULL;
2843 #endif
2844 
2845         ctx = rn->waiting;
2846         rn->waiting = NULL;
2847 
2848         if (ctx) {
2849 
2850             if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
2851 
2852                 /* unlock name mutex */
2853 
2854                 do {
2855                     ctx->state = NGX_RESOLVE_NXDOMAIN;
2856                     next = ctx->next;
2857 
2858                     ctx->handler(ctx);
2859 
2860                     ctx = next;
2861                 } while (ctx);
2862 
2863                 return;
2864             }
2865 
2866             for (next = ctx; next; next = next->next) {
2867                 next->node = NULL;
2868             }
2869 
2870             (void) ngx_resolve_name_locked(r, ctx, &name);
2871         }
2872 
2873         /* unlock name mutex */
2874 
2875         return;
2876     }
2877 
2878     ngx_log_error(r->log_level, r->log, 0, "no SRV type in DNS response");
2879 
2880     return;
2881 
2882 short_response:
2883 
2884     err = "short DNS response";
2885 
2886 invalid:
2887 
2888     /* unlock name mutex */
2889 
2890     ngx_log_error(r->log_level, r->log, 0, err);
2891 
2892     return;
2893 
2894 failed:
2895 
2896     /* unlock name mutex */
2897 
2898     return;
2899 }
2900 
2901 
2902 static void
2903 ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx, ngx_resolver_node_t *rn)
2904 {
2905     ngx_uint_t                i;
2906     ngx_resolver_t           *r;
2907     ngx_resolver_ctx_t       *cctx;
2908     ngx_resolver_srv_name_t  *srvs;
2909 
2910     r = ctx->resolver;
2911 
2912     ctx->node = NULL;
2913     ctx->state = NGX_OK;
2914     ctx->valid = rn->valid;
2915     ctx->count = rn->nsrvs;
2916 
2917     srvs = ngx_resolver_calloc(r, rn->nsrvs * sizeof(ngx_resolver_srv_name_t));
2918     if (srvs == NULL) {
2919         goto failed;
2920     }
2921 
2922     ctx->srvs = srvs;
2923     ctx->nsrvs = rn->nsrvs;
2924 
2925     if (ctx->event && ctx->event->timer_set) {
2926         ngx_del_timer(ctx->event);
2927     }
2928 
2929     for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
2930         srvs[i].name.data = ngx_resolver_alloc(r, rn->u.srvs[i].name.len);
2931         if (srvs[i].name.data == NULL) {
2932             goto failed;
2933         }
2934 
2935         srvs[i].name.len = rn->u.srvs[i].name.len;
2936         ngx_memcpy(srvs[i].name.data, rn->u.srvs[i].name.data,
2937                    srvs[i].name.len);
2938 
2939         cctx = ngx_resolve_start(r, NULL);
2940         if (cctx == NULL) {
2941             goto failed;
2942         }
2943 
2944         cctx->name = srvs[i].name;
2945         cctx->handler = ngx_resolver_srv_names_handler;
2946         cctx->data = ctx;
2947         cctx->srvs = &srvs[i];
2948         cctx->timeout = ctx->timeout;
2949 
2950         srvs[i].priority = rn->u.srvs[i].priority;
2951         srvs[i].weight = rn->u.srvs[i].weight;
2952         srvs[i].port = rn->u.srvs[i].port;
2953         srvs[i].ctx = cctx;
2954 
2955         if (ngx_resolve_name(cctx) == NGX_ERROR) {
2956             srvs[i].ctx = NULL;
2957             goto failed;
2958         }
2959     }
2960 
2961     return;
2962 
2963 failed:
2964 
2965     ctx->state = NGX_ERROR;
2966     ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
2967 
2968     ctx->handler(ctx);
2969 }
2970 
2971 
2972 static void
2973 ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx)
2974 {
2975     ngx_uint_t                i;
2976     ngx_addr_t               *addrs;
2977     ngx_resolver_t           *r;
2978     ngx_sockaddr_t           *sockaddr;
2979     ngx_resolver_ctx_t       *ctx;
2980     ngx_resolver_srv_name_t  *srv;
2981 
2982     r = cctx->resolver;
2983     ctx = cctx->data;
2984     srv = cctx->srvs;
2985 
2986     ctx->count--;
2987     ctx->async |= cctx->async;
2988 
2989     srv->ctx = NULL;
2990     srv->state = cctx->state;
2991 
2992     if (cctx->naddrs) {
2993 
2994         ctx->valid = ngx_min(ctx->valid, cctx->valid);
2995 
2996         addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t));
2997         if (addrs == NULL) {
2998             srv->state = NGX_ERROR;
2999             goto done;
3000         }
3001 
3002         sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t));
3003         if (sockaddr == NULL) {
3004             ngx_resolver_free(r, addrs);
3005             srv->state = NGX_ERROR;
3006             goto done;
3007         }
3008 
3009         for (i = 0; i < cctx->naddrs; i++) {
3010             addrs[i].sockaddr = &sockaddr[i].sockaddr;
3011             addrs[i].socklen = cctx->addrs[i].socklen;
3012 
3013             ngx_memcpy(&sockaddr[i], cctx->addrs[i].sockaddr,
3014                        addrs[i].socklen);
3015 
3016             ngx_inet_set_port(addrs[i].sockaddr, srv->port);
3017         }
3018 
3019         srv->addrs = addrs;
3020         srv->naddrs = cctx->naddrs;
3021     }
3022 
3023 done:
3024 
3025     ngx_resolve_name_done(cctx);
3026 
3027     if (ctx->count == 0) {
3028         ngx_resolver_report_srv(r, ctx);
3029     }
3030 }
3031 
3032 
3033 static void
3034 ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
3035     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
3036 {
3037     char                 *err;
3038     size_t                len;
3039     in_addr_t             addr;
3040     int32_t               ttl;
3041     ngx_int_t             octet;
3042     ngx_str_t             name;
3043     ngx_uint_t            mask, type, class, qident, a, i, start;
3044     ngx_queue_t          *expire_queue;
3045     ngx_rbtree_t         *tree;
3046     ngx_resolver_an_t    *an;
3047     ngx_resolver_ctx_t   *ctx, *next;
3048     ngx_resolver_node_t  *rn;
3049 #if (NGX_HAVE_INET6)
3050     uint32_t              hash;
3051     ngx_int_t             digit;
3052     struct in6_addr       addr6;
3053 #endif
3054 
3055     if (ngx_resolver_copy(r, &name, buf,
3056                           buf + sizeof(ngx_resolver_hdr_t), buf + n)
3057         != NGX_OK)
3058     {
3059         return;
3060     }
3061 
3062     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
3063 
3064     /* AF_INET */
3065 
3066     addr = 0;
3067     i = sizeof(ngx_resolver_hdr_t);
3068 
3069     for (mask = 0; mask < 32; mask += 8) {
3070         len = buf[i++];
3071 
3072         octet = ngx_atoi(&buf[i], len);
3073         if (octet == NGX_ERROR || octet > 255) {
3074             goto invalid_in_addr_arpa;
3075         }
3076 
3077         addr += octet << mask;
3078         i += len;
3079     }
3080 
3081     if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) {
3082         i += sizeof("\7in-addr\4arpa");
3083 
3084         /* lock addr mutex */
3085 
3086         rn = ngx_resolver_lookup_addr(r, addr);
3087 
3088         tree = &r->addr_rbtree;
3089         expire_queue = &r->addr_expire_queue;
3090 
3091         goto valid;
3092     }
3093 
3094 invalid_in_addr_arpa:
3095 
3096 #if (NGX_HAVE_INET6)
3097 
3098     i = sizeof(ngx_resolver_hdr_t);
3099 
3100     for (octet = 15; octet >= 0; octet--) {
3101         if (buf[i++] != '\1') {
3102             goto invalid_ip6_arpa;
3103         }
3104 
3105         digit = ngx_hextoi(&buf[i++], 1);
3106         if (digit == NGX_ERROR) {
3107             goto invalid_ip6_arpa;
3108         }
3109 
3110         addr6.s6_addr[octet] = (u_char) digit;
3111 
3112         if (buf[i++] != '\1') {
3113             goto invalid_ip6_arpa;
3114         }
3115 
3116         digit = ngx_hextoi(&buf[i++], 1);
3117         if (digit == NGX_ERROR) {
3118             goto invalid_ip6_arpa;
3119         }
3120 
3121         addr6.s6_addr[octet] += (u_char) (digit * 16);
3122     }
3123 
3124     if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) {
3125         i += sizeof("\3ip6\4arpa");
3126 
3127         /* lock addr mutex */
3128 
3129         hash = ngx_crc32_short(addr6.s6_addr, 16);
3130         rn = ngx_resolver_lookup_addr6(r, &addr6, hash);
3131 
3132         tree = &r->addr6_rbtree;
3133         expire_queue = &r->addr6_expire_queue;
3134 
3135         goto valid;
3136     }
3137 
3138 invalid_ip6_arpa:
3139 #endif
3140 
3141     ngx_log_error(r->log_level, r->log, 0,
3142                   "invalid in-addr.arpa or ip6.arpa name in DNS response");
3143     ngx_resolver_free(r, name.data);
3144     return;
3145 
3146 valid:
3147 
3148     if (rn == NULL || rn->query == NULL) {
3149         ngx_log_error(r->log_level, r->log, 0,
3150                       "unexpected response for %V", &name);
3151         ngx_resolver_free(r, name.data);
3152         goto failed;
3153     }
3154 
3155     qident = (rn->query[0] << 8) + rn->query[1];
3156 
3157     if (ident != qident) {
3158         ngx_log_error(r->log_level, r->log, 0,
3159                       "wrong ident %ui response for %V, expect %ui",
3160                       ident, &name, qident);
3161         ngx_resolver_free(r, name.data);
3162         goto failed;
3163     }
3164 
3165     ngx_resolver_free(r, name.data);
3166 
3167     if (code == 0 && nan == 0) {
3168         code = NGX_RESOLVE_NXDOMAIN;
3169     }
3170 
3171     if (code) {
3172         next = rn->waiting;
3173         rn->waiting = NULL;
3174 
3175         ngx_queue_remove(&rn->queue);
3176 
3177         ngx_rbtree_delete(tree, &rn->node);
3178 
3179         /* unlock addr mutex */
3180 
3181         while (next) {
3182             ctx = next;
3183             ctx->state = code;
3184             ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
3185             next = ctx->next;
3186 
3187             ctx->handler(ctx);
3188         }
3189 
3190         ngx_resolver_free_node(r, rn);
3191 
3192         return;
3193     }
3194 
3195     i += sizeof(ngx_resolver_qs_t);
3196 
3197     for (a = 0; a < nan; a++) {
3198 
3199         start = i;
3200 
3201         while (i < n) {
3202 
3203             if (buf[i] & 0xc0) {
3204                 i += 2;
3205                 goto found;
3206             }
3207 
3208             if (buf[i] == 0) {
3209                 i++;
3210                 goto test_length;
3211             }
3212 
3213             i += 1 + buf[i];
3214         }
3215 
3216         goto short_response;
3217 
3218     test_length:
3219 
3220         if (i - start < 2) {
3221             err = "invalid name in DNS response";
3222             goto invalid;
3223         }
3224 
3225     found:
3226 
3227         if (i + sizeof(ngx_resolver_an_t) >= n) {
3228             goto short_response;
3229         }
3230 
3231         an = (ngx_resolver_an_t *) &buf[i];
3232 
3233         type = (an->type_hi << 8) + an->type_lo;
3234         class = (an->class_hi << 8) + an->class_lo;
3235         len = (an->len_hi << 8) + an->len_lo;
3236         ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
3237             + (an->ttl[2] << 8) + (an->ttl[3]);
3238 
3239         if (class != 1) {
3240             ngx_log_error(r->log_level, r->log, 0,
3241                           "unexpected RR class %ui", class);
3242             goto failed;
3243         }
3244 
3245         if (ttl < 0) {
3246             ttl = 0;
3247         }
3248 
3249         ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
3250                       "resolver qt:%ui cl:%ui len:%uz",
3251                       type, class, len);
3252 
3253         i += sizeof(ngx_resolver_an_t);
3254 
3255         switch (type) {
3256 
3257         case NGX_RESOLVE_PTR:
3258 
3259             goto ptr;
3260 
3261         case NGX_RESOLVE_CNAME:
3262 
3263             break;
3264 
3265         default:
3266 
3267             ngx_log_error(r->log_level, r->log, 0,
3268                           "unexpected RR type %ui", type);
3269         }
3270 
3271         i += len;
3272     }
3273 
3274     /* unlock addr mutex */
3275 
3276     ngx_log_error(r->log_level, r->log, 0,
3277                   "no PTR type in DNS response");
3278     return;
3279 
3280 ptr:
3281 
3282     if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) {
3283         goto failed;
3284     }
3285 
3286     ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
3287 
3288     if (name.len != (size_t) rn->nlen
3289         || ngx_strncmp(name.data, rn->name, name.len) != 0)
3290     {
3291         if (rn->nlen) {
3292             ngx_resolver_free(r, rn->name);
3293         }
3294 
3295         rn->nlen = (u_short) name.len;
3296         rn->name = name.data;
3297 
3298         name.data = ngx_resolver_dup(r, rn->name, name.len);
3299         if (name.data == NULL) {
3300             goto failed;
3301         }
3302     }
3303 
3304     ngx_queue_remove(&rn->queue);
3305 
3306     rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
3307     rn->expire = ngx_time() + r->expire;
3308 
3309     ngx_queue_insert_head(expire_queue, &rn->queue);
3310 
3311     next = rn->waiting;
3312     rn->waiting = NULL;
3313 
3314     /* unlock addr mutex */
3315 
3316     while (next) {
3317         ctx = next;
3318         ctx->state = NGX_OK;
3319         ctx->valid = rn->valid;
3320         ctx->name = name;
3321         next = ctx->next;
3322 
3323         ctx->handler(ctx);
3324     }
3325 
3326     ngx_resolver_free(r, name.data);
3327 
3328     return;
3329 
3330 short_response:
3331 
3332     err = "short DNS response";
3333 
3334 invalid:
3335 
3336     /* unlock addr mutex */
3337 
3338     ngx_log_error(r->log_level, r->log, 0, err);
3339 
3340     return;
3341 
3342 failed:
3343 
3344     /* unlock addr mutex */
3345 
3346     return;
3347 }
3348 
3349 
3350 static ngx_resolver_node_t *
3351 ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
3352 {
3353     ngx_int_t             rc;
3354     ngx_rbtree_node_t    *node, *sentinel;
3355     ngx_resolver_node_t  *rn;
3356 
3357     node = r->name_rbtree.root;
3358     sentinel = r->name_rbtree.sentinel;
3359 
3360     while (node != sentinel) {
3361 
3362         if (hash < node->key) {
3363             node = node->left;
3364             continue;
3365         }
3366 
3367         if (hash > node->key) {
3368             node = node->right;
3369             continue;
3370         }
3371 
3372         /* hash == node->key */
3373 
3374         rn = ngx_resolver_node(node);
3375 
3376         rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
3377 
3378         if (rc == 0) {
3379             return rn;
3380         }
3381 
3382         node = (rc < 0) ? node->left : node->right;
3383     }
3384 
3385     /* not found */
3386 
3387     return NULL;
3388 }
3389 
3390 
3391 static ngx_resolver_node_t *
3392 ngx_resolver_lookup_srv(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
3393 {
3394     ngx_int_t             rc;
3395     ngx_rbtree_node_t    *node, *sentinel;
3396     ngx_resolver_node_t  *rn;
3397 
3398     node = r->srv_rbtree.root;
3399     sentinel = r->srv_rbtree.sentinel;
3400 
3401     while (node != sentinel) {
3402 
3403         if (hash < node->key) {
3404             node = node->left;
3405             continue;
3406         }
3407 
3408         if (hash > node->key) {
3409             node = node->right;
3410             continue;
3411         }
3412 
3413         /* hash == node->key */
3414 
3415         rn = ngx_resolver_node(node);
3416 
3417         rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
3418 
3419         if (rc == 0) {
3420             return rn;
3421         }
3422 
3423         node = (rc < 0) ? node->left : node->right;
3424     }
3425 
3426     /* not found */
3427 
3428     return NULL;
3429 }
3430 
3431 
3432 static ngx_resolver_node_t *
3433 ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
3434 {
3435     ngx_rbtree_node_t  *node, *sentinel;
3436 
3437     node = r->addr_rbtree.root;
3438     sentinel = r->addr_rbtree.sentinel;
3439 
3440     while (node != sentinel) {
3441 
3442         if (addr < node->key) {
3443             node = node->left;
3444             continue;
3445         }
3446 
3447         if (addr > node->key) {
3448             node = node->right;
3449             continue;
3450         }
3451 
3452         /* addr == node->key */
3453 
3454         return ngx_resolver_node(node);
3455     }
3456 
3457     /* not found */
3458 
3459     return NULL;
3460 }
3461 
3462 
3463 #if (NGX_HAVE_INET6)
3464 
3465 static ngx_resolver_node_t *
3466 ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr,
3467     uint32_t hash)
3468 {
3469     ngx_int_t             rc;
3470     ngx_rbtree_node_t    *node, *sentinel;
3471     ngx_resolver_node_t  *rn;
3472 
3473     node = r->addr6_rbtree.root;
3474     sentinel = r->addr6_rbtree.sentinel;
3475 
3476     while (node != sentinel) {
3477 
3478         if (hash < node->key) {
3479             node = node->left;
3480             continue;
3481         }
3482 
3483         if (hash > node->key) {
3484             node = node->right;
3485             continue;
3486         }
3487 
3488         /* hash == node->key */
3489 
3490         rn = ngx_resolver_node(node);
3491 
3492         rc = ngx_memcmp(addr, &rn->addr6, 16);
3493 
3494         if (rc == 0) {
3495             return rn;
3496         }
3497 
3498         node = (rc < 0) ? node->left : node->right;
3499     }
3500 
3501     /* not found */
3502 
3503     return NULL;
3504 }
3505 
3506 #endif
3507 
3508 
3509 static void
3510 ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
3511     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
3512 {
3513     ngx_rbtree_node_t    **p;
3514     ngx_resolver_node_t   *rn, *rn_temp;
3515 
3516     for ( ;; ) {
3517 
3518         if (node->key < temp->key) {
3519 
3520             p = &temp->left;
3521 
3522         } else if (node->key > temp->key) {
3523 
3524             p = &temp->right;
3525 
3526         } else { /* node->key == temp->key */
3527 
3528             rn = ngx_resolver_node(node);
3529             rn_temp = ngx_resolver_node(temp);
3530 
3531             p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)
3532                  < 0) ? &temp->left : &temp->right;
3533         }
3534 
3535         if (*p == sentinel) {
3536             break;
3537         }
3538 
3539         temp = *p;
3540     }
3541 
3542     *p = node;
3543     node->parent = temp;
3544     node->left = sentinel;
3545     node->right = sentinel;
3546     ngx_rbt_red(node);
3547 }
3548 
3549 
3550 #if (NGX_HAVE_INET6)
3551 
3552 static void
3553 ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
3554     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
3555 {
3556     ngx_rbtree_node_t    **p;
3557     ngx_resolver_node_t   *rn, *rn_temp;
3558 
3559     for ( ;; ) {
3560 
3561         if (node->key < temp->key) {
3562 
3563             p = &temp->left;
3564 
3565         } else if (node->key > temp->key) {
3566 
3567             p = &temp->right;
3568 
3569         } else { /* node->key == temp->key */
3570 
3571             rn = ngx_resolver_node(node);
3572             rn_temp = ngx_resolver_node(temp);
3573 
3574             p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16)
3575                  < 0) ? &temp->left : &temp->right;
3576         }
3577 
3578         if (*p == sentinel) {
3579             break;
3580         }
3581 
3582         temp = *p;
3583     }
3584 
3585     *p = node;
3586     node->parent = temp;
3587     node->left = sentinel;
3588     node->right = sentinel;
3589     ngx_rbt_red(node);
3590 }
3591 
3592 #endif
3593 
3594 
3595 static ngx_int_t
3596 ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
3597     ngx_str_t *name)
3598 {
3599     u_char              *p, *s;
3600     size_t               len, nlen;
3601     ngx_uint_t           ident;
3602     ngx_resolver_qs_t   *qs;
3603     ngx_resolver_hdr_t  *query;
3604 
3605     nlen = name->len ? (1 + name->len + 1) : 1;
3606 
3607     len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
3608 
3609 #if (NGX_HAVE_INET6)
3610     p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len);
3611 #else
3612     p = ngx_resolver_alloc(r, len);
3613 #endif
3614     if (p == NULL) {
3615         return NGX_ERROR;
3616     }
3617 
3618     rn->qlen = (u_short) len;
3619     rn->query = p;
3620 
3621 #if (NGX_HAVE_INET6)
3622     if (r->ipv6) {
3623         rn->query6 = p + len;
3624     }
3625 #endif
3626 
3627     query = (ngx_resolver_hdr_t *) p;
3628 
3629     ident = ngx_random();
3630 
3631     ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
3632                    "resolve: \"%V\" A %i", name, ident & 0xffff);
3633 
3634     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3635     query->ident_lo = (u_char) (ident & 0xff);
3636 
3637     /* recursion query */
3638     query->flags_hi = 1; query->flags_lo = 0;
3639 
3640     /* one question */
3641     query->nqs_hi = 0; query->nqs_lo = 1;
3642     query->nan_hi = 0; query->nan_lo = 0;
3643     query->nns_hi = 0; query->nns_lo = 0;
3644     query->nar_hi = 0; query->nar_lo = 0;
3645 
3646     p += sizeof(ngx_resolver_hdr_t) + nlen;
3647 
3648     qs = (ngx_resolver_qs_t *) p;
3649 
3650     /* query type */
3651     qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A;
3652 
3653     /* IN query class */
3654     qs->class_hi = 0; qs->class_lo = 1;
3655 
3656     /* convert "www.example.com" to "\3www\7example\3com\0" */
3657 
3658     len = 0;
3659     p--;
3660     *p-- = '\0';
3661 
3662     if (name->len == 0)  {
3663         return NGX_DECLINED;
3664     }
3665 
3666     for (s = name->data + name->len - 1; s >= name->data; s--) {
3667         if (*s != '.') {
3668             *p = *s;
3669             len++;
3670 
3671         } else {
3672             if (len == 0 || len > 255) {
3673                 return NGX_DECLINED;
3674             }
3675 
3676             *p = (u_char) len;
3677             len = 0;
3678         }
3679 
3680         p--;
3681     }
3682 
3683     if (len == 0 || len > 255) {
3684         return NGX_DECLINED;
3685     }
3686 
3687     *p = (u_char) len;
3688 
3689 #if (NGX_HAVE_INET6)
3690     if (!r->ipv6) {
3691         return NGX_OK;
3692     }
3693 
3694     p = rn->query6;
3695 
3696     ngx_memcpy(p, rn->query, rn->qlen);
3697 
3698     query = (ngx_resolver_hdr_t *) p;
3699 
3700     ident = ngx_random();
3701 
3702     ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
3703                    "resolve: \"%V\" AAAA %i", name, ident & 0xffff);
3704 
3705     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3706     query->ident_lo = (u_char) (ident & 0xff);
3707 
3708     p += sizeof(ngx_resolver_hdr_t) + nlen;
3709 
3710     qs = (ngx_resolver_qs_t *) p;
3711 
3712     qs->type_lo = NGX_RESOLVE_AAAA;
3713 #endif
3714 
3715     return NGX_OK;
3716 }
3717 
3718 
3719 static ngx_int_t
3720 ngx_resolver_create_srv_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
3721     ngx_str_t *name)
3722 {
3723     u_char              *p, *s;
3724     size_t               len, nlen;
3725     ngx_uint_t           ident;
3726     ngx_resolver_qs_t   *qs;
3727     ngx_resolver_hdr_t  *query;
3728 
3729     nlen = name->len ? (1 + name->len + 1) : 1;
3730 
3731     len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
3732 
3733     p = ngx_resolver_alloc(r, len);
3734     if (p == NULL) {
3735         return NGX_ERROR;
3736     }
3737 
3738     rn->qlen = (u_short) len;
3739     rn->query = p;
3740 
3741     query = (ngx_resolver_hdr_t *) p;
3742 
3743     ident = ngx_random();
3744 
3745     ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
3746                    "resolve: \"%V\" SRV %i", name, ident & 0xffff);
3747 
3748     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3749     query->ident_lo = (u_char) (ident & 0xff);
3750 
3751     /* recursion query */
3752     query->flags_hi = 1; query->flags_lo = 0;
3753 
3754     /* one question */
3755     query->nqs_hi = 0; query->nqs_lo = 1;
3756     query->nan_hi = 0; query->nan_lo = 0;
3757     query->nns_hi = 0; query->nns_lo = 0;
3758     query->nar_hi = 0; query->nar_lo = 0;
3759 
3760     p += sizeof(ngx_resolver_hdr_t) + nlen;
3761 
3762     qs = (ngx_resolver_qs_t *) p;
3763 
3764     /* query type */
3765     qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_SRV;
3766 
3767     /* IN query class */
3768     qs->class_hi = 0; qs->class_lo = 1;
3769 
3770     /* converts "www.example.com" to "\3www\7example\3com\0" */
3771 
3772     len = 0;
3773     p--;
3774     *p-- = '\0';
3775 
3776     if (name->len == 0)  {
3777         return NGX_DECLINED;
3778     }
3779 
3780     for (s = name->data + name->len - 1; s >= name->data; s--) {
3781         if (*s != '.') {
3782             *p = *s;
3783             len++;
3784 
3785         } else {
3786             if (len == 0 || len > 255) {
3787                 return NGX_DECLINED;
3788             }
3789 
3790             *p = (u_char) len;
3791             len = 0;
3792         }
3793 
3794         p--;
3795     }
3796 
3797     if (len == 0 || len > 255) {
3798         return NGX_DECLINED;
3799     }
3800 
3801     *p = (u_char) len;
3802 
3803     return NGX_OK;
3804 }
3805 
3806 
3807 static ngx_int_t
3808 ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
3809     ngx_resolver_addr_t *addr)
3810 {
3811     u_char               *p, *d;
3812     size_t                len;
3813     in_addr_t             inaddr;
3814     ngx_int_t             n;
3815     ngx_uint_t            ident;
3816     ngx_resolver_hdr_t   *query;
3817     struct sockaddr_in   *sin;
3818 #if (NGX_HAVE_INET6)
3819     struct sockaddr_in6  *sin6;
3820 #endif
3821 
3822     switch (addr->sockaddr->sa_family) {
3823 
3824 #if (NGX_HAVE_INET6)
3825     case AF_INET6:
3826         len = sizeof(ngx_resolver_hdr_t)
3827               + 64 + sizeof(".ip6.arpa.") - 1
3828               + sizeof(ngx_resolver_qs_t);
3829 
3830         break;
3831 #endif
3832 
3833     default: /* AF_INET */
3834         len = sizeof(ngx_resolver_hdr_t)
3835               + sizeof(".255.255.255.255.in-addr.arpa.") - 1
3836               + sizeof(ngx_resolver_qs_t);
3837     }
3838 
3839     p = ngx_resolver_alloc(r, len);
3840     if (p == NULL) {
3841         return NGX_ERROR;
3842     }
3843 
3844     rn->query = p;
3845     query = (ngx_resolver_hdr_t *) p;
3846 
3847     ident = ngx_random();
3848 
3849     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3850     query->ident_lo = (u_char) (ident & 0xff);
3851 
3852     /* recursion query */
3853     query->flags_hi = 1; query->flags_lo = 0;
3854 
3855     /* one question */
3856     query->nqs_hi = 0; query->nqs_lo = 1;
3857     query->nan_hi = 0; query->nan_lo = 0;
3858     query->nns_hi = 0; query->nns_lo = 0;
3859     query->nar_hi = 0; query->nar_lo = 0;
3860 
3861     p += sizeof(ngx_resolver_hdr_t);
3862 
3863     switch (addr->sockaddr->sa_family) {
3864 
3865 #if (NGX_HAVE_INET6)
3866     case AF_INET6:
3867         sin6 = (struct sockaddr_in6 *) addr->sockaddr;
3868 
3869         for (n = 15; n >= 0; n--) {
3870             p = ngx_sprintf(p, "\1%xd\1%xd",
3871                             sin6->sin6_addr.s6_addr[n] & 0xf,
3872                             (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf);
3873         }
3874 
3875         p = ngx_cpymem(p, "\3ip6\4arpa\0", 10);
3876 
3877         break;
3878 #endif
3879 
3880     default: /* AF_INET */
3881 
3882         sin = (struct sockaddr_in *) addr->sockaddr;
3883         inaddr = ntohl(sin->sin_addr.s_addr);
3884 
3885         for (n = 0; n < 32; n += 8) {
3886             d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff);
3887             *p = (u_char) (d - &p[1]);
3888             p = d;
3889         }
3890 
3891         p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14);
3892     }
3893 
3894     /* query type "PTR", IN query class */
3895     p = ngx_cpymem(p, "\0\14\0\1", 4);
3896 
3897     rn->qlen = (u_short) (p - rn->query);
3898 
3899     return NGX_OK;
3900 }
3901 
3902 
3903 static ngx_int_t
3904 ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src,
3905     u_char *last)
3906 {
3907     char        *err;
3908     u_char      *p, *dst;
3909     ssize_t      len;
3910     ngx_uint_t   i, n;
3911 
3912     p = src;
3913     len = -1;
3914 
3915     /*
3916      * compression pointers allow to create endless loop, so we set limit;
3917      * 128 pointers should be enough to store 255-byte name
3918      */
3919 
3920     for (i = 0; i < 128; i++) {
3921         n = *p++;
3922 
3923         if (n == 0) {
3924             goto done;
3925         }
3926 
3927         if (n & 0xc0) {
3928             n = ((n & 0x3f) << 8) + *p;
3929             p = &buf[n];
3930 
3931         } else {
3932             len += 1 + n;
3933             p = &p[n];
3934         }
3935 
3936         if (p >= last) {
3937             err = "name is out of response";
3938             goto invalid;
3939         }
3940     }
3941 
3942     err = "compression pointers loop";
3943 
3944 invalid:
3945 
3946     ngx_log_error(r->log_level, r->log, 0, err);
3947 
3948     return NGX_ERROR;
3949 
3950 done:
3951 
3952     if (name == NULL) {
3953         return NGX_OK;
3954     }
3955 
3956     if (len == -1) {
3957         ngx_str_null(name);
3958         return NGX_OK;
3959     }
3960 
3961     dst = ngx_resolver_alloc(r, len);
3962     if (dst == NULL) {
3963         return NGX_ERROR;
3964     }
3965 
3966     name->data = dst;
3967 
3968     n = *src++;
3969 
3970     for ( ;; ) {
3971         if (n & 0xc0) {
3972             n = ((n & 0x3f) << 8) + *src;
3973             src = &buf[n];
3974 
3975             n = *src++;
3976 
3977         } else {
3978             ngx_strlow(dst, src, n);
3979             dst += n;
3980             src += n;
3981 
3982             n = *src++;
3983 
3984             if (n != 0) {
3985                 *dst++ = '.';
3986             }
3987         }
3988 
3989         if (n == 0) {
3990             name->len = dst - name->data;
3991             return NGX_OK;
3992         }
3993     }
3994 }
3995 
3996 
3997 static ngx_int_t
3998 ngx_resolver_set_timeout(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
3999 {
4000     if (ctx->event || ctx->timeout == 0) {
4001         return NGX_OK;
4002     }
4003 
4004     ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
4005     if (ctx->event == NULL) {
4006         return NGX_ERROR;
4007     }
4008 
4009     ctx->event->handler = ngx_resolver_timeout_handler;
4010     ctx->event->data = ctx;
4011     ctx->event->log = r->log;
4012     ctx->event->cancelable = ctx->cancelable;
4013     ctx->ident = -1;
4014 
4015     ngx_add_timer(ctx->event, ctx->timeout);
4016 
4017     return NGX_OK;
4018 }
4019 
4020 
4021 static void
4022 ngx_resolver_timeout_handler(ngx_event_t *ev)
4023 {
4024     ngx_resolver_ctx_t  *ctx;
4025 
4026     ctx = ev->data;
4027 
4028     ctx->state = NGX_RESOLVE_TIMEDOUT;
4029 
4030     ctx->handler(ctx);
4031 }
4032 
4033 
4034 static void
4035 ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
4036 {
4037     ngx_uint_t  i;
4038 
4039     /* lock alloc mutex */
4040 
4041     if (rn->query) {
4042         ngx_resolver_free_locked(r, rn->query);
4043     }
4044 
4045     if (rn->name) {
4046         ngx_resolver_free_locked(r, rn->name);
4047     }
4048 
4049     if (rn->cnlen) {
4050         ngx_resolver_free_locked(r, rn->u.cname);
4051     }
4052 
4053     if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
4054         ngx_resolver_free_locked(r, rn->u.addrs);
4055     }
4056 
4057 #if (NGX_HAVE_INET6)
4058     if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
4059         ngx_resolver_free_locked(r, rn->u6.addrs6);
4060     }
4061 #endif
4062 
4063     if (rn->nsrvs) {
4064         for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
4065             if (rn->u.srvs[i].name.data) {
4066                 ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
4067             }
4068         }
4069 
4070         ngx_resolver_free_locked(r, rn->u.srvs);
4071     }
4072 
4073     ngx_resolver_free_locked(r, rn);
4074 
4075     /* unlock alloc mutex */
4076 }
4077 
4078 
4079 static void *
4080 ngx_resolver_alloc(ngx_resolver_t *r, size_t size)
4081 {
4082     u_char  *p;
4083 
4084     /* lock alloc mutex */
4085 
4086     p = ngx_alloc(size, r->log);
4087 
4088     /* unlock alloc mutex */
4089 
4090     return p;
4091 }
4092 
4093 
4094 static void *
4095 ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
4096 {
4097     u_char  *p;
4098 
4099     p = ngx_resolver_alloc(r, size);
4100 
4101     if (p) {
4102         ngx_memzero(p, size);
4103     }
4104 
4105     return p;
4106 }
4107 
4108 
4109 static void
4110 ngx_resolver_free(ngx_resolver_t *r, void *p)
4111 {
4112     /* lock alloc mutex */
4113 
4114     ngx_free(p);
4115 
4116     /* unlock alloc mutex */
4117 }
4118 
4119 
4120 static void
4121 ngx_resolver_free_locked(ngx_resolver_t *r, void *p)
4122 {
4123     ngx_free(p);
4124 }
4125 
4126 
4127 static void *
4128 ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
4129 {
4130     void  *dst;
4131 
4132     dst = ngx_resolver_alloc(r, size);
4133 
4134     if (dst == NULL) {
4135         return dst;
4136     }
4137 
4138     ngx_memcpy(dst, src, size);
4139 
4140     return dst;
4141 }
4142 
4143 
4144 static ngx_resolver_addr_t *
4145 ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn,
4146     ngx_uint_t rotate)
4147 {
4148     ngx_uint_t            d, i, j, n;
4149     in_addr_t            *addr;
4150     ngx_sockaddr_t       *sockaddr;
4151     struct sockaddr_in   *sin;
4152     ngx_resolver_addr_t  *dst;
4153 #if (NGX_HAVE_INET6)
4154     struct in6_addr      *addr6;
4155     struct sockaddr_in6  *sin6;
4156 #endif
4157 
4158     n = rn->naddrs;
4159 #if (NGX_HAVE_INET6)
4160     n += rn->naddrs6;
4161 #endif
4162 
4163     dst = ngx_resolver_calloc(r, n * sizeof(ngx_resolver_addr_t));
4164     if (dst == NULL) {
4165         return NULL;
4166     }
4167 
4168     sockaddr = ngx_resolver_calloc(r, n * sizeof(ngx_sockaddr_t));
4169     if (sockaddr == NULL) {
4170         ngx_resolver_free(r, dst);
4171         return NULL;
4172     }
4173 
4174     i = 0;
4175     d = rotate ? ngx_random() % n : 0;
4176 
4177     if (rn->naddrs) {
4178         j = rotate ? ngx_random() % rn->naddrs : 0;
4179 
4180         addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs;
4181 
4182         do {
4183             sin = &sockaddr[d].sockaddr_in;
4184             sin->sin_family = AF_INET;
4185             sin->sin_addr.s_addr = addr[j++];
4186             dst[d].sockaddr = (struct sockaddr *) sin;
4187             dst[d++].socklen = sizeof(struct sockaddr_in);
4188 
4189             if (d == n) {
4190                 d = 0;
4191             }
4192 
4193             if (j == (ngx_uint_t) rn->naddrs) {
4194                 j = 0;
4195             }
4196         } while (++i < (ngx_uint_t) rn->naddrs);
4197     }
4198 
4199 #if (NGX_HAVE_INET6)
4200     if (rn->naddrs6) {
4201         j = rotate ? ngx_random() % rn->naddrs6 : 0;
4202 
4203         addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6;
4204 
4205         do {
4206             sin6 = &sockaddr[d].sockaddr_in6;
4207             sin6->sin6_family = AF_INET6;
4208             ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16);
4209             dst[d].sockaddr = (struct sockaddr *) sin6;
4210             dst[d++].socklen = sizeof(struct sockaddr_in6);
4211 
4212             if (d == n) {
4213                 d = 0;
4214             }
4215 
4216             if (j == rn->naddrs6) {
4217                 j = 0;
4218             }
4219         } while (++i < n);
4220     }
4221 #endif
4222 
4223     return dst;
4224 }
4225 
4226 
4227 static void
4228 ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
4229 {
4230     ngx_uint_t                naddrs, nsrvs, nw, i, j, k, l, m, n, w;
4231     ngx_resolver_addr_t      *addrs;
4232     ngx_resolver_srv_name_t  *srvs;
4233 
4234     srvs = ctx->srvs;
4235     nsrvs = ctx->nsrvs;
4236 
4237     naddrs = 0;
4238 
4239     for (i = 0; i < nsrvs; i++) {
4240         if (srvs[i].state == NGX_ERROR) {
4241             ctx->state = NGX_ERROR;
4242             ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4243 
4244             ctx->handler(ctx);
4245             return;
4246         }
4247 
4248         naddrs += srvs[i].naddrs;
4249     }
4250 
4251     if (naddrs == 0) {
4252         ctx->state = NGX_RESOLVE_NXDOMAIN;
4253         ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4254 
4255         ctx->handler(ctx);
4256         return;
4257     }
4258 
4259     addrs = ngx_resolver_calloc(r, naddrs * sizeof(ngx_resolver_addr_t));
4260     if (addrs == NULL) {
4261         ctx->state = NGX_ERROR;
4262         ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4263 
4264         ctx->handler(ctx);
4265         return;
4266     }
4267 
4268     i = 0;
4269     n = 0;
4270 
4271     do {
4272         nw = 0;
4273 
4274         for (j = i; j < nsrvs; j++) {
4275             if (srvs[j].priority != srvs[i].priority) {
4276                 break;
4277             }
4278 
4279             nw += srvs[j].naddrs * srvs[j].weight;
4280         }
4281 
4282         if (nw == 0) {
4283             goto next_srv;
4284         }
4285 
4286         w = ngx_random() % nw;
4287 
4288         for (k = i; k < j; k++) {
4289             if (w < srvs[k].naddrs * srvs[k].weight) {
4290                 break;
4291             }
4292 
4293             w -= srvs[k].naddrs * srvs[k].weight;
4294         }
4295 
4296         for (l = i; l < j; l++) {
4297 
4298             for (m = 0; m < srvs[k].naddrs; m++) {
4299                 addrs[n].socklen = srvs[k].addrs[m].socklen;
4300                 addrs[n].sockaddr = srvs[k].addrs[m].sockaddr;
4301                 addrs[n].name = srvs[k].name;
4302                 addrs[n].priority = srvs[k].priority;
4303                 addrs[n].weight = srvs[k].weight;
4304                 n++;
4305             }
4306 
4307             if (++k == j) {
4308                 k = i;
4309             }
4310         }
4311 
4312 next_srv:
4313 
4314         i = j;
4315 
4316     } while (i < ctx->nsrvs);
4317 
4318     ctx->state = NGX_OK;
4319     ctx->addrs = addrs;
4320     ctx->naddrs = naddrs;
4321 
4322     ctx->handler(ctx);
4323 
4324     ngx_resolver_free(r, addrs);
4325 }
4326 
4327 
4328 char *
4329 ngx_resolver_strerror(ngx_int_t err)
4330 {
4331     static char *errors[] = {
4332         "Format error",     /* FORMERR */
4333         "Server failure",   /* SERVFAIL */
4334         "Host not found",   /* NXDOMAIN */
4335         "Unimplemented",    /* NOTIMP */
4336         "Operation refused" /* REFUSED */
4337     };
4338 
4339     if (err > 0 && err < 6) {
4340         return errors[err - 1];
4341     }
4342 
4343     if (err == NGX_RESOLVE_TIMEDOUT) {
4344         return "Operation timed out";
4345     }
4346 
4347     return "Unknown error";
4348 }
4349 
4350 
4351 static u_char *
4352 ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len)
4353 {
4354     u_char                     *p;
4355     ngx_resolver_connection_t  *rec;
4356 
4357     p = buf;
4358 
4359     if (log->action) {
4360         p = ngx_snprintf(buf, len, " while %s", log->action);
4361         len -= p - buf;
4362     }
4363 
4364     rec = log->data;
4365 
4366     if (rec) {
4367         p = ngx_snprintf(p, len, ", resolver: %V", &rec->server);
4368     }
4369 
4370     return p;
4371 }
4372 
4373 
4374 static ngx_int_t
4375 ngx_udp_connect(ngx_resolver_connection_t *rec)
4376 {
4377     int                rc;
4378     ngx_int_t          event;
4379     ngx_event_t       *rev, *wev;
4380     ngx_socket_t       s;
4381     ngx_connection_t  *c;
4382 
4383     s = ngx_socket(rec->sockaddr->sa_family, SOCK_DGRAM, 0);
4384 
4385     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "UDP socket %d", s);
4386 
4387     if (s == (ngx_socket_t) -1) {
4388         ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4389                       ngx_socket_n " failed");
4390         return NGX_ERROR;
4391     }
4392 
4393     c = ngx_get_connection(s, &rec->log);
4394 
4395     if (c == NULL) {
4396         if (ngx_close_socket(s) == -1) {
4397             ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4398                           ngx_close_socket_n "failed");
4399         }
4400 
4401         return NGX_ERROR;
4402     }
4403 
4404     if (ngx_nonblocking(s) == -1) {
4405         ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4406                       ngx_nonblocking_n " failed");
4407 
4408         goto failed;
4409     }
4410 
4411     rev = c->read;
4412     wev = c->write;
4413 
4414     rev->log = &rec->log;
4415     wev->log = &rec->log;
4416 
4417     rec->udp = c;
4418 
4419     c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
4420 
4421     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
4422                    "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
4423 
4424     rc = connect(s, rec->sockaddr, rec->socklen);
4425 
4426     /* TODO: iocp */
4427 
4428     if (rc == -1) {
4429         ngx_log_error(NGX_LOG_CRIT, &rec->log, ngx_socket_errno,
4430                       "connect() failed");
4431 
4432         goto failed;
4433     }
4434 
4435     /* UDP sockets are always ready to write */
4436     wev->ready = 1;
4437 
4438     event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
4439                 /* kqueue, epoll */                 NGX_CLEAR_EVENT:
4440                 /* select, poll, /dev/poll */       NGX_LEVEL_EVENT;
4441                 /* eventport event type has no meaning: oneshot only */
4442 
4443     if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
4444         goto failed;
4445     }
4446 
4447     return NGX_OK;
4448 
4449 failed:
4450 
4451     ngx_close_connection(c);
4452     rec->udp = NULL;
4453 
4454     return NGX_ERROR;
4455 }
4456 
4457 
4458 static ngx_int_t
4459 ngx_tcp_connect(ngx_resolver_connection_t *rec)
4460 {
4461     int                rc;
4462     ngx_int_t          event;
4463     ngx_err_t          err;
4464     ngx_uint_t         level;
4465     ngx_socket_t       s;
4466     ngx_event_t       *rev, *wev;
4467     ngx_connection_t  *c;
4468 
4469     s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM, 0);
4470 
4471     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "TCP socket %d", s);
4472 
4473     if (s == (ngx_socket_t) -1) {
4474         ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4475                       ngx_socket_n " failed");
4476         return NGX_ERROR;
4477     }
4478 
4479     c = ngx_get_connection(s, &rec->log);
4480 
4481     if (c == NULL) {
4482         if (ngx_close_socket(s) == -1) {
4483             ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4484                           ngx_close_socket_n "failed");
4485         }
4486 
4487         return NGX_ERROR;
4488     }
4489 
4490     if (ngx_nonblocking(s) == -1) {
4491         ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4492                       ngx_nonblocking_n " failed");
4493 
4494         goto failed;
4495     }
4496 
4497     rev = c->read;
4498     wev = c->write;
4499 
4500     rev->log = &rec->log;
4501     wev->log = &rec->log;
4502 
4503     rec->tcp = c;
4504 
4505     c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
4506 
4507     if (ngx_add_conn) {
4508         if (ngx_add_conn(c) == NGX_ERROR) {
4509             goto failed;
4510         }
4511     }
4512 
4513     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
4514                    "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
4515 
4516     rc = connect(s, rec->sockaddr, rec->socklen);
4517 
4518     if (rc == -1) {
4519         err = ngx_socket_errno;
4520 
4521 
4522         if (err != NGX_EINPROGRESS
4523 #if (NGX_WIN32)
4524             /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
4525             && err != NGX_EAGAIN
4526 #endif
4527             )
4528         {
4529             if (err == NGX_ECONNREFUSED
4530 #if (NGX_LINUX)
4531                 /*
4532                  * Linux returns EAGAIN instead of ECONNREFUSED
4533                  * for unix sockets if listen queue is full
4534                  */
4535                 || err == NGX_EAGAIN
4536 #endif
4537                 || err == NGX_ECONNRESET
4538                 || err == NGX_ENETDOWN
4539                 || err == NGX_ENETUNREACH
4540                 || err == NGX_EHOSTDOWN
4541                 || err == NGX_EHOSTUNREACH)
4542             {
4543                 level = NGX_LOG_ERR;
4544 
4545             } else {
4546                 level = NGX_LOG_CRIT;
4547             }
4548 
4549             ngx_log_error(level, c->log, err, "connect() to %V failed",
4550                           &rec->server);
4551 
4552             ngx_close_connection(c);
4553             rec->tcp = NULL;
4554 
4555             return NGX_ERROR;
4556         }
4557     }
4558 
4559     if (ngx_add_conn) {
4560         if (rc == -1) {
4561 
4562             /* NGX_EINPROGRESS */
4563 
4564             return NGX_AGAIN;
4565         }
4566 
4567         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
4568 
4569         wev->ready = 1;
4570 
4571         return NGX_OK;
4572     }
4573 
4574     if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
4575 
4576         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, ngx_socket_errno,
4577                        "connect(): %d", rc);
4578 
4579         if (ngx_blocking(s) == -1) {
4580             ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4581                           ngx_blocking_n " failed");
4582             goto failed;
4583         }
4584 
4585         /*
4586          * FreeBSD's aio allows to post an operation on non-connected socket.
4587          * NT does not support it.
4588          *
4589          * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
4590          */
4591 
4592         rev->ready = 1;
4593         wev->ready = 1;
4594 
4595         return NGX_OK;
4596     }
4597 
4598     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
4599 
4600         /* kqueue */
4601 
4602         event = NGX_CLEAR_EVENT;
4603 
4604     } else {
4605 
4606         /* select, poll, /dev/poll */
4607 
4608         event = NGX_LEVEL_EVENT;
4609     }
4610 
4611     if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
4612         goto failed;
4613     }
4614 
4615     if (rc == -1) {
4616 
4617         /* NGX_EINPROGRESS */
4618 
4619         if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
4620             goto failed;
4621         }
4622 
4623         return NGX_AGAIN;
4624     }
4625 
4626     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
4627 
4628     wev->ready = 1;
4629 
4630     return NGX_OK;
4631 
4632 failed:
4633 
4634     ngx_close_connection(c);
4635     rec->tcp = NULL;
4636 
4637     return NGX_ERROR;
4638 }
4639 
4640 
4641 static ngx_int_t
4642 ngx_resolver_cmp_srvs(const void *one, const void *two)
4643 {
4644     ngx_int_t            p1, p2;
4645     ngx_resolver_srv_t  *first, *second;
4646 
4647     first = (ngx_resolver_srv_t *) one;
4648     second = (ngx_resolver_srv_t *) two;
4649 
4650     p1 = first->priority;
4651     p2 = second->priority;
4652 
4653     return p1 - p2;
4654 }