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;
}