text: 
  /*
   * 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);
  
  //将一个字符串IP 转为 in_addr_t 数字
  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
  
  //sockaddr[]转换成可读的字符串形式 /* 将二进制的地址结构，转换为文本格式 127.0.0.1:80*/
  size_t
  ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len,
      ngx_uint_t port)
  {
      u_char               *p;
  #if (NGX_HAVE_INET6 || NGX_HAVE_UNIX_DOMAIN)
      size_t                n;
  #endif
      struct sockaddr_in   *sin;
  #if (NGX_HAVE_INET6)
      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 {
              n = ngx_strnlen((u_char *) saun->sun_path,
                              socklen - offsetof(struct sockaddr_un, sun_path));
              p = ngx_snprintf(text, len, "unix:%*s%Z", n, 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
  
  // 计算ip地址和掩码
  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;
      }
  }
  