/* Set address from a name */
PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af,
					     pj_sockaddr *addr,
					     const pj_str_t *str_addr)
{
    pj_status_t status;

    if (af == PJ_AF_INET) {
	return pj_sockaddr_in_set_str_addr(&addr->ipv4, str_addr);
    }

    PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP);

    /* IPv6 specific */

    addr->ipv6.sin6_family = PJ_AF_INET6;
    PJ_SOCKADDR_RESET_LEN(addr);

    if (str_addr && str_addr->slen) {
	status = pj_inet_pton(PJ_AF_INET6, str_addr, &addr->ipv6.sin6_addr);
	if (status != PJ_SUCCESS) {
    	    pj_addrinfo ai;
	    unsigned count = 1;

	    status = pj_getaddrinfo(PJ_AF_INET6, str_addr, &count, &ai);
	    if (status==PJ_SUCCESS) {
		pj_memcpy(&addr->ipv6.sin6_addr, &ai.ai_addr.ipv6.sin6_addr,
			  sizeof(pj_sockaddr_in6));
	    }
	}
    } else {
	status = PJ_SUCCESS;
    }

    return status;
}
Exemple #2
0
/*
 * Accept incoming connections
 */
PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
				    pj_sock_t *newsock,
				    pj_sockaddr_t *addr,
				    int *addrlen)
{
    PJ_CHECK_STACK();
    PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);

#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
    if (addr) {
	PJ_SOCKADDR_SET_LEN(addr, *addrlen);
    }
#endif
    
    *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
    if (*newsock==PJ_INVALID_SOCKET)
	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
    else {
	
#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
	if (addr) {
	    PJ_SOCKADDR_RESET_LEN(addr);
	}
#endif
	    
	return PJ_SUCCESS;
    }
}
Exemple #3
0
/*
 * Set the IP address of an IP socket address from string address, 
 * with resolving the host if necessary. The string address may be in a
 * standard numbers and dots notation or may be a hostname. If hostname
 * is specified, then the function will resolve the host into the IP
 * address.
 */
PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
					         const pj_str_t *str_addr)
{
    PJ_CHECK_STACK();

    PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME, 
                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));

    PJ_SOCKADDR_RESET_LEN(addr);
    addr->sin_family = PJ_AF_INET;
    pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));

    if (str_addr && str_addr->slen) {
	addr->sin_addr = pj_inet_addr(str_addr);
	if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
    	    pj_hostent he;
	    pj_status_t rc;

	    rc = pj_gethostbyname(str_addr, &he);
	    if (rc == 0) {
		addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
	    } else {
		addr->sin_addr.s_addr = PJ_INADDR_NONE;
		return rc;
	    }
	}

    } else {
	addr->sin_addr.s_addr = 0;
    }

    return PJ_SUCCESS;
}
Exemple #4
0
/*
 * Get socket name.
 */
PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
					 pj_sockaddr_t *addr,
					 int *namelen)
{
    PJ_CHECK_STACK();
    if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
    else {
	PJ_SOCKADDR_RESET_LEN(addr);
	return PJ_SUCCESS;
    }
}
Exemple #5
0
/*
 * Set the IP address and port of an IP socket address.
 * The string address may be in a standard numbers and dots notation or 
 * may be a hostname. If hostname is specified, then the function will 
 * resolve the host into the IP address.
 */
PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
				         const pj_str_t *str_addr,
					 pj_uint16_t port)
{
    PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));

    PJ_SOCKADDR_RESET_LEN(addr);
    addr->sin_family = PJ_AF_INET;
    pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
    pj_sockaddr_in_set_port(addr, port);
    return pj_sockaddr_in_set_str_addr(addr, str_addr);
}
Exemple #6
0
/*
 * Receive data.
 */
PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
				     void *buf,
				     pj_ssize_t *len,
				     unsigned flags,
				     pj_sockaddr_t *from,
				     int *fromlen)
{
    PJ_CHECK_STACK();
    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
    PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));

    *len = recvfrom(sock, (char*)buf, *len, flags, 
		    (struct sockaddr*)from, (socklen_t*)fromlen);

    if (*len < 0) 
	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
    else {
	PJ_SOCKADDR_RESET_LEN(from);
	return PJ_SUCCESS;
    }
}
/* Resolve the IP address of local machine */
PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
{
    unsigned i, count, cand_cnt;
    enum {
	CAND_CNT = 8,

	/* Weighting to be applied to found addresses */
	WEIGHT_HOSTNAME	= 1,	/* hostname IP is not always valid! */
	WEIGHT_DEF_ROUTE = 2,
	WEIGHT_INTERFACE = 1,
	WEIGHT_LOOPBACK = -5,
	WEIGHT_LINK_LOCAL = -4,
	WEIGHT_DISABLED = -50,

	MIN_WEIGHT = WEIGHT_DISABLED+1	/* minimum weight to use */
    };
    /* candidates: */
    pj_sockaddr cand_addr[CAND_CNT];
    int		cand_weight[CAND_CNT];
    int	        selected_cand;
    char	strip[PJ_INET6_ADDRSTRLEN+10];
    /* Special IPv4 addresses. */
    struct spec_ipv4_t
    {
	pj_uint32_t addr;
	pj_uint32_t mask;
	int	    weight;
    } spec_ipv4[] =
    {
	/* 127.0.0.0/8, loopback addr will be used if there is no other
	 * addresses.
	 */
	{ 0x7f000000, 0xFF000000, WEIGHT_LOOPBACK },

	/* 0.0.0.0/8, special IP that doesn't seem to be practically useful */
	{ 0x00000000, 0xFF000000, WEIGHT_DISABLED },

	/* 169.254.0.0/16, a zeroconf/link-local address, which has higher
	 * priority than loopback and will be used if there is no other
	 * valid addresses.
	 */
	{ 0xa9fe0000, 0xFFFF0000, WEIGHT_LINK_LOCAL }
    };
    /* Special IPv6 addresses */
    struct spec_ipv6_t
    {
	pj_uint8_t addr[16];
	pj_uint8_t mask[16];
	int	   weight;
    } spec_ipv6[] =
    {
	/* Loopback address, ::1/128 */
	{ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	  {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	   0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
	  WEIGHT_LOOPBACK
	},

	/* Link local, fe80::/10 */
	{ {0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	  {0xff,0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	  WEIGHT_LINK_LOCAL
	},

	/* Disabled, ::/128 */
	{ {0x0,0x0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
	  WEIGHT_DISABLED
	}
    };
    pj_addrinfo ai;
    pj_status_t status;

    /* May not be used if TRACE_ is disabled */
    PJ_UNUSED_ARG(strip);

#ifdef _MSC_VER
    /* Get rid of "uninitialized he variable" with MS compilers */
    pj_bzero(&ai, sizeof(ai));
#endif

    cand_cnt = 0;
    pj_bzero(cand_addr, sizeof(cand_addr));
    pj_bzero(cand_weight, sizeof(cand_weight));
    for (i=0; i<PJ_ARRAY_SIZE(cand_addr); ++i) {
	cand_addr[i].addr.sa_family = (pj_uint16_t)af;
	PJ_SOCKADDR_RESET_LEN(&cand_addr[i]);
    }

    addr->addr.sa_family = (pj_uint16_t)af;
    PJ_SOCKADDR_RESET_LEN(addr);

#if !defined(PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION) || \
	PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION == 0
	TRACE_((THIS_FILE, "pj_gethostip() pj_getaddrinfo1"));
    /* Get hostname's IP address */
    count = 1;
    status = pj_getaddrinfo(af, pj_gethostname(), &count, &ai);
    if (status == PJ_SUCCESS) {
    	pj_assert(ai.ai_addr.addr.sa_family == (pj_uint16_t)af);
    	pj_sockaddr_copy_addr(&cand_addr[cand_cnt], &ai.ai_addr);
	pj_sockaddr_set_port(&cand_addr[cand_cnt], 0);
	cand_weight[cand_cnt] += WEIGHT_HOSTNAME;
	++cand_cnt;

	TRACE_((THIS_FILE, "hostname IP is %s",
		pj_sockaddr_print(&ai.ai_addr, strip, sizeof(strip), 0)));
	}
	TRACE_((THIS_FILE, "pj_gethostip() pj_getaddrinfo2"));
#else
    PJ_UNUSED_ARG(ai);
    PJ_UNUSED_ARG(count);
#endif

    /* Get default interface (interface for default route) */
    if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
	status = pj_getdefaultipinterface(af, addr);
	if (status == PJ_SUCCESS) {
	    TRACE_((THIS_FILE, "default IP is %s",
		    pj_sockaddr_print(addr, strip, sizeof(strip), 0)));

	    pj_sockaddr_set_port(addr, 0);
	    for (i=0; i<cand_cnt; ++i) {
		if (pj_sockaddr_cmp(&cand_addr[i], addr)==0)
		    break;
	    }

	    cand_weight[i] += WEIGHT_DEF_ROUTE;
	    if (i >= cand_cnt) {
		pj_sockaddr_copy_addr(&cand_addr[i], addr);
		++cand_cnt;
	    }
	}
    }


    /* Enumerate IP interfaces */
    if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
	unsigned start_if = cand_cnt;
	unsigned count = PJ_ARRAY_SIZE(cand_addr) - start_if;

	status = pj_enum_ip_interface(af, &count, &cand_addr[start_if]);
	if (status == PJ_SUCCESS && count) {
	    /* Clear the port number */
	    for (i=0; i<count; ++i)            
		pj_sockaddr_set_port(&cand_addr[start_if+i], 0);

	    /* For each candidate that we found so far (that is the hostname
	     * address and default interface address, check if they're found
	     * in the interface list. If found, add the weight, and if not,
	     * decrease the weight.
	     */
	    for (i=0; i<cand_cnt; ++i) {
		unsigned j;
		for (j=0; j<count; ++j) {
		    if (pj_sockaddr_cmp(&cand_addr[i], 
					&cand_addr[start_if+j])==0)
			break;
		}

		if (j == count) {
		    /* Not found */
		    cand_weight[i] -= WEIGHT_INTERFACE;
		} else {
		    cand_weight[i] += WEIGHT_INTERFACE;
		}
	    }

	    /* Add remaining interface to candidate list. */
	    for (i=0; i<count; ++i) {
		unsigned j;
		for (j=0; j<cand_cnt; ++j) {
		    if (pj_sockaddr_cmp(&cand_addr[start_if+i], 
					&cand_addr[j])==0)
			break;
		}

		if (j == cand_cnt) {
		    pj_sockaddr_copy_addr(&cand_addr[cand_cnt], 
					  &cand_addr[start_if+i]);
		    cand_weight[cand_cnt] += WEIGHT_INTERFACE;
		    ++cand_cnt;
		}
	    }
	}
    }

    /* Apply weight adjustment for special IPv4/IPv6 addresses
     * See http://trac.pjsip.org/repos/ticket/1046
     */
    if (af == PJ_AF_INET) {
	for (i=0; i<cand_cnt; ++i) {
	    unsigned j;
	    for (j=0; j<PJ_ARRAY_SIZE(spec_ipv4); ++j) {
		    pj_uint32_t a = pj_ntohl(cand_addr[i].ipv4.sin_addr.s_addr);
		    pj_uint32_t pa = spec_ipv4[j].addr;
		    pj_uint32_t pm = spec_ipv4[j].mask;

		    if ((a & pm) == pa) {
			cand_weight[i] += spec_ipv4[j].weight;
			break;
		    }
	    }
	}
    } else if (af == PJ_AF_INET6) {
	for (i=0; i<PJ_ARRAY_SIZE(spec_ipv6); ++i) {
		unsigned j;
		for (j=0; j<cand_cnt; ++j) {
		    pj_uint8_t *a = cand_addr[j].ipv6.sin6_addr.s6_addr;
		    pj_uint8_t am[16];
		    pj_uint8_t *pa = spec_ipv6[i].addr;
		    pj_uint8_t *pm = spec_ipv6[i].mask;
		    unsigned k;

		    for (k=0; k<16; ++k) {
			am[k] = (pj_uint8_t)((a[k] & pm[k]) & 0xFF);
		    }

		    if (pj_memcmp(am, pa, 16)==0) {
			cand_weight[j] += spec_ipv6[i].weight;
		    }
		}
	}
    } else {
	return PJ_EAFNOTSUP;
    }

    /* Enumerate candidates to get the best IP address to choose */
    selected_cand = -1;
    for (i=0; i<cand_cnt; ++i) {
	TRACE_((THIS_FILE, "Checking candidate IP %s, weight=%d",
		pj_sockaddr_print(&cand_addr[i], strip, sizeof(strip), 0),
		cand_weight[i]));

	if (cand_weight[i] < MIN_WEIGHT) {
	    continue;
	}

	if (selected_cand == -1)
	    selected_cand = i;
	else if (cand_weight[i] > cand_weight[selected_cand])
	    selected_cand = i;
    }

    /* If else fails, returns loopback interface as the last resort */
    if (selected_cand == -1) {
	if (af==PJ_AF_INET) {
	    addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001);
	} else {
	    pj_in6_addr *s6_addr;

	    s6_addr = (pj_in6_addr*) pj_sockaddr_get_addr(addr);
	    pj_bzero(s6_addr, sizeof(pj_in6_addr));
	    s6_addr->s6_addr[15] = 1;
	}
	TRACE_((THIS_FILE, "Loopback IP %s returned",
		pj_sockaddr_print(addr, strip, sizeof(strip), 0)));
    } else {
	pj_sockaddr_copy_addr(addr, &cand_addr[selected_cand]);
	TRACE_((THIS_FILE, "Candidate %s selected",
		pj_sockaddr_print(addr, strip, sizeof(strip), 0)));
    }

    return PJ_SUCCESS;
}
Exemple #8
0
/* Resolve IPv4/IPv6 address */
PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
				   unsigned *count, pj_addrinfo ai[])
{
#if defined(PJ_SOCK_HAS_GETADDRINFO) && PJ_SOCK_HAS_GETADDRINFO!=0
    char nodecopy[PJ_MAX_HOSTNAME];
    struct addrinfo hint, *res, *orig_res;
    unsigned i;
    int rc;

    PJ_ASSERT_RETURN(nodename && count && *count && ai, PJ_EINVAL);
    PJ_ASSERT_RETURN(nodename->ptr && nodename->slen, PJ_EINVAL);
    PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6 ||
		     af==PJ_AF_UNSPEC, PJ_EINVAL);

    /* Check if nodename is IP address */
    pj_bzero(&ai[0], sizeof(ai[0]));
    if (af == PJ_AF_UNSPEC) {
	if (pj_inet_pton(PJ_AF_INET, nodename, 
			 &ai[0].ai_addr.ipv4.sin_addr) == PJ_SUCCESS)
	{
	    af = PJ_AF_INET;
	}
	else if (pj_inet_pton(PJ_AF_INET6, nodename, 
			      &ai[0].ai_addr.ipv6.sin6_addr) == PJ_SUCCESS)
	{
	    af = PJ_AF_INET6;
	}

	if (af != PJ_AF_UNSPEC) {
	    pj_str_t tmp;

	    tmp.ptr = ai[0].ai_canonname;
	    pj_strncpy_with_null(&tmp, nodename, PJ_MAX_HOSTNAME);
	    ai[0].ai_addr.addr.sa_family = (pj_uint16_t)af;
	    *count = 1;

	    return PJ_SUCCESS;
	}
    }

    /* Copy node name to null terminated string. */
    if (nodename->slen >= PJ_MAX_HOSTNAME)
	return PJ_ENAMETOOLONG;
    pj_memcpy(nodecopy, nodename->ptr, nodename->slen);
    nodecopy[nodename->slen] = '\0';

    /* Call getaddrinfo() */
    pj_bzero(&hint, sizeof(hint));
    hint.ai_family = af;

    rc = getaddrinfo(nodecopy, NULL, &hint, &res);
    if (rc != 0)
	return PJ_ERESOLVE;

    orig_res = res;

    /* Enumerate each item in the result */
    for (i=0; i<*count && res; res=res->ai_next) {
	/* Ignore unwanted address families */
	if (af!=PJ_AF_UNSPEC && res->ai_family != af)
	    continue;

	/* Store canonical name (possibly truncating the name) */
	if (res->ai_canonname) {
	    pj_ansi_strncpy(ai[i].ai_canonname, res->ai_canonname,
			    sizeof(ai[i].ai_canonname));
	    ai[i].ai_canonname[sizeof(ai[i].ai_canonname)-1] = '\0';
	} else {
	    pj_ansi_strcpy(ai[i].ai_canonname, nodecopy);
	}

	/* Store address */
	PJ_ASSERT_ON_FAIL(res->ai_addrlen <= sizeof(pj_sockaddr), continue);
	pj_memcpy(&ai[i].ai_addr, res->ai_addr, res->ai_addrlen);
	PJ_SOCKADDR_RESET_LEN(&ai[i].ai_addr);

	/* Next slot */
	++i;
    }

    *count = i;

    freeaddrinfo(orig_res);

    /* Done */
    return PJ_SUCCESS;

