int jk_resolve()

in native/common/jk_connect.c [400:601]


int jk_resolve(const char *host, int port, jk_sockaddr_t *saddr,
               void *pool, int prefer_ipv6, jk_log_context_t *l)
{
    int family = JK_INET;
    struct in_addr iaddr;

    JK_TRACE_ENTER(l);

    memset(saddr, 0, sizeof(jk_sockaddr_t));
    if (*host >= '0' && *host <= '9' && strspn(host, "0123456789.") == strlen(host)) {

        /* If we found only digits we use inet_addr() */
        iaddr.s_addr = jk_inet_addr(host);
        memcpy(&(saddr->sa.sin.sin_addr), &iaddr, sizeof(struct in_addr));
    }
    else {
#ifdef HAVE_APR
        apr_sockaddr_t *remote_sa, *temp_sa;

        if (!jk_apr_pool) {
            if (apr_pool_create(&jk_apr_pool, (apr_pool_t *)pool) != APR_SUCCESS) {
                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
        }
        apr_pool_clear(jk_apr_pool);
        if (apr_sockaddr_info_get(&remote_sa, host, APR_UNSPEC, (apr_port_t)port,
                                  0, jk_apr_pool) != APR_SUCCESS) {
            JK_TRACE_EXIT(l);
            return JK_FALSE;
        }

        /* Check if we have multiple address matches
         */
        if (remote_sa->next) {
            /* Since we are only handling JK_INET (IPV4) address (in_addr_t) */
            /* make sure we find one of those.                               */
            temp_sa = remote_sa;
#if APR_HAVE_IPV6
            if (prefer_ipv6) {
                while ((NULL != temp_sa) && (APR_INET6 != temp_sa->family))
                    temp_sa = temp_sa->next;
            }
#endif
            if (NULL != temp_sa) {
                remote_sa = temp_sa;
            }
            else {
                while ((NULL != temp_sa) && (APR_INET != temp_sa->family))
                    temp_sa = temp_sa->next;
#if APR_HAVE_IPV6
                if (NULL == temp_sa) {
                    temp_sa = remote_sa;
                    while ((NULL != temp_sa) && (APR_INET6 != temp_sa->family))
                        temp_sa = temp_sa->next;
                }
#endif
            }
            /* if temp_sa is set, we have a valid address otherwise, just return */
            if (NULL != temp_sa) {
                remote_sa = temp_sa;
            }
            else {
                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
        }
        if (remote_sa->family == APR_INET) {
            saddr->sa.sin = remote_sa->sa.sin;
            family = JK_INET;
        }
#if APR_HAVE_IPV6
        else {
            saddr->sa.sin6 = remote_sa->sa.sin6;
            family = JK_INET6;
        }
#endif
#else /* HAVE_APR */
        /* Without APR go the classic way.
         */
#if defined(HAVE_GETADDRINFO)
        /* TODO:
         * 1. Check for numeric IPV6 addresses
         * 2. Do we need to set service name for getaddrinfo?
         */
        struct addrinfo hints, *ai_list, *ai = NULL;
        int error;
        char  pbuf[12];
        char *pbufptr = NULL;

        memset(&hints, 0, sizeof(hints));
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;

#if JK_HAVE_IPV6
        if (strchr(host, ':')) {
            /* If host name contains colon this must be IPV6 address.
             * Set prefer_ipv6 flag in this case if it wasn't set already
             */
            prefer_ipv6 = 1;
        }
        if (prefer_ipv6)
            hints.ai_family = JK_INET6;
        else
#endif
            hints.ai_family = JK_INET;
        if (port > 0) {
            snprintf(pbuf, sizeof(pbuf), "%d", port);
            pbufptr = pbuf;
        }
        error = getaddrinfo(host, pbufptr, &hints, &ai_list);
#if JK_HAVE_IPV6
        /* XXX:
         * Is the check for EAI_FAMILY/WSAEAFNOSUPPORT correct
         * way to retry the IPv4 address?
         */
        if (error == EAI_FAMILY && prefer_ipv6) {
            hints.ai_family = JK_INET;
            error = getaddrinfo(host, pbufptr, &hints, &ai_list);
        }
#endif
        if (error) {
            JK_TRACE_EXIT(l);
            errno = error;
            return JK_FALSE;
        }
#if JK_HAVE_IPV6
        if (prefer_ipv6) {
            ai = ai_list;
            while (ai) {
                if (ai->ai_family == JK_INET6) {
                    /* ignore elements without required address info */
                    if((ai->ai_addr != NULL) && (ai->ai_addrlen > 0)) {
                        family = JK_INET6;
                        break;
                    }
                }
                ai = ai->ai_next;
            }
        }
#endif
        if (ai == NULL) {
            ai = ai_list;
            while (ai) {
                if (ai->ai_family == JK_INET) {
                    /* ignore elements without required address info */
                    if((ai->ai_addr != NULL) && (ai->ai_addrlen > 0)) {
                        family = JK_INET;
                        break;
                    }
                }
                ai = ai->ai_next;
            }
        }
        if (ai == NULL) {
            /* No address found
             * XXX: Use better error code?
             */
            freeaddrinfo(ai_list);
            JK_TRACE_EXIT(l);
            errno = ENOENT;
            return JK_FALSE;
        }
        memcpy(&(saddr->sa), ai->ai_addr, ai->ai_addrlen);
        freeaddrinfo(ai_list);
#else /* HAVE_GETADDRINFO */
        struct hostent *hoste;

        /* XXX : WARNING : We should really use gethostbyname_r in multi-threaded env */
        /* Fortunatly when APR is available, ie under Apache 2.0, we use it */
        hoste = gethostbyname(host);
        if (!hoste) {
            JK_TRACE_EXIT(l);
            return JK_FALSE;
        }
        iaddr = *((struct in_addr *)hoste->h_addr_list[0]);
        memcpy(&(saddr->sa.sin.sin_addr), &iaddr, sizeof(struct in_addr));
#endif /* HAVE_GETADDRINFO */
#endif /* HAVE_APR */
    }

    if (family == JK_INET) {
        saddr->ipaddr_ptr = &(saddr->sa.sin.sin_addr);
        saddr->ipaddr_len = (int)sizeof(struct in_addr);
        saddr->salen      = (int)sizeof(struct sockaddr_in);
    }
#if JK_HAVE_IPV6
    else {
        saddr->ipaddr_ptr = &(saddr->sa.sin6.sin6_addr);
        saddr->ipaddr_len = (int)sizeof(struct in6_addr);
        saddr->salen      = (int)sizeof(struct sockaddr_in6);
    }
#endif
    saddr->sa.sin.sin_family = family;
    /* XXX IPv6: assumes sin_port and sin6_port at same offset */
    saddr->sa.sin.sin_port = htons(port);
    saddr->port   = port;
    saddr->family = family;

    JK_TRACE_EXIT(l);
    return JK_TRUE;
}