Alien-cares

 view release on metacpan or  search on metacpan

libcares/ares_getaddrinfo.c  view on Meta::CPAN

      const struct sockaddr_in6 *a1_dst =
          (const struct sockaddr_in6 *)a1->ai->ai_addr;
      const struct sockaddr_in6 *a2_src = &a2->src_addr.sa6;
      const struct sockaddr_in6 *a2_dst =
          (const struct sockaddr_in6 *)a2->ai->ai_addr;
      prefixlen1 = common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr);
      prefixlen2 = common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr);
      if (prefixlen1 != prefixlen2)
        {
          return prefixlen2 - prefixlen1;
        }
    }

  /*
   * Rule 10: Leave the order unchanged.
   * We need this since qsort() is not necessarily stable.
   */
  return a1->original_order - a2->original_order;
}

static int get_scope(const struct sockaddr *addr)
{
  if (addr->sa_family == AF_INET6)
    {
      const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
      if (IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr))
        {
          return IPV6_ADDR_MC_SCOPE(&addr6->sin6_addr);
        }
      else if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) ||
               IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr))
        {
          /*
           * RFC 4291 section 2.5.3 says loopback is to be treated as having
           * link-local scope.
           */
          return IPV6_ADDR_SCOPE_LINKLOCAL;
        }
      else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr))
        {
          return IPV6_ADDR_SCOPE_SITELOCAL;
        }
      else
        {
          return IPV6_ADDR_SCOPE_GLOBAL;
        }
    }
  else if (addr->sa_family == AF_INET)
    {
      const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
      unsigned long int na = ntohl(addr4->sin_addr.s_addr);
      if (IN_LOOPBACK(na) || /* 127.0.0.0/8 */
          (na & 0xffff0000) == 0xa9fe0000)
        { /* 169.254.0.0/16 */
          return IPV6_ADDR_SCOPE_LINKLOCAL;
        }
      else
        {
          /*
           * RFC 6724 section 3.2. Other IPv4 addresses, including private
           * addresses and shared addresses (100.64.0.0/10), are assigned global
           * scope.
           */
          return IPV6_ADDR_SCOPE_GLOBAL;
        }
    }
  else
    {
      /*
       * This should never happen.
       * Return a scope with low priority as a last resort.
       */
      return IPV6_ADDR_SCOPE_NODELOCAL;
    }
}

static int get_label(const struct sockaddr *addr)
{
  if (addr->sa_family == AF_INET)
    {
      return 4;
    }
  else if (addr->sa_family == AF_INET6)
    {
      const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
      if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr))
        {
          return 0;
        }
      else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr))
        {
          return 4;
        }
      else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr))
        {
          return 2;
        }
      else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr))
        {
          return 5;
        }
      else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr))
        {
          return 13;
        }
      else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr))
        {
          return 3;
        }
      else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr))
        {
          return 11;
        }
      else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr))
        {
          return 12;
        }
      else
        {
          /* All other IPv6 addresses, including global unicast addresses. */
          return 1;
        }
    }
  else
    {
      /*
       * This should never happen.
       * Return a semi-random label as a last resort.
       */
      return 1;
    }
}

/*
 * Get the precedence for a given IPv4/IPv6 address.
 * RFC 6724, section 2.1.
 */
static int get_precedence(const struct sockaddr *addr)
{
  if (addr->sa_family == AF_INET)
    {
      return 35;
    }
  else if (addr->sa_family == AF_INET6)
    {
      const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
      if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr))
        {
          return 50;
        }
      else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr))
        {
          return 35;
        }
      else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr))
        {
          return 30;
        }
      else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr))
        {
          return 5;
        }
      else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr))
        {
          return 3;
        }
      else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) ||
               IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) ||
               IN6_IS_ADDR_6BONE(&addr6->sin6_addr))
        {
          return 1;
        }
      else
        {
          /* All other IPv6 addresses, including global unicast addresses. */
          return 40;
        }
    }
  else
    {
      return 1;
    }
}

static int common_prefix_len(const struct in6_addr *a1,
                             const struct in6_addr *a2)
{
  const char *p1 = (const char *)a1;
  const char *p2 = (const char *)a2;
  unsigned i;

  for (i = 0; i < sizeof(*a1); ++i)
    {
      int x, j;

      if (p1[i] == p2[i])
        {
          continue;
        }
      x = p1[i] ^ p2[i];
      for (j = 0; j < CHAR_BIT; ++j)
        {
          if (x & (1 << (CHAR_BIT - 1)))
            {
              return i * CHAR_BIT + j;
            }
          x <<= 1;
        }
    }
  return sizeof(*a1) * CHAR_BIT;
}



( run in 0.482 second using v1.01-cache-2.11-cpan-e1769b4cff6 )