#else	/* PJ_SOCK_HAS_GETADDRINFO */

    PJ_ASSERT_RETURN(count && *count, PJ_EINVAL);

    /* Check if nodename is IP address */
    pj_bzero(&ai[0], sizeof(ai[0]));
    if (af == PJ_AF_UNSPEC) {
	if (pj_inet_pton(PJ_AF_INET, nodename, 
			 &ai[0].ai_addr.ipv4.sin_addr) == PJ_SUCCESS)
	{
	    af = PJ_AF_INET;
	}
	else if (pj_inet_pton(PJ_AF_INET6, nodename, 
			      &ai[0].ai_addr.ipv6.sin6_addr) == PJ_SUCCESS)
	{
	    af = PJ_AF_INET6;
	}

	if (af != PJ_AF_UNSPEC) {
	    pj_str_t tmp;

	    tmp.ptr = ai[0].ai_canonname;
	    pj_strncpy_with_null(&tmp, nodename, PJ_MAX_HOSTNAME);
	    ai[0].ai_addr.addr.sa_family = (pj_uint16_t)af;
	    *count = 1;

	    return PJ_SUCCESS;
	}
    }

    if (af == PJ_AF_INET || af == PJ_AF_UNSPEC) {
	pj_hostent he;
	unsigned i, max_count;
	pj_status_t status;
	
	/* VC6 complains that "he" is uninitialized */
	#ifdef _MSC_VER
	pj_bzero(&he, sizeof(he));
	#endif

	status = pj_gethostbyname(nodename, &he);
	if (status != PJ_SUCCESS)
	    return status;

	max_count = *count;
	*count = 0;

	pj_bzero(ai, max_count * sizeof(pj_addrinfo));

	for (i=0; he.h_addr_list[i] && *count<max_count; ++i) {
	    pj_ansi_strncpy(ai[*count].ai_canonname, he.h_name,
			    sizeof(ai[*count].ai_canonname));
	    ai[*count].ai_canonname[sizeof(ai[*count].ai_canonname)-1] = '\0';

	    ai[*count].ai_addr.ipv4.sin_family = PJ_AF_INET;
	    pj_memcpy(&ai[*count].ai_addr.ipv4.sin_addr,
		      he.h_addr_list[i], he.h_length);
	    PJ_SOCKADDR_RESET_LEN(&ai[*count].ai_addr);

	    (*count)++;
	}

	return PJ_SUCCESS;

    } else {
	/* IPv6 is not supported */
	*count = 0;

	return PJ_EIPV6NOTSUP;
    }
