Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

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