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