#endif	/* PJ_SOCK_HAS_GETADDRINFO */
}
/* Resolve IPv4/IPv6 address */
PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
				   unsigned *count, pj_addrinfo ai[])
{
#if defined(PJ_SOCK_HAS_GETADDRINFO) && PJ_SOCK_HAS_GETADDRINFO!=0
    char nodecopy[PJ_MAX_HOSTNAME];
    pj_bool_t has_addr = PJ_FALSE;
    unsigned i;
#if defined(PJ_GETADDRINFO_USE_CFHOST) && PJ_GETADDRINFO_USE_CFHOST!=0
    CFStringRef hostname;
    CFHostRef hostRef;
    pj_status_t status = PJ_SUCCESS;
#else
    int rc;
    struct addrinfo hint, *res, *orig_res;
#endif

    PJ_ASSERT_RETURN(nodename && count && *count && ai, PJ_EINVAL);
    PJ_ASSERT_RETURN(nodename->ptr && nodename->slen, PJ_EINVAL);
    PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6 ||
		     af==PJ_AF_UNSPEC, PJ_EINVAL);

    /* Check if nodename is IP address */
    pj_bzero(&ai[0], sizeof(ai[0]));
    if ((af==PJ_AF_INET || af==PJ_AF_UNSPEC) &&
	pj_inet_pton(PJ_AF_INET, nodename,
		     &ai[0].ai_addr.ipv4.sin_addr) == PJ_SUCCESS)
    {
	af = PJ_AF_INET;
	has_addr = PJ_TRUE;
    } else if ((af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) &&
	       pj_inet_pton(PJ_AF_INET6, nodename,
	                    &ai[0].ai_addr.ipv6.sin6_addr) == PJ_SUCCESS)
    {
	af = PJ_AF_INET6;
	has_addr = PJ_TRUE;
    }

    if (has_addr) {
	pj_str_t tmp;

	tmp.ptr = ai[0].ai_canonname;
	pj_strncpy_with_null(&tmp, nodename, PJ_MAX_HOSTNAME);
	ai[0].ai_addr.addr.sa_family = (pj_uint16_t)af;
	*count = 1;

	return PJ_SUCCESS;
    }

    /* Copy node name to null terminated string. */
    if (nodename->slen >= PJ_MAX_HOSTNAME)
	return PJ_ENAMETOOLONG;
    pj_memcpy(nodecopy, nodename->ptr, nodename->slen);
    nodecopy[nodename->slen] = '\0';

