One Level Up
Top Level
src/core/ngx_resolver.c - nginx-1.7.10
Data types defined
Functions defined
Macros defined
Source code
- #include <ngx_config.h>
- #include <ngx_core.h>
- #include <ngx_event.h>
- #define NGX_RESOLVER_UDP_SIZE 4096
- typedef struct {
- u_char ident_hi;
- u_char ident_lo;
- u_char flags_hi;
- u_char flags_lo;
- u_char nqs_hi;
- u_char nqs_lo;
- u_char nan_hi;
- u_char nan_lo;
- u_char nns_hi;
- u_char nns_lo;
- u_char nar_hi;
- u_char nar_lo;
- } ngx_resolver_hdr_t;
- typedef struct {
- u_char type_hi;
- u_char type_lo;
- u_char class_hi;
- u_char class_lo;
- } ngx_resolver_qs_t;
- typedef struct {
- u_char type_hi;
- u_char type_lo;
- u_char class_hi;
- u_char class_lo;
- u_char ttl[4];
- u_char len_hi;
- u_char len_lo;
- } ngx_resolver_an_t;
- #define ngx_resolver_node(n) \
- (ngx_resolver_node_t *) \
- ((u_char *) (n) - offsetof(ngx_resolver_node_t, node))
- ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc);
- static void ngx_resolver_cleanup(void *data);
- static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
- static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
- ngx_resolver_ctx_t *ctx);
- static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
- ngx_queue_t *queue);
- static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
- ngx_resolver_node_t *rn);
- static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn,
- ngx_resolver_ctx_t *ctx);
- static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn,
- ngx_resolver_ctx_t *ctx);
- static void ngx_resolver_resend_handler(ngx_event_t *ev);
- static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
- ngx_queue_t *queue);
- static void ngx_resolver_read_response(ngx_event_t *rev);
- static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
- size_t n);
- static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
- ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
- ngx_uint_t nan, ngx_uint_t ans);
- static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
- ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
- static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
- ngx_str_t *name, uint32_t hash);
- static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
- in_addr_t addr);
- static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
- static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
- u_char *buf, u_char *src, u_char *last);
- static void ngx_resolver_timeout_handler(ngx_event_t *ev);
- static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
- static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
- static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
- static void ngx_resolver_free(ngx_resolver_t *r, void *p);
- static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
- static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
- static ngx_addr_t *ngx_resolver_export(ngx_resolver_t *r,
- ngx_resolver_node_t *rn, ngx_uint_t rotate);
- static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
- #if (NGX_HAVE_INET6)
- static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
- static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r,
- struct in6_addr *addr, uint32_t hash);
- #endif
- ngx_resolver_t *
- ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
- {
- ngx_str_t s;
- ngx_url_t u;
- ngx_uint_t i, j;
- ngx_resolver_t *r;
- ngx_pool_cleanup_t *cln;
- ngx_udp_connection_t *uc;
- cln = ngx_pool_cleanup_add(cf->pool, 0);
- if (cln == NULL) {
- return NULL;
- }
- cln->handler = ngx_resolver_cleanup;
- r = ngx_calloc(sizeof(ngx_resolver_t), cf->log);
- if (r == NULL) {
- return NULL;
- }
- cln->data = r;
- r->event = ngx_calloc(sizeof(ngx_event_t), cf->log);
- if (r->event == NULL) {
- return NULL;
- }
- ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel,
- ngx_resolver_rbtree_insert_value);
- ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
- ngx_rbtree_insert_value);
- ngx_queue_init(&r->name_resend_queue);
- ngx_queue_init(&r->addr_resend_queue);
- ngx_queue_init(&r->name_expire_queue);
- ngx_queue_init(&r->addr_expire_queue);
- #if (NGX_HAVE_INET6)
- r->ipv6 = 1;
- ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel,
- ngx_resolver_rbtree_insert_addr6_value);
- ngx_queue_init(&r->addr6_resend_queue);
- ngx_queue_init(&r->addr6_expire_queue);
- #endif
- r->event->handler = ngx_resolver_resend_handler;
- r->event->data = r;
- r->event->log = &cf->cycle->new_log;
- r->ident = -1;
- r->resend_timeout = 5;
- r->expire = 30;
- r->valid = 0;
- r->log = &cf->cycle->new_log;
- r->log_level = NGX_LOG_ERR;
- if (n) {
- if (ngx_array_init(&r->udp_connections, cf->pool, n,
- sizeof(ngx_udp_connection_t))
- != NGX_OK)
- {
- return NULL;
- }
- }
- for (i = 0; i < n; i++) {
- if (ngx_strncmp(names[i].data, "valid=", 6) == 0) {
- s.len = names[i].len - 6;
- s.data = names[i].data + 6;
- r->valid = ngx_parse_time(&s, 1);
- if (r->valid == (time_t) NGX_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid parameter: %V", &names[i]);
- return NULL;
- }
- continue;
- }
- #if (NGX_HAVE_INET6)
- if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) {
- if (ngx_strcmp(&names[i].data[5], "on") == 0) {
- r->ipv6 = 1;
- } else if (ngx_strcmp(&names[i].data[5], "off") == 0) {
- r->ipv6 = 0;
- } else {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid parameter: %V", &names[i]);
- return NULL;
- }
- continue;
- }
- #endif
- ngx_memzero(&u, sizeof(ngx_url_t));
- u.url = names[i];
- u.default_port = 53;
- if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
- if (u.err) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "%s in resolver \"%V\"",
- u.err, &u.url);
- }
- return NULL;
- }
- uc = ngx_array_push_n(&r->udp_connections, u.naddrs);
- if (uc == NULL) {
- return NULL;
- }
- ngx_memzero(uc, u.naddrs * sizeof(ngx_udp_connection_t));
- for (j = 0; j < u.naddrs; j++) {
- uc[j].sockaddr = u.addrs[j].sockaddr;
- uc[j].socklen = u.addrs[j].socklen;
- uc[j].server = u.addrs[j].name;
- }
- }
- return r;
- }
- static void
- ngx_resolver_cleanup(void *data)
- {
- ngx_resolver_t *r = data;
- ngx_uint_t i;
- ngx_udp_connection_t *uc;
- if (r) {
- ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
- "cleanup resolver");
- ngx_resolver_cleanup_tree(r, &r->name_rbtree);
- ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
- #if (NGX_HAVE_INET6)
- ngx_resolver_cleanup_tree(r, &r->addr6_rbtree);
- #endif
- if (r->event) {
- ngx_free(r->event);
- }
- uc = r->udp_connections.elts;
- for (i = 0; i < r->udp_connections.nelts; i++) {
- if (uc[i].connection) {
- ngx_close_connection(uc[i].connection);
- }
- }
- ngx_free(r);
- }
- }
- static void
- ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree)
- {
- ngx_resolver_ctx_t *ctx, *next;
- ngx_resolver_node_t *rn;
- while (tree->root != tree->sentinel) {
- rn = ngx_resolver_node(ngx_rbtree_min(tree->root, tree->sentinel));
- ngx_queue_remove(&rn->queue);
- for (ctx = rn->waiting; ctx; ctx = next) {
- next = ctx->next;
- if (ctx->event) {
- ngx_resolver_free(r, ctx->event);
- }
- ngx_resolver_free(r, ctx);
- }
- ngx_rbtree_delete(tree, &rn->node);
- ngx_resolver_free_node(r, rn);
- }
- }
- ngx_resolver_ctx_t *
- ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
- {
- in_addr_t addr;
- ngx_resolver_ctx_t *ctx;
- if (temp) {
- addr = ngx_inet_addr(temp->name.data, temp->name.len);
- if (addr != INADDR_NONE) {
- temp->resolver = r;
- temp->state = NGX_OK;
- temp->naddrs = 1;
- temp->addrs = &temp->addr;
- temp->addr.sockaddr = (struct sockaddr *) &temp->sin;
- temp->addr.socklen = sizeof(struct sockaddr_in);
- ngx_memzero(&temp->sin, sizeof(struct sockaddr_in));
- temp->sin.sin_family = AF_INET;
- temp->sin.sin_addr.s_addr = addr;
- temp->quick = 1;
- return temp;
- }
- }
- if (r->udp_connections.nelts == 0) {
- return NGX_NO_RESOLVER;
- }
- ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t));
- if (ctx) {
- ctx->resolver = r;
- }
- return ctx;
- }
- ngx_int_t
- ngx_resolve_name(ngx_resolver_ctx_t *ctx)
- {
- ngx_int_t rc;
- ngx_resolver_t *r;
- r = ctx->resolver;
- if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') {
- ctx->name.len--;
- }
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolve: \"%V\"", &ctx->name);
- if (ctx->quick) {
- ctx->handler(ctx);
- return NGX_OK;
- }
-
- rc = ngx_resolve_name_locked(r, ctx);
- if (rc == NGX_OK) {
- return NGX_OK;
- }
-
- if (rc == NGX_AGAIN) {
- return NGX_OK;
- }
-
- if (ctx->event) {
- ngx_resolver_free(r, ctx->event);
- }
- ngx_resolver_free(r, ctx);
- return NGX_ERROR;
- }
- void
- ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
- {
- uint32_t hash;
- ngx_resolver_t *r;
- ngx_resolver_ctx_t *w, **p;
- ngx_resolver_node_t *rn;
- r = ctx->resolver;
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolve name done: %i", ctx->state);
- if (ctx->quick) {
- return;
- }
- if (ctx->event && ctx->event->timer_set) {
- ngx_del_timer(ctx->event);
- }
-
- if (ctx->state == NGX_AGAIN) {
- hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
- rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
- if (rn) {
- p = &rn->waiting;
- w = rn->waiting;
- while (w) {
- if (w == ctx) {
- *p = w->next;
- goto done;
- }
- p = &w->next;
- w = w->next;
- }
- }
- ngx_log_error(NGX_LOG_ALERT, r->log, 0,
- "could not cancel %V resolving", &ctx->name);
- }
- done:
- ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue);
-
-
- if (ctx->event) {
- ngx_resolver_free_locked(r, ctx->event);
- }
- ngx_resolver_free_locked(r, ctx);
-
- }
- static ngx_int_t
- ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
- {
- uint32_t hash;
- ngx_int_t rc;
- ngx_uint_t naddrs;
- ngx_addr_t *addrs;
- ngx_resolver_ctx_t *next;
- ngx_resolver_node_t *rn;
- ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len);
- hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
- rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
- if (rn) {
- if (rn->valid >= ngx_time()) {
- ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
- ngx_queue_remove(&rn->queue);
- rn->expire = ngx_time() + r->expire;
- ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
- naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs;
- #if (NGX_HAVE_INET6)
- naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6;
- #endif
- if (naddrs) {
- if (naddrs == 1 && rn->naddrs == 1) {
- addrs = NULL;
- } else {
- addrs = ngx_resolver_export(r, rn, 1);
- if (addrs == NULL) {
- return NGX_ERROR;
- }
- }
- ctx->next = rn->waiting;
- rn->waiting = NULL;
-
- do {
- ctx->state = NGX_OK;
- ctx->naddrs = naddrs;
- if (addrs == NULL) {
- ctx->addrs = &ctx->addr;
- ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
- ctx->addr.socklen = sizeof(struct sockaddr_in);
- ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
- ctx->sin.sin_family = AF_INET;
- ctx->sin.sin_addr.s_addr = rn->u.addr;
- } else {
- ctx->addrs = addrs;
- }
- next = ctx->next;
- ctx->handler(ctx);
- ctx = next;
- } while (ctx);
- if (addrs != NULL) {
- ngx_resolver_free(r, addrs->sockaddr);
- ngx_resolver_free(r, addrs);
- }
- return NGX_OK;
- }
-
- if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
- ctx->name.len = rn->cnlen;
- ctx->name.data = rn->u.cname;
- return ngx_resolve_name_locked(r, ctx);
- }
- ctx->next = rn->waiting;
- rn->waiting = NULL;
-
- do {
- ctx->state = NGX_RESOLVE_NXDOMAIN;
- next = ctx->next;
- ctx->handler(ctx);
- ctx = next;
- } while (ctx);
- return NGX_OK;
- }
- if (rn->waiting) {
- ctx->next = rn->waiting;
- rn->waiting = ctx;
- ctx->state = NGX_AGAIN;
- return NGX_AGAIN;
- }
- ngx_queue_remove(&rn->queue);
-
- if (rn->query) {
- ngx_resolver_free_locked(r, rn->query);
- rn->query = NULL;
- #if (NGX_HAVE_INET6)
- rn->query6 = NULL;
- #endif
- }
- if (rn->cnlen) {
- ngx_resolver_free_locked(r, rn->u.cname);
- }
- if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
- ngx_resolver_free_locked(r, rn->u.addrs);
- }
- #if (NGX_HAVE_INET6)
- if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
- ngx_resolver_free_locked(r, rn->u6.addrs6);
- }
- #endif
-
- } else {
- rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
- if (rn == NULL) {
- return NGX_ERROR;
- }
- rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len);
- if (rn->name == NULL) {
- ngx_resolver_free(r, rn);
- return NGX_ERROR;
- }
- rn->node.key = hash;
- rn->nlen = (u_short) ctx->name.len;
- rn->query = NULL;
- #if (NGX_HAVE_INET6)
- rn->query6 = NULL;
- #endif
- ngx_rbtree_insert(&r->name_rbtree, &rn->node);
- }
- rc = ngx_resolver_create_name_query(rn, ctx);
- if (rc == NGX_ERROR) {
- goto failed;
- }
- if (rc == NGX_DECLINED) {
- ngx_rbtree_delete(&r->name_rbtree, &rn->node);
- ngx_resolver_free(r, rn->query);
- ngx_resolver_free(r, rn->name);
- ngx_resolver_free(r, rn);
- ctx->state = NGX_RESOLVE_NXDOMAIN;
- ctx->handler(ctx);
- return NGX_OK;
- }
- rn->naddrs = (u_short) -1;
- #if (NGX_HAVE_INET6)
- rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0;
- #endif
- if (ngx_resolver_send_query(r, rn) != NGX_OK) {
- goto failed;
- }
- if (ctx->event == NULL) {
- ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
- if (ctx->event == NULL) {
- goto failed;
- }
- ctx->event->handler = ngx_resolver_timeout_handler;
- ctx->event->data = rn;
- ctx->event->log = r->log;
- rn->ident = -1;
- ngx_add_timer(ctx->event, ctx->timeout);
- }
- if (ngx_queue_empty(&r->name_resend_queue)) {
- ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
- }
- rn->expire = ngx_time() + r->resend_timeout;
- ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
- rn->code = 0;
- rn->cnlen = 0;
- rn->valid = 0;
- rn->ttl = NGX_MAX_UINT32_VALUE;
- rn->waiting = ctx;
- ctx->state = NGX_AGAIN;
- return NGX_AGAIN;
- failed:
- ngx_rbtree_delete(&r->name_rbtree, &rn->node);
- if (rn->query) {
- ngx_resolver_free(r, rn->query);
- }
- ngx_resolver_free(r, rn->name);
- ngx_resolver_free(r, rn);
- return NGX_ERROR;
- }
- ngx_int_t
- ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
- {
- u_char *name;
- in_addr_t addr;
- ngx_queue_t *resend_queue, *expire_queue;
- ngx_rbtree_t *tree;
- ngx_resolver_t *r;
- struct sockaddr_in *sin;
- ngx_resolver_node_t *rn;
- #if (NGX_HAVE_INET6)
- uint32_t hash;
- struct sockaddr_in6 *sin6;
- #endif
- #if (NGX_SUPPRESS_WARN)
- addr = 0;
- #if (NGX_HAVE_INET6)
- hash = 0;
- sin6 = NULL;
- #endif
- #endif
- r = ctx->resolver;
- switch (ctx->addr.sockaddr->sa_family) {
- #if (NGX_HAVE_INET6)
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
- hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
-
- rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
- tree = &r->addr6_rbtree;
- resend_queue = &r->addr6_resend_queue;
- expire_queue = &r->addr6_expire_queue;
- break;
- #endif
- default:
- sin = (struct sockaddr_in *) ctx->addr.sockaddr;
- addr = ntohl(sin->sin_addr.s_addr);
-
- rn = ngx_resolver_lookup_addr(r, addr);
- tree = &r->addr_rbtree;
- resend_queue = &r->addr_resend_queue;
- expire_queue = &r->addr_expire_queue;
- }
- if (rn) {
- if (rn->valid >= ngx_time()) {
- ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
- ngx_queue_remove(&rn->queue);
- rn->expire = ngx_time() + r->expire;
- ngx_queue_insert_head(expire_queue, &rn->queue);
- name = ngx_resolver_dup(r, rn->name, rn->nlen);
- if (name == NULL) {
- goto failed;
- }
- ctx->name.len = rn->nlen;
- ctx->name.data = name;
-
- ctx->state = NGX_OK;
- ctx->handler(ctx);
- ngx_resolver_free(r, name);
- return NGX_OK;
- }
- if (rn->waiting) {
- ctx->next = rn->waiting;
- rn->waiting = ctx;
- ctx->state = NGX_AGAIN;
-
- return NGX_OK;
- }
- ngx_queue_remove(&rn->queue);
- ngx_resolver_free(r, rn->query);
- rn->query = NULL;
- #if (NGX_HAVE_INET6)
- rn->query6 = NULL;
- #endif
- } else {
- rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
- if (rn == NULL) {
- goto failed;
- }
- switch (ctx->addr.sockaddr->sa_family) {
- #if (NGX_HAVE_INET6)
- case AF_INET6:
- rn->addr6 = sin6->sin6_addr;
- rn->node.key = hash;
- break;
- #endif
- default:
- rn->node.key = addr;
- }
- rn->query = NULL;
- #if (NGX_HAVE_INET6)
- rn->query6 = NULL;
- #endif
- ngx_rbtree_insert(tree, &rn->node);
- }
- if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
- goto failed;
- }
- rn->naddrs = (u_short) -1;
- #if (NGX_HAVE_INET6)
- rn->naddrs6 = (u_short) -1;
- #endif
- if (ngx_resolver_send_query(r, rn) != NGX_OK) {
- goto failed;
- }
- ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
- if (ctx->event == NULL) {
- goto failed;
- }
- ctx->event->handler = ngx_resolver_timeout_handler;
- ctx->event->data = rn;
- ctx->event->log = r->log;
- rn->ident = -1;
- ngx_add_timer(ctx->event, ctx->timeout);
- if (ngx_queue_empty(resend_queue)) {
- ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
- }
- rn->expire = ngx_time() + r->resend_timeout;
- ngx_queue_insert_head(resend_queue, &rn->queue);
- rn->code = 0;
- rn->cnlen = 0;
- rn->name = NULL;
- rn->nlen = 0;
- rn->valid = 0;
- rn->ttl = NGX_MAX_UINT32_VALUE;
- rn->waiting = ctx;
-
- ctx->state = NGX_AGAIN;
- return NGX_OK;
- failed:
- if (rn) {
- ngx_rbtree_delete(tree, &rn->node);
- if (rn->query) {
- ngx_resolver_free(r, rn->query);
- }
- ngx_resolver_free(r, rn);
- }
-
- if (ctx->event) {
- ngx_resolver_free(r, ctx->event);
- }
- ngx_resolver_free(r, ctx);
- return NGX_ERROR;
- }
- void
- ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
- {
- in_addr_t addr;
- ngx_queue_t *expire_queue;
- ngx_rbtree_t *tree;
- ngx_resolver_t *r;
- ngx_resolver_ctx_t *w, **p;
- struct sockaddr_in *sin;
- ngx_resolver_node_t *rn;
- #if (NGX_HAVE_INET6)
- uint32_t hash;
- struct sockaddr_in6 *sin6;
- #endif
- r = ctx->resolver;
- switch (ctx->addr.sockaddr->sa_family) {
- #if (NGX_HAVE_INET6)
- case AF_INET6:
- tree = &r->addr6_rbtree;
- expire_queue = &r->addr6_expire_queue;
- break;
- #endif
- default:
- tree = &r->addr_rbtree;
- expire_queue = &r->addr_expire_queue;
- }
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolve addr done: %i", ctx->state);
- if (ctx->event && ctx->event->timer_set) {
- ngx_del_timer(ctx->event);
- }
-
- if (ctx->state == NGX_AGAIN) {
- switch (ctx->addr.sockaddr->sa_family) {
- #if (NGX_HAVE_INET6)
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
- hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
- rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
- break;
- #endif
- default:
- sin = (struct sockaddr_in *) ctx->addr.sockaddr;
- addr = ntohl(sin->sin_addr.s_addr);
- rn = ngx_resolver_lookup_addr(r, addr);
- }
- if (rn) {
- p = &rn->waiting;
- w = rn->waiting;
- while (w) {
- if (w == ctx) {
- *p = w->next;
- goto done;
- }
- p = &w->next;
- w = w->next;
- }
- }
- {
- u_char text[NGX_SOCKADDR_STRLEN];
- ngx_str_t addrtext;
- addrtext.data = text;
- addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen,
- text, NGX_SOCKADDR_STRLEN, 0);
- ngx_log_error(NGX_LOG_ALERT, r->log, 0,
- "could not cancel %V resolving", &addrtext);
- }
- }
- done:
- ngx_resolver_expire(r, tree, expire_queue);
-
-
- if (ctx->event) {
- ngx_resolver_free_locked(r, ctx->event);
- }
- ngx_resolver_free_locked(r, ctx);
-
- }
- static void
- ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
- {
- time_t now;
- ngx_uint_t i;
- ngx_queue_t *q;
- ngx_resolver_node_t *rn;
- ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire");
- now = ngx_time();
- for (i = 0; i < 2; i++) {
- if (ngx_queue_empty(queue)) {
- return;
- }
- q = ngx_queue_last(queue);
- rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
- if (now <= rn->expire) {
- return;
- }
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name);
- ngx_queue_remove(q);
- ngx_rbtree_delete(tree, &rn->node);
- ngx_resolver_free_node(r, rn);
- }
- }
- static ngx_int_t
- ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
- {
- ssize_t n;
- ngx_udp_connection_t *uc;
- uc = r->udp_connections.elts;
- uc = &uc[r->last_connection++];
- if (r->last_connection == r->udp_connections.nelts) {
- r->last_connection = 0;
- }
- if (uc->connection == NULL) {
- uc->log = *r->log;
- uc->log.handler = ngx_resolver_log_error;
- uc->log.data = uc;
- uc->log.action = "resolving";
- if (ngx_udp_connect(uc) != NGX_OK) {
- return NGX_ERROR;
- }
- uc->connection->data = r;
- uc->connection->read->handler = ngx_resolver_read_response;
- uc->connection->read->resolver = 1;
- }
- if (rn->naddrs == (u_short) -1) {
- n = ngx_send(uc->connection, rn->query, rn->qlen);
- if (n == -1) {
- return NGX_ERROR;
- }
- if ((size_t) n != (size_t) rn->qlen) {
- ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete");
- return NGX_ERROR;
- }
- }
- #if (NGX_HAVE_INET6)
- if (rn->query6 && rn->naddrs6 == (u_short) -1) {
- n = ngx_send(uc->connection, rn->query6, rn->qlen);
- if (n == -1) {
- return NGX_ERROR;
- }
- if ((size_t) n != (size_t) rn->qlen) {
- ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete");
- return NGX_ERROR;
- }
- }
- #endif
- return NGX_OK;
- }
- static void
- ngx_resolver_resend_handler(ngx_event_t *ev)
- {
- time_t timer, atimer, ntimer;
- #if (NGX_HAVE_INET6)
- time_t a6timer;
- #endif
- ngx_resolver_t *r;
- r = ev->data;
- ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver resend handler");
-
- ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue);
-
-
- atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue);
-
- #if (NGX_HAVE_INET6)
-
- a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue);
-
- #endif
- timer = ntimer;
- if (timer == 0) {
- timer = atimer;
- } else if (atimer) {
- timer = ngx_min(timer, atimer);
- }
- #if (NGX_HAVE_INET6)
- if (timer == 0) {
- timer = a6timer;
- } else if (a6timer) {
- timer = ngx_min(timer, a6timer);
- }
- #endif
- if (timer) {
- ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
- }
- }
- static time_t
- ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
- {
- time_t now;
- ngx_queue_t *q;
- ngx_resolver_node_t *rn;
- now = ngx_time();
- for ( ;; ) {
- if (ngx_queue_empty(queue)) {
- return 0;
- }
- q = ngx_queue_last(queue);
- rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
- if (now < rn->expire) {
- return rn->expire - now;
- }
- ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver resend \"%*s\" %p",
- (size_t) rn->nlen, rn->name, rn->waiting);
- ngx_queue_remove(q);
- if (rn->waiting) {
- (void) ngx_resolver_send_query(r, rn);
- rn->expire = now + r->resend_timeout;
- ngx_queue_insert_head(queue, q);
- continue;
- }
- ngx_rbtree_delete(tree, &rn->node);
- ngx_resolver_free_node(r, rn);
- }
- }
- static void
- ngx_resolver_read_response(ngx_event_t *rev)
- {
- ssize_t n;
- ngx_connection_t *c;
- u_char buf[NGX_RESOLVER_UDP_SIZE];
- c = rev->data;
- do {
- n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
- if (n < 0) {
- return;
- }
- ngx_resolver_process_response(c->data, buf, n);
- } while (rev->ready);
- }
- static void
- ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
- {
- char *err;
- ngx_uint_t i, times, ident, qident, flags, code, nqs, nan,
- qtype, qclass;
- #if (NGX_HAVE_INET6)
- ngx_uint_t qident6;
- #endif
- ngx_queue_t *q;
- ngx_resolver_qs_t *qs;
- ngx_resolver_hdr_t *response;
- ngx_resolver_node_t *rn;
- if (n < sizeof(ngx_resolver_hdr_t)) {
- goto short_response;
- }
- response = (ngx_resolver_hdr_t *) buf;
- ident = (response->ident_hi << 8) + response->ident_lo;
- flags = (response->flags_hi << 8) + response->flags_lo;
- nqs = (response->nqs_hi << 8) + response->nqs_lo;
- nan = (response->nan_hi << 8) + response->nan_lo;
- ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud",
- ident, flags, nqs, nan,
- (response->nns_hi << 8) + response->nns_lo,
- (response->nar_hi << 8) + response->nar_lo);
-
- if ((flags & 0xf870) != 0x8000) {
- ngx_log_error(r->log_level, r->log, 0,
- "invalid DNS response %ui fl:%04Xui", ident, flags);
- return;
- }
- code = flags & 0xf;
- if (code == NGX_RESOLVE_FORMERR) {
- times = 0;
- for (q = ngx_queue_head(&r->name_resend_queue);
- q != ngx_queue_sentinel(&r->name_resend_queue) || times++ < 100;
- q = ngx_queue_next(q))
- {
- rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
- qident = (rn->query[0] << 8) + rn->query[1];
- if (qident == ident) {
- goto dns_error_name;
- }
- #if (NGX_HAVE_INET6)
- if (rn->query6) {
- qident6 = (rn->query6[0] << 8) + rn->query6[1];
- if (qident6 == ident) {
- goto dns_error_name;
- }
- }
- #endif
- }
- goto dns_error;
- }
- if (code > NGX_RESOLVE_REFUSED) {
- goto dns_error;
- }
- if (nqs != 1) {
- err = "invalid number of questions in DNS response";
- goto done;
- }
- i = sizeof(ngx_resolver_hdr_t);
- while (i < (ngx_uint_t) n) {
- if (buf[i] == '\0') {
- goto found;
- }
- i += 1 + buf[i];
- }
- goto short_response;
- found:
- if (i++ == sizeof(ngx_resolver_hdr_t)) {
- err = "zero-length domain name in DNS response";
- goto done;
- }
- if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t))
- > (ngx_uint_t) n)
- {
- goto short_response;
- }
- qs = (ngx_resolver_qs_t *) &buf[i];
- qtype = (qs->type_hi << 8) + qs->type_lo;
- qclass = (qs->class_hi << 8) + qs->class_lo;
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver DNS response qt:%ui cl:%ui", qtype, qclass);
- if (qclass != 1) {
- ngx_log_error(r->log_level, r->log, 0,
- "unknown query class %ui in DNS response", qclass);
- return;
- }
- switch (qtype) {
- case NGX_RESOLVE_A:
- #if (NGX_HAVE_INET6)
- case NGX_RESOLVE_AAAA:
- #endif
- ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan,
- i + sizeof(ngx_resolver_qs_t));
- break;
- case NGX_RESOLVE_PTR:
- ngx_resolver_process_ptr(r, buf, n, ident, code, nan);
- break;
- default:
- ngx_log_error(r->log_level, r->log, 0,
- "unknown query type %ui in DNS response", qtype);
- return;
- }
- return;
- short_response:
- err = "short DNS response";
- done:
- ngx_log_error(r->log_level, r->log, 0, err);
- return;
- dns_error_name:
- ngx_log_error(r->log_level, r->log, 0,
- "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
- code, ngx_resolver_strerror(code), ident,
- rn->nlen, rn->name);
- return;
- dns_error:
- ngx_log_error(r->log_level, r->log, 0,
- "DNS error (%ui: %s), query id:%ui",
- code, ngx_resolver_strerror(code), ident);
- return;
- }
- static void
- ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
- ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
- ngx_uint_t nan, ngx_uint_t ans)
- {
- char *err;
- u_char *cname;
- size_t len;
- int32_t ttl;
- uint32_t hash;
- in_addr_t *addr;
- ngx_str_t name;
- ngx_addr_t *addrs;
- ngx_uint_t type, class, qident, naddrs, a, i, n, start;
- #if (NGX_HAVE_INET6)
- struct in6_addr *addr6;
- #endif
- ngx_resolver_an_t *an;
- ngx_resolver_ctx_t *ctx, *next;
- ngx_resolver_node_t *rn;
- if (ngx_resolver_copy(r, &name, buf,
- buf + sizeof(ngx_resolver_hdr_t), buf + last)
- != NGX_OK)
- {
- return;
- }
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
- hash = ngx_crc32_short(name.data, name.len);
-
- rn = ngx_resolver_lookup_name(r, &name, hash);
- if (rn == NULL) {
- ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %V", &name);
- ngx_resolver_free(r, name.data);
- goto failed;
- }
- switch (qtype) {
- #if (NGX_HAVE_INET6)
- case NGX_RESOLVE_AAAA:
- if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) {
- ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %V", &name);
- ngx_resolver_free(r, name.data);
- goto failed;
- }
- qident = (rn->query6[0] << 8) + rn->query6[1];
- break;
- #endif
- default:
- if (rn->query == NULL || rn->naddrs != (u_short) -1) {
- ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %V", &name);
- ngx_resolver_free(r, name.data);
- goto failed;
- }
- qident = (rn->query[0] << 8) + rn->query[1];
- }
- if (ident != qident) {
- ngx_log_error(r->log_level, r->log, 0,
- "wrong ident %ui response for %V, expect %ui",
- ident, &name, qident);
- ngx_resolver_free(r, name.data);
- goto failed;
- }
- ngx_resolver_free(r, name.data);
- if (code == 0 && rn->code) {
- code = rn->code;
- }
- if (code == 0 && nan == 0) {
- #if (NGX_HAVE_INET6)
- switch (qtype) {
- case NGX_RESOLVE_AAAA:
- rn->naddrs6 = 0;
- if (rn->naddrs == (u_short) -1) {
- goto next;
- }
- if (rn->naddrs) {
- goto export;
- }
- break;
- default:
- rn->naddrs = 0;
- if (rn->naddrs6 == (u_short) -1) {
- goto next;
- }
- if (rn->naddrs6) {
- goto export;
- }
- }
- #endif
- code = NGX_RESOLVE_NXDOMAIN;
- }
- if (code) {
- #if (NGX_HAVE_INET6)
- switch (qtype) {
- case NGX_RESOLVE_AAAA:
- rn->naddrs6 = 0;
- if (rn->naddrs == (u_short) -1) {
- rn->code = (u_char) code;
- goto next;
- }
- break;
- default:
- rn->naddrs = 0;
- if (rn->naddrs6 == (u_short) -1) {
- rn->code = (u_char) code;
- goto next;
- }
- }
- #endif
- next = rn->waiting;
- rn->waiting = NULL;
- ngx_queue_remove(&rn->queue);
- ngx_rbtree_delete(&r->name_rbtree, &rn->node);
-
- while (next) {
- ctx = next;
- ctx->state = code;
- next = ctx->next;
- ctx->handler(ctx);
- }
- ngx_resolver_free_node(r, rn);
- return;
- }
- i = ans;
- naddrs = 0;
- cname = NULL;
- for (a = 0; a < nan; a++) {
- start = i;
- while (i < last) {
- if (buf[i] & 0xc0) {
- i += 2;
- goto found;
- }
- if (buf[i] == 0) {
- i++;
- goto test_length;
- }
- i += 1 + buf[i];
- }
- goto short_response;
- test_length:
- if (i - start < 2) {
- err = "invalid name in DNS response";
- goto invalid;
- }
- found:
- if (i + sizeof(ngx_resolver_an_t) >= last) {
- goto short_response;
- }
- an = (ngx_resolver_an_t *) &buf[i];
- type = (an->type_hi << 8) + an->type_lo;
- class = (an->class_hi << 8) + an->class_lo;
- len = (an->len_hi << 8) + an->len_lo;
- ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
- + (an->ttl[2] << 8) + (an->ttl[3]);
- if (class != 1) {
- ngx_log_error(r->log_level, r->log, 0,
- "unexpected RR class %ui", class);
- goto failed;
- }
- if (ttl < 0) {
- ttl = 0;
- }
- rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
- i += sizeof(ngx_resolver_an_t);
- switch (type) {
- case NGX_RESOLVE_A:
- if (qtype != NGX_RESOLVE_A) {
- err = "unexpected A record in DNS response";
- goto invalid;
- }
- if (len != 4) {
- err = "invalid A record in DNS response";
- goto invalid;
- }
- if (i + 4 > last) {
- goto short_response;
- }
- naddrs++;
- break;
- #if (NGX_HAVE_INET6)
- case NGX_RESOLVE_AAAA:
- if (qtype != NGX_RESOLVE_AAAA) {
- err = "unexpected AAAA record in DNS response";
- goto invalid;
- }
- if (len != 16) {
- err = "invalid AAAA record in DNS response";
- goto invalid;
- }
- if (i + 16 > last) {
- goto short_response;
- }
- naddrs++;
- break;
- #endif
- case NGX_RESOLVE_CNAME:
- cname = &buf[i];
- break;
- case NGX_RESOLVE_DNAME:
- break;
- default:
- ngx_log_error(r->log_level, r->log, 0,
- "unexpected RR type %ui", type);
- }
- i += len;
- }
- ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver naddrs:%ui cname:%p ttl:%uD",
- naddrs, cname, rn->ttl);
- if (naddrs) {
- switch (qtype) {
- #if (NGX_HAVE_INET6)
- case NGX_RESOLVE_AAAA:
- if (naddrs == 1) {
- addr6 = &rn->u6.addr6;
- rn->naddrs6 = 1;
- } else {
- addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr));
- if (addr6 == NULL) {
- goto failed;
- }
- rn->u6.addrs6 = addr6;
- rn->naddrs6 = (u_short) naddrs;
- }
- #if (NGX_SUPPRESS_WARN)
- addr = NULL;
- #endif
- break;
- #endif
- default:
- if (naddrs == 1) {
- addr = &rn->u.addr;
- rn->naddrs = 1;
- } else {
- addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
- if (addr == NULL) {
- goto failed;
- }
- rn->u.addrs = addr;
- rn->naddrs = (u_short) naddrs;
- }
- #if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN)
- addr6 = NULL;
- #endif
- }
- n = 0;
- i = ans;
- for (a = 0; a < nan; a++) {
- for ( ;; ) {
- if (buf[i] & 0xc0) {
- i += 2;
- break;
- }
- if (buf[i] == 0) {
- i++;
- break;
- }
- i += 1 + buf[i];
- }
- an = (ngx_resolver_an_t *) &buf[i];
- type = (an->type_hi << 8) + an->type_lo;
- len = (an->len_hi << 8) + an->len_lo;
- i += sizeof(ngx_resolver_an_t);
- if (type == NGX_RESOLVE_A) {
- addr[n] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
- + (buf[i + 2] << 8) + (buf[i + 3]));
- if (++n == naddrs) {
- #if (NGX_HAVE_INET6)
- if (rn->naddrs6 == (u_short) -1) {
- goto next;
- }
- #endif
- break;
- }
- }
- #if (NGX_HAVE_INET6)
- else if (type == NGX_RESOLVE_AAAA) {
- ngx_memcpy(addr6[n].s6_addr, &buf[i], 16);
- if (++n == naddrs) {
- if (rn->naddrs == (u_short) -1) {
- goto next;
- }
- break;
- }
- }
- #endif
- i += len;
- }
- }
- switch (qtype) {
- #if (NGX_HAVE_INET6)
- case NGX_RESOLVE_AAAA:
- if (rn->naddrs6 == (u_short) -1) {
- rn->naddrs6 = 0;
- }
- break;
- #endif
- default:
- if (rn->naddrs == (u_short) -1) {
- rn->naddrs = 0;
- }
- }
- if (rn->naddrs != (u_short) -1
- #if (NGX_HAVE_INET6)
- && rn->naddrs6 != (u_short) -1
- #endif
- && rn->naddrs
- #if (NGX_HAVE_INET6)
- + rn->naddrs6
- #endif
- > 0)
- {
- #if (NGX_HAVE_INET6)
- export:
- #endif
- naddrs = rn->naddrs;
- #if (NGX_HAVE_INET6)
- naddrs += rn->naddrs6;
- #endif
- if (naddrs == 1 && rn->naddrs == 1) {
- addrs = NULL;
- } else {
- addrs = ngx_resolver_export(r, rn, 0);
- if (addrs == NULL) {
- goto failed;
- }
- }
- ngx_queue_remove(&rn->queue);
- rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
- rn->expire = ngx_time() + r->expire;
- ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
- next = rn->waiting;
- rn->waiting = NULL;
-
- while (next) {
- ctx = next;
- ctx->state = NGX_OK;
- ctx->naddrs = naddrs;
- if (addrs == NULL) {
- ctx->addrs = &ctx->addr;
- ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
- ctx->addr.socklen = sizeof(struct sockaddr_in);
- ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
- ctx->sin.sin_family = AF_INET;
- ctx->sin.sin_addr.s_addr = rn->u.addr;
- } else {
- ctx->addrs = addrs;
- }
- next = ctx->next;
- ctx->handler(ctx);
- }
- if (addrs != NULL) {
- ngx_resolver_free(r, addrs->sockaddr);
- ngx_resolver_free(r, addrs);
- }
- ngx_resolver_free(r, rn->query);
- rn->query = NULL;
- #if (NGX_HAVE_INET6)
- rn->query6 = NULL;
- #endif
- return;
- }
- if (cname) {
-
- if (rn->naddrs == (u_short) -1
- #if (NGX_HAVE_INET6)
- || rn->naddrs6 == (u_short) -1
- #endif
- )
- {
- goto next;
- }
- if (ngx_resolver_copy(r, &name, buf, cname, buf + last) != NGX_OK) {
- goto failed;
- }
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver cname:\"%V\"", &name);
- ngx_queue_remove(&rn->queue);
- rn->cnlen = (u_short) name.len;
- rn->u.cname = name.data;
- rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
- rn->expire = ngx_time() + r->expire;
- ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
- ctx = rn->waiting;
- rn->waiting = NULL;
- if (ctx) {
- ctx->name = name;
- (void) ngx_resolve_name_locked(r, ctx);
- }
- ngx_resolver_free(r, rn->query);
- rn->query = NULL;
- #if (NGX_HAVE_INET6)
- rn->query6 = NULL;
- #endif
-
- return;
- }
- ngx_log_error(r->log_level, r->log, 0,
- "no A or CNAME types in DNS response");
- return;
- short_response:
- err = "short DNS response";
- invalid:
-
- ngx_log_error(r->log_level, r->log, 0, err);
- return;
- failed:
- next:
-
- return;
- }
- static void
- ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
- ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
- {
- char *err;
- size_t len;
- u_char text[NGX_SOCKADDR_STRLEN];
- in_addr_t addr;
- int32_t ttl;
- ngx_int_t octet;
- ngx_str_t name;
- ngx_uint_t i, mask, qident, class;
- ngx_queue_t *expire_queue;
- ngx_rbtree_t *tree;
- ngx_resolver_an_t *an;
- ngx_resolver_ctx_t *ctx, *next;
- ngx_resolver_node_t *rn;
- #if (NGX_HAVE_INET6)
- uint32_t hash;
- ngx_int_t digit;
- struct in6_addr addr6;
- #endif
- if (ngx_resolver_copy(r, NULL, buf,
- buf + sizeof(ngx_resolver_hdr_t), buf + n)
- != NGX_OK)
- {
- return;
- }
-
- addr = 0;
- i = sizeof(ngx_resolver_hdr_t);
- for (mask = 0; mask < 32; mask += 8) {
- len = buf[i++];
- octet = ngx_atoi(&buf[i], len);
- if (octet == NGX_ERROR || octet > 255) {
- goto invalid_in_addr_arpa;
- }
- addr += octet << mask;
- i += len;
- }
- if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) {
- i += sizeof("\7in-addr\4arpa");
-
- rn = ngx_resolver_lookup_addr(r, addr);
- tree = &r->addr_rbtree;
- expire_queue = &r->addr_expire_queue;
- addr = htonl(addr);
- name.len = ngx_inet_ntop(AF_INET, &addr, text, NGX_SOCKADDR_STRLEN);
- name.data = text;
- goto valid;
- }
- invalid_in_addr_arpa:
- #if (NGX_HAVE_INET6)
- i = sizeof(ngx_resolver_hdr_t);
- for (octet = 15; octet >= 0; octet--) {
- if (buf[i++] != '\1') {
- goto invalid_ip6_arpa;
- }
- digit = ngx_hextoi(&buf[i++], 1);
- if (digit == NGX_ERROR) {
- goto invalid_ip6_arpa;
- }
- addr6.s6_addr[octet] = (u_char) digit;
- if (buf[i++] != '\1') {
- goto invalid_ip6_arpa;
- }
- digit = ngx_hextoi(&buf[i++], 1);
- if (digit == NGX_ERROR) {
- goto invalid_ip6_arpa;
- }
- addr6.s6_addr[octet] += (u_char) (digit * 16);
- }
- if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) {
- i += sizeof("\3ip6\4arpa");
-
- hash = ngx_crc32_short(addr6.s6_addr, 16);
- rn = ngx_resolver_lookup_addr6(r, &addr6, hash);
- tree = &r->addr6_rbtree;
- expire_queue = &r->addr6_expire_queue;
- name.len = ngx_inet6_ntop(addr6.s6_addr, text, NGX_SOCKADDR_STRLEN);
- name.data = text;
- goto valid;
- }
- invalid_ip6_arpa:
- #endif
- ngx_log_error(r->log_level, r->log, 0,
- "invalid in-addr.arpa or ip6.arpa name in DNS response");
- return;
- valid:
- if (rn == NULL || rn->query == NULL) {
- ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %V", &name);
- goto failed;
- }
- qident = (rn->query[0] << 8) + rn->query[1];
- if (ident != qident) {
- ngx_log_error(r->log_level, r->log, 0,
- "wrong ident %ui response for %V, expect %ui",
- ident, &name, qident);
- goto failed;
- }
- if (code == 0 && nan == 0) {
- code = NGX_RESOLVE_NXDOMAIN;
- }
- if (code) {
- next = rn->waiting;
- rn->waiting = NULL;
- ngx_queue_remove(&rn->queue);
- ngx_rbtree_delete(tree, &rn->node);
-
- while (next) {
- ctx = next;
- ctx->state = code;
- next = ctx->next;
- ctx->handler(ctx);
- }
- ngx_resolver_free_node(r, rn);
- return;
- }
- i += sizeof(ngx_resolver_qs_t);
- if (i + 2 + sizeof(ngx_resolver_an_t) >= n) {
- goto short_response;
- }
-
- if (buf[i] != 0xc0 || buf[i + 1] != sizeof(ngx_resolver_hdr_t)) {
- err = "invalid in-addr.arpa or ip6.arpa name in DNS response";
- goto invalid;
- }
- an = (ngx_resolver_an_t *) &buf[i + 2];
- class = (an->class_hi << 8) + an->class_lo;
- len = (an->len_hi << 8) + an->len_lo;
- ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
- + (an->ttl[2] << 8) + (an->ttl[3]);
- if (class != 1) {
- ngx_log_error(r->log_level, r->log, 0,
- "unexpected RR class %ui", class);
- goto failed;
- }
- if (ttl < 0) {
- ttl = 0;
- }
- ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver qt:%ui cl:%ui len:%uz",
- (an->type_hi << 8) + an->type_lo,
- class, len);
- i += 2 + sizeof(ngx_resolver_an_t);
- if (i + len > n) {
- goto short_response;
- }
- if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) {
- goto failed;
- }
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
- if (name.len != (size_t) rn->nlen
- || ngx_strncmp(name.data, rn->name, name.len) != 0)
- {
- if (rn->nlen) {
- ngx_resolver_free(r, rn->name);
- }
- rn->nlen = (u_short) name.len;
- rn->name = name.data;
- name.data = ngx_resolver_dup(r, rn->name, name.len);
- if (name.data == NULL) {
- goto failed;
- }
- }
- ngx_queue_remove(&rn->queue);
- rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
- rn->expire = ngx_time() + r->expire;
- ngx_queue_insert_head(expire_queue, &rn->queue);
- next = rn->waiting;
- rn->waiting = NULL;
-
- while (next) {
- ctx = next;
- ctx->state = NGX_OK;
- ctx->name = name;
- next = ctx->next;
- ctx->handler(ctx);
- }
- ngx_resolver_free(r, name.data);
- return;
- short_response:
- err = "short DNS response";
- invalid:
-
- ngx_log_error(r->log_level, r->log, 0, err);
- return;
- failed:
-
- return;
- }
- static ngx_resolver_node_t *
- ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
- {
- ngx_int_t rc;
- ngx_rbtree_node_t *node, *sentinel;
- ngx_resolver_node_t *rn;
- node = r->name_rbtree.root;
- sentinel = r->name_rbtree.sentinel;
- while (node != sentinel) {
- if (hash < node->key) {
- node = node->left;
- continue;
- }
- if (hash > node->key) {
- node = node->right;
- continue;
- }
-
- rn = ngx_resolver_node(node);
- rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
- if (rc == 0) {
- return rn;
- }
- node = (rc < 0) ? node->left : node->right;
- }
-
- return NULL;
- }
- static ngx_resolver_node_t *
- ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
- {
- ngx_rbtree_node_t *node, *sentinel;
- node = r->addr_rbtree.root;
- sentinel = r->addr_rbtree.sentinel;
- while (node != sentinel) {
- if (addr < node->key) {
- node = node->left;
- continue;
- }
- if (addr > node->key) {
- node = node->right;
- continue;
- }
-
- return ngx_resolver_node(node);
- }
-
- return NULL;
- }
- #if (NGX_HAVE_INET6)
- static ngx_resolver_node_t *
- ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr,
- uint32_t hash)
- {
- ngx_int_t rc;
- ngx_rbtree_node_t *node, *sentinel;
- ngx_resolver_node_t *rn;
- node = r->addr6_rbtree.root;
- sentinel = r->addr6_rbtree.sentinel;
- while (node != sentinel) {
- if (hash < node->key) {
- node = node->left;
- continue;
- }
- if (hash > node->key) {
- node = node->right;
- continue;
- }
-
- rn = ngx_resolver_node(node);
- rc = ngx_memcmp(addr, &rn->addr6, 16);
- if (rc == 0) {
- return rn;
- }
- node = (rc < 0) ? node->left : node->right;
- }
-
- return NULL;
- }
- #endif
- static void
- ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
- {
- ngx_rbtree_node_t **p;
- ngx_resolver_node_t *rn, *rn_temp;
- for ( ;; ) {
- if (node->key < temp->key) {
- p = &temp->left;
- } else if (node->key > temp->key) {
- p = &temp->right;
- } else {
- rn = ngx_resolver_node(node);
- rn_temp = ngx_resolver_node(temp);
- p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)
- < 0) ? &temp->left : &temp->right;
- }
- if (*p == sentinel) {
- break;
- }
- temp = *p;
- }
- *p = node;
- node->parent = temp;
- node->left = sentinel;
- node->right = sentinel;
- ngx_rbt_red(node);
- }
- #if (NGX_HAVE_INET6)
- static void
- ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
- {
- ngx_rbtree_node_t **p;
- ngx_resolver_node_t *rn, *rn_temp;
- for ( ;; ) {
- if (node->key < temp->key) {
- p = &temp->left;
- } else if (node->key > temp->key) {
- p = &temp->right;
- } else {
- rn = ngx_resolver_node(node);
- rn_temp = ngx_resolver_node(temp);
- p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16)
- < 0) ? &temp->left : &temp->right;
- }
- if (*p == sentinel) {
- break;
- }
- temp = *p;
- }
- *p = node;
- node->parent = temp;
- node->left = sentinel;
- node->right = sentinel;
- ngx_rbt_red(node);
- }
- #endif
- static ngx_int_t
- ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
- {
- u_char *p, *s;
- size_t len, nlen;
- ngx_uint_t ident;
- #if (NGX_HAVE_INET6)
- ngx_resolver_t *r;
- #endif
- ngx_resolver_qs_t *qs;
- ngx_resolver_hdr_t *query;
- nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1;
- len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
- #if (NGX_HAVE_INET6)
- r = ctx->resolver;
- p = ngx_resolver_alloc(ctx->resolver, r->ipv6 ? len * 2 : len);
- #else
- p = ngx_resolver_alloc(ctx->resolver, len);
- #endif
- if (p == NULL) {
- return NGX_ERROR;
- }
- rn->qlen = (u_short) len;
- rn->query = p;
- #if (NGX_HAVE_INET6)
- if (r->ipv6) {
- rn->query6 = p + len;
- }
- #endif
- query = (ngx_resolver_hdr_t *) p;
- ident = ngx_random();
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
- "resolve: \"%V\" A %i", &ctx->name, ident & 0xffff);
- query->ident_hi = (u_char) ((ident >> 8) & 0xff);
- query->ident_lo = (u_char) (ident & 0xff);
-
- query->flags_hi = 1; query->flags_lo = 0;
-
- query->nqs_hi = 0; query->nqs_lo = 1;
- query->nan_hi = 0; query->nan_lo = 0;
- query->nns_hi = 0; query->nns_lo = 0;
- query->nar_hi = 0; query->nar_lo = 0;
- p += sizeof(ngx_resolver_hdr_t) + nlen;
- qs = (ngx_resolver_qs_t *) p;
-
- qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A;
-
- qs->class_hi = 0; qs->class_lo = 1;
-
- len = 0;
- p--;
- *p-- = '\0';
- if (ctx->name.len == 0) {
- return NGX_DECLINED;
- }
- for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) {
- if (*s != '.') {
- *p = *s;
- len++;
- } else {
- if (len == 0 || len > 255) {
- return NGX_DECLINED;
- }
- *p = (u_char) len;
- len = 0;
- }
- p--;
- }
- if (len == 0 || len > 255) {
- return NGX_DECLINED;
- }
- *p = (u_char) len;
- #if (NGX_HAVE_INET6)
- if (!r->ipv6) {
- return NGX_OK;
- }
- p = rn->query6;
- ngx_memcpy(p, rn->query, rn->qlen);
- query = (ngx_resolver_hdr_t *) p;
- ident = ngx_random();
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
- "resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff);
- query->ident_hi = (u_char) ((ident >> 8) & 0xff);
- query->ident_lo = (u_char) (ident & 0xff);
- p += sizeof(ngx_resolver_hdr_t) + nlen;
- qs = (ngx_resolver_qs_t *) p;
- qs->type_lo = NGX_RESOLVE_AAAA;
- #endif
- return NGX_OK;
- }
- static ngx_int_t
- ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
- {
- u_char *p, *d;
- size_t len;
- in_addr_t addr;
- ngx_int_t n;
- ngx_uint_t ident;
- ngx_resolver_hdr_t *query;
- struct sockaddr_in *sin;
- #if (NGX_HAVE_INET6)
- struct sockaddr_in6 *sin6;
- #endif
- switch (ctx->addr.sockaddr->sa_family) {
- #if (NGX_HAVE_INET6)
- case AF_INET6:
- len = sizeof(ngx_resolver_hdr_t)
- + 64 + sizeof(".ip6.arpa.") - 1
- + sizeof(ngx_resolver_qs_t);
- break;
- #endif
- default:
- len = sizeof(ngx_resolver_hdr_t)
- + sizeof(".255.255.255.255.in-addr.arpa.") - 1
- + sizeof(ngx_resolver_qs_t);
- }
- p = ngx_resolver_alloc(ctx->resolver, len);
- if (p == NULL) {
- return NGX_ERROR;
- }
- rn->query = p;
- query = (ngx_resolver_hdr_t *) p;
- ident = ngx_random();
- query->ident_hi = (u_char) ((ident >> 8) & 0xff);
- query->ident_lo = (u_char) (ident & 0xff);
-
- query->flags_hi = 1; query->flags_lo = 0;
-
- query->nqs_hi = 0; query->nqs_lo = 1;
- query->nan_hi = 0; query->nan_lo = 0;
- query->nns_hi = 0; query->nns_lo = 0;
- query->nar_hi = 0; query->nar_lo = 0;
- p += sizeof(ngx_resolver_hdr_t);
- switch (ctx->addr.sockaddr->sa_family) {
- #if (NGX_HAVE_INET6)
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
- for (n = 15; n >= 0; n--) {
- p = ngx_sprintf(p, "\1%xd\1%xd",
- sin6->sin6_addr.s6_addr[n] & 0xf,
- (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf);
- }
- p = ngx_cpymem(p, "\3ip6\4arpa\0", 10);
- break;
- #endif
- default:
- sin = (struct sockaddr_in *) ctx->addr.sockaddr;
- addr = ntohl(sin->sin_addr.s_addr);
- for (n = 0; n < 32; n += 8) {
- d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff);
- *p = (u_char) (d - &p[1]);
- p = d;
- }
- p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14);
- }
-
- p = ngx_cpymem(p, "\0\14\0\1", 4);
- rn->qlen = (u_short) (p - rn->query);
- return NGX_OK;
- }
- static ngx_int_t
- ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src,
- u_char *last)
- {
- char *err;
- u_char *p, *dst;
- ssize_t len;
- ngx_uint_t i, n;
- p = src;
- len = -1;
-
- for (i = 0; i < 128; i++) {
- n = *p++;
- if (n == 0) {
- goto done;
- }
- if (n & 0xc0) {
- n = ((n & 0x3f) << 8) + *p;
- p = &buf[n];
- } else {
- len += 1 + n;
- p = &p[n];
- }
- if (p >= last) {
- err = "name is out of response";
- goto invalid;
- }
- }
- err = "compression pointers loop";
- invalid:
- ngx_log_error(r->log_level, r->log, 0, err);
- return NGX_ERROR;
- done:
- if (name == NULL) {
- return NGX_OK;
- }
- if (len == -1) {
- ngx_str_null(name);
- return NGX_OK;
- }
- dst = ngx_resolver_alloc(r, len);
- if (dst == NULL) {
- return NGX_ERROR;
- }
- name->data = dst;
- n = *src++;
- for ( ;; ) {
- if (n & 0xc0) {
- n = ((n & 0x3f) << 8) + *src;
- src = &buf[n];
- n = *src++;
- } else {
- ngx_strlow(dst, src, n);
- dst += n;
- src += n;
- n = *src++;
- if (n != 0) {
- *dst++ = '.';
- }
- }
- if (n == 0) {
- name->len = dst - name->data;
- return NGX_OK;
- }
- }
- }
- static void
- ngx_resolver_timeout_handler(ngx_event_t *ev)
- {
- ngx_resolver_ctx_t *ctx, *next;
- ngx_resolver_node_t *rn;
- rn = ev->data;
- ctx = rn->waiting;
- rn->waiting = NULL;
- do {
- ctx->state = NGX_RESOLVE_TIMEDOUT;
- next = ctx->next;
- ctx->handler(ctx);
- ctx = next;
- } while (ctx);
- }
- static void
- ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
- {
-
- if (rn->query) {
- ngx_resolver_free_locked(r, rn->query);
- }
- if (rn->name) {
- ngx_resolver_free_locked(r, rn->name);
- }
- if (rn->cnlen) {
- ngx_resolver_free_locked(r, rn->u.cname);
- }
- if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
- ngx_resolver_free_locked(r, rn->u.addrs);
- }
- #if (NGX_HAVE_INET6)
- if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
- ngx_resolver_free_locked(r, rn->u6.addrs6);
- }
- #endif
- ngx_resolver_free_locked(r, rn);
-
- }
- static void *
- ngx_resolver_alloc(ngx_resolver_t *r, size_t size)
- {
- u_char *p;
-
- p = ngx_alloc(size, r->log);
-
- return p;
- }
- static void *
- ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
- {
- u_char *p;
- p = ngx_resolver_alloc(r, size);
- if (p) {
- ngx_memzero(p, size);
- }
- return p;
- }
- static void
- ngx_resolver_free(ngx_resolver_t *r, void *p)
- {
-
- ngx_free(p);
-
- }
- static void
- ngx_resolver_free_locked(ngx_resolver_t *r, void *p)
- {
- ngx_free(p);
- }
- static void *
- ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
- {
- void *dst;
- dst = ngx_resolver_alloc(r, size);
- if (dst == NULL) {
- return dst;
- }
- ngx_memcpy(dst, src, size);
- return dst;
- }
- static ngx_addr_t *
- ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn,
- ngx_uint_t rotate)
- {
- ngx_addr_t *dst;
- ngx_uint_t d, i, j, n;
- u_char (*sockaddr)[NGX_SOCKADDRLEN];
- in_addr_t *addr;
- struct sockaddr_in *sin;
- #if (NGX_HAVE_INET6)
- struct in6_addr *addr6;
- struct sockaddr_in6 *sin6;
- #endif
- n = rn->naddrs;
- #if (NGX_HAVE_INET6)
- n += rn->naddrs6;
- #endif
- dst = ngx_resolver_calloc(r, n * sizeof(ngx_addr_t));
- if (dst == NULL) {
- return NULL;
- }
- sockaddr = ngx_resolver_calloc(r, n * NGX_SOCKADDRLEN);
- if (sockaddr == NULL) {
- ngx_resolver_free(r, dst);
- return NULL;
- }
- i = 0;
- d = rotate ? ngx_random() % n : 0;
- if (rn->naddrs) {
- j = rotate ? ngx_random() % rn->naddrs : 0;
- addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs;
- do {
- sin = (struct sockaddr_in *) sockaddr[d];
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = addr[j++];
- dst[d].sockaddr = (struct sockaddr *) sin;
- dst[d++].socklen = sizeof(struct sockaddr_in);
- if (d == n) {
- d = 0;
- }
- if (j == rn->naddrs) {
- j = 0;
- }
- } while (++i < rn->naddrs);
- }
- #if (NGX_HAVE_INET6)
- if (rn->naddrs6) {
- j = rotate ? ngx_random() % rn->naddrs6 : 0;
- addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6;
- do {
- sin6 = (struct sockaddr_in6 *) sockaddr[d];
- sin6->sin6_family = AF_INET6;
- ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16);
- dst[d].sockaddr = (struct sockaddr *) sin6;
- dst[d++].socklen = sizeof(struct sockaddr_in6);
- if (d == n) {
- d = 0;
- }
- if (j == rn->naddrs6) {
- j = 0;
- }
- } while (++i < n);
- }
- #endif
- return dst;
- }
- char *
- ngx_resolver_strerror(ngx_int_t err)
- {
- static char *errors[] = {
- "Format error",
- "Server failure",
- "Host not found",
- "Unimplemented",
- "Operation refused"
- };
- if (err > 0 && err < 6) {
- return errors[err - 1];
- }
- if (err == NGX_RESOLVE_TIMEDOUT) {
- return "Operation timed out";
- }
- return "Unknown error";
- }
- static u_char *
- ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len)
- {
- u_char *p;
- ngx_udp_connection_t *uc;
- p = buf;
- if (log->action) {
- p = ngx_snprintf(buf, len, " while %s", log->action);
- len -= p - buf;
- }
- uc = log->data;
- if (uc) {
- p = ngx_snprintf(p, len, ", resolver: %V", &uc->server);
- }
- return p;
- }
- ngx_int_t
- ngx_udp_connect(ngx_udp_connection_t *uc)
- {
- int rc;
- ngx_int_t event;
- ngx_event_t *rev, *wev;
- ngx_socket_t s;
- ngx_connection_t *c;
- s = ngx_socket(uc->sockaddr->sa_family, SOCK_DGRAM, 0);
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s);
- if (s == (ngx_socket_t) -1) {
- ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
- ngx_socket_n " failed");
- return NGX_ERROR;
- }
- c = ngx_get_connection(s, &uc->log);
- if (c == NULL) {
- if (ngx_close_socket(s) == -1) {
- ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
- ngx_close_socket_n "failed");
- }
- return NGX_ERROR;
- }
- if (ngx_nonblocking(s) == -1) {
- ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
- ngx_nonblocking_n " failed");
- goto failed;
- }
- rev = c->read;
- wev = c->write;
- rev->log = &uc->log;
- wev->log = &uc->log;
- uc->connection = c;
- c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
- ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0,
- "connect to %V, fd:%d #%uA", &uc->server, s, c->number);
- rc = connect(s, uc->sockaddr, uc->socklen);
- TODO
- if (rc == -1) {
- ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno,
- "connect() failed");
- goto failed;
- }
-
- wev->ready = 1;
- if (ngx_add_event) {
- event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
- NGX_CLEAR_EVENT:
- NGX_LEVEL_EVENT;
-
- if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
- goto failed;
- }
- } else {
-
- if (ngx_add_conn(c) == NGX_ERROR) {
- goto failed;
- }
- }
- return NGX_OK;
- failed:
- ngx_close_connection(c);
- uc->connection = NULL;
- return NGX_ERROR;
- }
One Level Up
Top Level