Annotation of embedaddon/nginx/src/core/ngx_resolver.c, revision 1.1.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>