Mercurial > hg > nginx-quic
view src/core/ngx_inet.c @ 6876:a5d1b1383dea
Upstream: fixed cache corruption and socket leaks with aio_write.
The ngx_event_pipe() function wasn't called on write events with
wev->delayed set. As a result, threaded writing results weren't
properly collected in ngx_event_pipe_write_to_downstream() when a
write event was triggered for a completed write.
Further, this wasn't detected, as p->aio was reset by a thread completion
handler, and results were later collected in ngx_event_pipe_read_upstream()
instead of scheduling a new write of additional data. If this happened
on the last reading from an upstream, last part of the response was never
written to the cache file.
Similar problems might also happen in case of timeouts when writing to
client, as this also results in ngx_event_pipe() not being called on write
events. In this scenario socket leaks were observed.
Fix is to check if p->writing is set in ngx_event_pipe_read_upstream(), and
therefore collect results of previous write operations in case of read events
as well, similar to how we do so in ngx_event_pipe_write_downstream().
This is enough to fix the wev->delayed case. Additionally, we now call
ngx_event_pipe() from ngx_http_upstream_process_request() if there are
uncollected write operations (p->writing and !p->aio). This also fixes
the wev->timedout case.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Fri, 20 Jan 2017 21:14:19 +0300 |
parents | 3f94a0fc05cf |
children | 874171c3c71a |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u); static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u); static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u); in_addr_t ngx_inet_addr(u_char *text, size_t len) { u_char *p, c; in_addr_t addr; ngx_uint_t octet, n; addr = 0; octet = 0; n = 0; for (p = text; p < text + len; p++) { c = *p; if (c >= '0' && c <= '9') { octet = octet * 10 + (c - '0'); if (octet > 255) { return INADDR_NONE; } continue; } if (c == '.') { addr = (addr << 8) + octet; octet = 0; n++; continue; } return INADDR_NONE; } if (n == 3) { addr = (addr << 8) + octet; return htonl(addr); } return INADDR_NONE; } #if (NGX_HAVE_INET6) ngx_int_t ngx_inet6_addr(u_char *p, size_t len, u_char *addr) { u_char c, *zero, *digit, *s, *d; size_t len4; ngx_uint_t n, nibbles, word; if (len == 0) { return NGX_ERROR; } zero = NULL; digit = NULL; len4 = 0; nibbles = 0; word = 0; n = 8; if (p[0] == ':') { p++; len--; } for (/* void */; len; len--) { c = *p++; if (c == ':') { if (nibbles) { digit = p; len4 = len; *addr++ = (u_char) (word >> 8); *addr++ = (u_char) (word & 0xff); if (--n) { nibbles = 0; word = 0; continue; } } else { if (zero == NULL) { digit = p; len4 = len; zero = addr; continue; } } return NGX_ERROR; } if (c == '.' && nibbles) { if (n < 2 || digit == NULL) { return NGX_ERROR; } word = ngx_inet_addr(digit, len4 - 1); if (word == INADDR_NONE) { return NGX_ERROR; } word = ntohl(word); *addr++ = (u_char) ((word >> 24) & 0xff); *addr++ = (u_char) ((word >> 16) & 0xff); n--; break; } if (++nibbles > 4) { return NGX_ERROR; } if (c >= '0' && c <= '9') { word = word * 16 + (c - '0'); continue; } c |= 0x20; if (c >= 'a' && c <= 'f') { word = word * 16 + (c - 'a') + 10; continue; } return NGX_ERROR; } if (nibbles == 0 && zero == NULL) { return NGX_ERROR; } *addr++ = (u_char) (word >> 8); *addr++ = (u_char) (word & 0xff); if (--n) { if (zero) { n *= 2; s = addr - 1; d = s + n; while (s >= zero) { *d-- = *s--; } ngx_memzero(zero, n); return NGX_OK; } } else { if (zero == NULL) { return NGX_OK; } } return NGX_ERROR; } #endif size_t ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len, ngx_uint_t port) { u_char *p; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) size_t n; struct sockaddr_in6 *sin6; #endif #if (NGX_HAVE_UNIX_DOMAIN) struct sockaddr_un *saun; #endif switch (sa->sa_family) { case AF_INET: sin = (struct sockaddr_in *) sa; p = (u_char *) &sin->sin_addr; if (port) { p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud:%d", p[0], p[1], p[2], p[3], ntohs(sin->sin_port)); } else { p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]); } return (p - text); #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) sa; n = 0; if (port) { text[n++] = '['; } n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len); if (port) { n = ngx_sprintf(&text[1 + n], "]:%d", ntohs(sin6->sin6_port)) - text; } return n; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: saun = (struct sockaddr_un *) sa; /* on Linux sockaddr might not include sun_path at all */ if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)) { p = ngx_snprintf(text, len, "unix:%Z"); } else { p = ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path); } /* we do not include trailing zero in address length */ return (p - text - 1); #endif default: return 0; } } size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len) { u_char *p; switch (family) { case AF_INET: p = addr; return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]) - text; #if (NGX_HAVE_INET6) case AF_INET6: return ngx_inet6_ntop(addr, text, len); #endif default: return 0; } } #if (NGX_HAVE_INET6) size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len) { u_char *dst; size_t max, n; ngx_uint_t i, zero, last; if (len < NGX_INET6_ADDRSTRLEN) { return 0; } zero = (ngx_uint_t) -1; last = (ngx_uint_t) -1; max = 1; n = 0; for (i = 0; i < 16; i += 2) { if (p[i] || p[i + 1]) { if (max < n) { zero = last; max = n; } n = 0; continue; } if (n++ == 0) { last = i; } } if (max < n) { zero = last; max = n; } dst = text; n = 16; if (zero == 0) { if ((max == 5 && p[10] == 0xff && p[11] == 0xff) || (max == 6) || (max == 7 && p[14] != 0 && p[15] != 1)) { n = 12; } *dst++ = ':'; } for (i = 0; i < n; i += 2) { if (i == zero) { *dst++ = ':'; i += (max - 1) * 2; continue; } dst = ngx_sprintf(dst, "%xd", p[i] * 256 + p[i + 1]); if (i < 14) { *dst++ = ':'; } } if (n == 12) { dst = ngx_sprintf(dst, "%ud.%ud.%ud.%ud", p[12], p[13], p[14], p[15]); } return dst - text; } #endif ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr) { u_char *addr, *mask, *last; size_t len; ngx_int_t shift; #if (NGX_HAVE_INET6) ngx_int_t rc; ngx_uint_t s, i; #endif addr = text->data; last = addr + text->len; mask = ngx_strlchr(addr, last, '/'); len = (mask ? mask : last) - addr; cidr->u.in.addr = ngx_inet_addr(addr, len); if (cidr->u.in.addr != INADDR_NONE) { cidr->family = AF_INET; if (mask == NULL) { cidr->u.in.mask = 0xffffffff; return NGX_OK; } #if (NGX_HAVE_INET6) } else if (ngx_inet6_addr(addr, len, cidr->u.in6.addr.s6_addr) == NGX_OK) { cidr->family = AF_INET6; if (mask == NULL) { ngx_memset(cidr->u.in6.mask.s6_addr, 0xff, 16); return NGX_OK; } #endif } else { return NGX_ERROR; } mask++; shift = ngx_atoi(mask, last - mask); if (shift == NGX_ERROR) { return NGX_ERROR; } switch (cidr->family) { #if (NGX_HAVE_INET6) case AF_INET6: if (shift > 128) { return NGX_ERROR; } addr = cidr->u.in6.addr.s6_addr; mask = cidr->u.in6.mask.s6_addr; rc = NGX_OK; for (i = 0; i < 16; i++) { s = (shift > 8) ? 8 : shift; shift -= s; mask[i] = (u_char) (0xffu << (8 - s)); if (addr[i] != (addr[i] & mask[i])) { rc = NGX_DONE; addr[i] &= mask[i]; } } return rc; #endif default: /* AF_INET */ if (shift > 32) { return NGX_ERROR; } if (shift) { cidr->u.in.mask = htonl((uint32_t) (0xffffffffu << (32 - shift))); } else { /* x86 compilers use a shl instruction that shifts by modulo 32 */ cidr->u.in.mask = 0; } if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) { return NGX_OK; } cidr->u.in.addr &= cidr->u.in.mask; return NGX_DONE; } } ngx_int_t ngx_cidr_match(struct sockaddr *sa, ngx_array_t *cidrs) { #if (NGX_HAVE_INET6) u_char *p; #endif in_addr_t inaddr; ngx_cidr_t *cidr; ngx_uint_t family, i; #if (NGX_HAVE_INET6) ngx_uint_t n; struct in6_addr *inaddr6; #endif #if (NGX_SUPPRESS_WARN) inaddr = 0; #if (NGX_HAVE_INET6) inaddr6 = NULL; #endif #endif family = sa->sa_family; if (family == AF_INET) { inaddr = ((struct sockaddr_in *) sa)->sin_addr.s_addr; } #if (NGX_HAVE_INET6) else if (family == AF_INET6) { inaddr6 = &((struct sockaddr_in6 *) sa)->sin6_addr; if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { family = AF_INET; p = inaddr6->s6_addr; inaddr = p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; inaddr = htonl(inaddr); } } #endif for (cidr = cidrs->elts, i = 0; i < cidrs->nelts; i++) { if (cidr[i].family != family) { goto next; } switch (family) { #if (NGX_HAVE_INET6) case AF_INET6: for (n = 0; n < 16; n++) { if ((inaddr6->s6_addr[n] & cidr[i].u.in6.mask.s6_addr[n]) != cidr[i].u.in6.addr.s6_addr[n]) { goto next; } } break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: break; #endif default: /* AF_INET */ if ((inaddr & cidr[i].u.in.mask) != cidr[i].u.in.addr) { goto next; } break; } return NGX_OK; next: continue; } return NGX_DECLINED; } ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len) { in_addr_t inaddr; ngx_uint_t family; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct in6_addr inaddr6; struct sockaddr_in6 *sin6; /* * prevent MSVC8 warning: * potentially uninitialized local variable 'inaddr6' used */ ngx_memzero(&inaddr6, sizeof(struct in6_addr)); #endif inaddr = ngx_inet_addr(text, len); if (inaddr != INADDR_NONE) { family = AF_INET; len = sizeof(struct sockaddr_in); #if (NGX_HAVE_INET6) } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) { family = AF_INET6; len = sizeof(struct sockaddr_in6); #endif } else { return NGX_DECLINED; } addr->sockaddr = ngx_pcalloc(pool, len); if (addr->sockaddr == NULL) { return NGX_ERROR; } addr->sockaddr->sa_family = (u_char) family; addr->socklen = len; switch (family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) addr->sockaddr; ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16); break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) addr->sockaddr; sin->sin_addr.s_addr = inaddr; break; } return NGX_OK; } ngx_int_t ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len) { u_char *p, *last; size_t plen; ngx_int_t rc, port; rc = ngx_parse_addr(pool, addr, text, len); if (rc != NGX_DECLINED) { return rc; } last = text + len; #if (NGX_HAVE_INET6) if (len && text[0] == '[') { p = ngx_strlchr(text, last, ']'); if (p == NULL || p == last - 1 || *++p != ':') { return NGX_DECLINED; } text++; len -= 2; } else #endif { p = ngx_strlchr(text, last, ':'); if (p == NULL) { return NGX_DECLINED; } } p++; plen = last - p; port = ngx_atoi(p, plen); if (port < 1 || port > 65535) { return NGX_DECLINED; } len -= plen + 1; rc = ngx_parse_addr(pool, addr, text, len); if (rc != NGX_OK) { return rc; } ngx_inet_set_port(addr->sockaddr, (in_port_t) port); return NGX_OK; } ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u) { u_char *p; size_t len; p = u->url.data; len = u->url.len; if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) { return ngx_parse_unix_domain_url(pool, u); } if (len && p[0] == '[') { return ngx_parse_inet6_url(pool, u); } return ngx_parse_inet_url(pool, u); } static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u) { #if (NGX_HAVE_UNIX_DOMAIN) u_char *path, *uri, *last; size_t len; struct sockaddr_un *saun; len = u->url.len; path = u->url.data; path += 5; len -= 5; if (u->uri_part) { last = path + len; uri = ngx_strlchr(path, last, ':'); if (uri) { len = uri - path; uri++; u->uri.len = last - uri; u->uri.data = uri; } } if (len == 0) { u->err = "no path in the unix domain socket"; return NGX_ERROR; } u->host.len = len++; u->host.data = path; if (len > sizeof(saun->sun_path)) { u->err = "too long path in the unix domain socket"; return NGX_ERROR; } u->socklen = sizeof(struct sockaddr_un); saun = (struct sockaddr_un *) &u->sockaddr; saun->sun_family = AF_UNIX; (void) ngx_cpystrn((u_char *) saun->sun_path, path, len); u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un)); if (saun == NULL) { return NGX_ERROR; } u->family = AF_UNIX; u->naddrs = 1; saun->sun_family = AF_UNIX; (void) ngx_cpystrn((u_char *) saun->sun_path, path, len); u->addrs[0].sockaddr = (struct sockaddr *) saun; u->addrs[0].socklen = sizeof(struct sockaddr_un); u->addrs[0].name.len = len + 4; u->addrs[0].name.data = u->url.data; return NGX_OK; #else u->err = "the unix domain sockets are not supported on this platform"; return NGX_ERROR; #endif } static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) { u_char *p, *host, *port, *last, *uri, *args; size_t len; ngx_int_t n; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif u->socklen = sizeof(struct sockaddr_in); sin = (struct sockaddr_in *) &u->sockaddr; sin->sin_family = AF_INET; u->family = AF_INET; host = u->url.data; last = host + u->url.len; port = ngx_strlchr(host, last, ':'); uri = ngx_strlchr(host, last, '/'); args = ngx_strlchr(host, last, '?'); if (args) { if (uri == NULL || args < uri) { uri = args; } } if (uri) { if (u->listen || !u->uri_part) { u->err = "invalid host"; return NGX_ERROR; } u->uri.len = last - uri; u->uri.data = uri; last = uri; if (uri < port) { port = NULL; } } if (port) { port++; len = last - port; n = ngx_atoi(port, len); if (n < 1 || n > 65535) { u->err = "invalid port"; return NGX_ERROR; } u->port = (in_port_t) n; sin->sin_port = htons((in_port_t) n); u->port_text.len = len; u->port_text.data = port; last = port - 1; } else { if (uri == NULL) { if (u->listen) { /* test value as port only */ n = ngx_atoi(host, last - host); if (n != NGX_ERROR) { if (n < 1 || n > 65535) { u->err = "invalid port"; return NGX_ERROR; } u->port = (in_port_t) n; sin->sin_port = htons((in_port_t) n); u->port_text.len = last - host; u->port_text.data = host; u->wildcard = 1; return NGX_OK; } } } u->no_port = 1; u->port = u->default_port; sin->sin_port = htons(u->default_port); } len = last - host; if (len == 0) { u->err = "no host"; return NGX_ERROR; } u->host.len = len; u->host.data = host; if (u->listen && len == 1 && *host == '*') { sin->sin_addr.s_addr = INADDR_ANY; u->wildcard = 1; return NGX_OK; } sin->sin_addr.s_addr = ngx_inet_addr(host, len); if (sin->sin_addr.s_addr != INADDR_NONE) { if (sin->sin_addr.s_addr == INADDR_ANY) { u->wildcard = 1; } u->naddrs = 1; u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); if (sin == NULL) { return NGX_ERROR; } ngx_memcpy(sin, &u->sockaddr, sizeof(struct sockaddr_in)); u->addrs[0].sockaddr = (struct sockaddr *) sin; u->addrs[0].socklen = sizeof(struct sockaddr_in); p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); if (p == NULL) { return NGX_ERROR; } u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", &u->host, u->port) - p; u->addrs[0].name.data = p; return NGX_OK; } if (u->no_resolve) { return NGX_OK; } if (ngx_inet_resolve_host(pool, u) != NGX_OK) { return NGX_ERROR; } u->family = u->addrs[0].sockaddr->sa_family; u->socklen = u->addrs[0].socklen; ngx_memcpy(&u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen); switch (u->family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) &u->sockaddr; if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { u->wildcard = 1; } break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) &u->sockaddr; if (sin->sin_addr.s_addr == INADDR_ANY) { u->wildcard = 1; } break; } return NGX_OK; } static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) { #if (NGX_HAVE_INET6) u_char *p, *host, *port, *last, *uri; size_t len; ngx_int_t n; struct sockaddr_in6 *sin6; u->socklen = sizeof(struct sockaddr_in6); sin6 = (struct sockaddr_in6 *) &u->sockaddr; sin6->sin6_family = AF_INET6; host = u->url.data + 1; last = u->url.data + u->url.len; p = ngx_strlchr(host, last, ']'); if (p == NULL) { u->err = "invalid host"; return NGX_ERROR; } port = p + 1; uri = ngx_strlchr(port, last, '/'); if (uri) { if (u->listen || !u->uri_part) { u->err = "invalid host"; return NGX_ERROR; } u->uri.len = last - uri; u->uri.data = uri; last = uri; } if (port < last) { if (*port != ':') { u->err = "invalid host"; return NGX_ERROR; } port++; len = last - port; n = ngx_atoi(port, len); if (n < 1 || n > 65535) { u->err = "invalid port"; return NGX_ERROR; } u->port = (in_port_t) n; sin6->sin6_port = htons((in_port_t) n); u->port_text.len = len; u->port_text.data = port; } else { u->no_port = 1; u->port = u->default_port; sin6->sin6_port = htons(u->default_port); } len = p - host; if (len == 0) { u->err = "no host"; return NGX_ERROR; } u->host.len = len + 2; u->host.data = host - 1; if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) { u->err = "invalid IPv6 address"; return NGX_ERROR; } if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { u->wildcard = 1; } u->family = AF_INET6; u->naddrs = 1; u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } sin6 = ngx_pcalloc(pool, sizeof(struct sockaddr_in6)); if (sin6 == NULL) { return NGX_ERROR; } ngx_memcpy(sin6, &u->sockaddr, sizeof(struct sockaddr_in6)); u->addrs[0].sockaddr = (struct sockaddr *) sin6; u->addrs[0].socklen = sizeof(struct sockaddr_in6); p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); if (p == NULL) { return NGX_ERROR; } u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", &u->host, u->port) - p; u->addrs[0].name.data = p; return NGX_OK; #else u->err = "the INET6 sockets are not supported on this platform"; return NGX_ERROR; #endif } #if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6) ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) { u_char *p, *host; size_t len; in_port_t port; ngx_uint_t i; struct addrinfo hints, *res, *rp; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; port = htons(u->port); host = ngx_alloc(u->host.len + 1, pool->log); if (host == NULL) { return NGX_ERROR; } (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); ngx_memzero(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; #ifdef AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG; #endif if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) { u->err = "host not found"; ngx_free(host); return NGX_ERROR; } ngx_free(host); for (i = 0, rp = res; rp != NULL; rp = rp->ai_next) { switch (rp->ai_family) { case AF_INET: case AF_INET6: break; default: continue; } i++; } if (i == 0) { u->err = "host not found"; goto failed; } /* MP: ngx_shared_palloc() */ u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); if (u->addrs == NULL) { goto failed; } u->naddrs = i; i = 0; /* AF_INET addresses first */ for (rp = res; rp != NULL; rp = rp->ai_next) { if (rp->ai_family != AF_INET) { continue; } sin = ngx_pcalloc(pool, rp->ai_addrlen); if (sin == NULL) { goto failed; } ngx_memcpy(sin, rp->ai_addr, rp->ai_addrlen); sin->sin_port = port; u->addrs[i].sockaddr = (struct sockaddr *) sin; u->addrs[i].socklen = rp->ai_addrlen; len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; p = ngx_pnalloc(pool, len); if (p == NULL) { goto failed; } len = ngx_sock_ntop((struct sockaddr *) sin, rp->ai_addrlen, p, len, 1); u->addrs[i].name.len = len; u->addrs[i].name.data = p; i++; } for (rp = res; rp != NULL; rp = rp->ai_next) { if (rp->ai_family != AF_INET6) { continue; } sin6 = ngx_pcalloc(pool, rp->ai_addrlen); if (sin6 == NULL) { goto failed; } ngx_memcpy(sin6, rp->ai_addr, rp->ai_addrlen); sin6->sin6_port = port; u->addrs[i].sockaddr = (struct sockaddr *) sin6; u->addrs[i].socklen = rp->ai_addrlen; len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; p = ngx_pnalloc(pool, len); if (p == NULL) { goto failed; } len = ngx_sock_ntop((struct sockaddr *) sin6, rp->ai_addrlen, p, len, 1); u->addrs[i].name.len = len; u->addrs[i].name.data = p; i++; } freeaddrinfo(res); return NGX_OK; failed: freeaddrinfo(res); return NGX_ERROR; } #else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */ ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) { u_char *p, *host; size_t len; in_port_t port; in_addr_t in_addr; ngx_uint_t i; struct hostent *h; struct sockaddr_in *sin; /* AF_INET only */ port = htons(u->port); in_addr = ngx_inet_addr(u->host.data, u->host.len); if (in_addr == INADDR_NONE) { host = ngx_alloc(u->host.len + 1, pool->log); if (host == NULL) { return NGX_ERROR; } (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); h = gethostbyname((char *) host); ngx_free(host); if (h == NULL || h->h_addr_list[0] == NULL) { u->err = "host not found"; return NGX_ERROR; } for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } /* MP: ngx_shared_palloc() */ u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } u->naddrs = i; for (i = 0; i < u->naddrs; i++) { sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); if (sin == NULL) { return NGX_ERROR; } sin->sin_family = AF_INET; sin->sin_port = port; sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]); u->addrs[i].sockaddr = (struct sockaddr *) sin; u->addrs[i].socklen = sizeof(struct sockaddr_in); len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; p = ngx_pnalloc(pool, len); if (p == NULL) { return NGX_ERROR; } len = ngx_sock_ntop((struct sockaddr *) sin, sizeof(struct sockaddr_in), p, len, 1); u->addrs[i].name.len = len; u->addrs[i].name.data = p; } } else { /* MP: ngx_shared_palloc() */ u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); if (sin == NULL) { return NGX_ERROR; } u->naddrs = 1; sin->sin_family = AF_INET; sin->sin_port = port; sin->sin_addr.s_addr = in_addr; u->addrs[0].sockaddr = (struct sockaddr *) sin; u->addrs[0].socklen = sizeof(struct sockaddr_in); p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); if (p == NULL) { return NGX_ERROR; } u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", &u->host, ntohs(port)) - p; u->addrs[0].name.data = p; } return NGX_OK; } #endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */ ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port) { struct sockaddr_in *sin1, *sin2; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin61, *sin62; #endif #if (NGX_HAVE_UNIX_DOMAIN) size_t len; struct sockaddr_un *saun1, *saun2; #endif if (sa1->sa_family != sa2->sa_family) { return NGX_DECLINED; } switch (sa1->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin61 = (struct sockaddr_in6 *) sa1; sin62 = (struct sockaddr_in6 *) sa2; if (cmp_port && sin61->sin6_port != sin62->sin6_port) { return NGX_DECLINED; } if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) { return NGX_DECLINED; } break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: saun1 = (struct sockaddr_un *) sa1; saun2 = (struct sockaddr_un *) sa2; if (slen1 < slen2) { len = slen1 - offsetof(struct sockaddr_un, sun_path); } else { len = slen2 - offsetof(struct sockaddr_un, sun_path); } if (len > sizeof(saun1->sun_path)) { len = sizeof(saun1->sun_path); } if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, len) != 0) { return NGX_DECLINED; } break; #endif default: /* AF_INET */ sin1 = (struct sockaddr_in *) sa1; sin2 = (struct sockaddr_in *) sa2; if (cmp_port && sin1->sin_port != sin2->sin_port) { return NGX_DECLINED; } if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { return NGX_DECLINED; } break; } return NGX_OK; } in_port_t ngx_inet_get_port(struct sockaddr *sa) { struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif switch (sa->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) sa; return ntohs(sin6->sin6_port); #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: return 0; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) sa; return ntohs(sin->sin_port); } } void ngx_inet_set_port(struct sockaddr *sa, in_port_t port) { struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif switch (sa->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) sa; sin6->sin6_port = htons(port); break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) sa; sin->sin_port = htons(port); break; } }