#if defined(PJ_GETADDRINFO_USE_CFHOST) && PJ_GETADDRINFO_USE_CFHOST!=0
    hostname =  CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, nodecopy,
						kCFStringEncodingASCII,
						kCFAllocatorNull);
    hostRef = CFHostCreateWithName(kCFAllocatorDefault, hostname);
    if (CFHostStartInfoResolution(hostRef, kCFHostAddresses, nil)) {
	CFArrayRef addrRef = CFHostGetAddressing(hostRef, nil);
	i = 0;
	if (addrRef != nil) {
	    CFIndex idx, naddr;
	    
	    naddr = CFArrayGetCount(addrRef);
	    for (idx = 0; idx < naddr && i < *count; idx++) {
		struct sockaddr *addr;
		
		addr = (struct sockaddr *)
		       CFDataGetBytePtr(CFArrayGetValueAtIndex(addrRef, idx));
		/* This should not happen. */
		pj_assert(addr);
		
		/* Ignore unwanted address families */
		if (af!=PJ_AF_UNSPEC && addr->sa_family != af)
		    continue;

		/* Store canonical name */
		pj_ansi_strcpy(ai[i].ai_canonname, nodecopy);
		
		/* Store address */
		PJ_ASSERT_ON_FAIL(sizeof(*addr) <= sizeof(pj_sockaddr),
				  continue);
		pj_memcpy(&ai[i].ai_addr, addr, sizeof(*addr));
		PJ_SOCKADDR_RESET_LEN(&ai[i].ai_addr);
		
		i++;
	    }
	}
	
	*count = i;
    } else {