Annotation of embedaddon/nginx/src/core/ngx_resolver.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>