Return to ngx_resolver.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / nginx / src / core |
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: }