예제 #1
0
/* 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;
}
예제 #2
0
/*
 * Internal:
 *  determine if an address is a valid IP address, and if it is,
 *  return the IP version (4 or 6).
 */
static int get_ip_addr_ver(const pj_str_t *host)
{
    pj_in_addr dummy;
    pj_in6_addr dummy6;

    /* First check if this is an IPv4 address */
    if (pj_inet_pton(pj_AF_INET(), host, &dummy) == PJ_SUCCESS)
	return 4;

    /* Then check if this is an IPv6 address */
    if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS)
	return 6;

    /* Not an IP address */
    return 0;
}
예제 #3
0
/* Start socket. */
PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock,
				        const pj_str_t *domain,
				        pj_uint16_t default_port,
				        pj_dns_resolver *resolver)
{
    pj_status_t status;

    PJ_ASSERT_RETURN(stun_sock && domain && default_port, PJ_EINVAL);

    /* Check whether the domain contains IP address */
    stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)stun_sock->af;
    status = pj_inet_pton(stun_sock->af, domain, 
			  pj_sockaddr_get_addr(&stun_sock->srv_addr));
    if (status != PJ_SUCCESS) {
	stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)0;
    }

    /* If resolver is set, try to resolve with DNS SRV first. It
     * will fallback to DNS A/AAAA when no SRV record is found.
     */
    if (status != PJ_SUCCESS && resolver) {
	const pj_str_t res_name = pj_str("_stun._udp.");
	unsigned opt;

	pj_assert(stun_sock->q == NULL);

	opt = PJ_DNS_SRV_FALLBACK_A;
	if (stun_sock->af == pj_AF_INET6()) {
	    opt |= (PJ_DNS_SRV_RESOLVE_AAAA | PJ_DNS_SRV_FALLBACK_AAAA);
	}

	status = pj_dns_srv_resolve(domain, &res_name, default_port, 
				    stun_sock->pool, resolver, opt,
				    stun_sock, &dns_srv_resolver_cb, 
				    &stun_sock->q);

	/* Processing will resume when the DNS SRV callback is called */
	return status;

    } else {

	if (status != PJ_SUCCESS) {
	    pj_addrinfo ai;
	    unsigned cnt = 1;

	    status = pj_getaddrinfo(stun_sock->af, domain, &cnt, &ai);
	    if (status != PJ_SUCCESS)
		return status;

	    pj_sockaddr_cp(&stun_sock->srv_addr, &ai.ai_addr);
	}

	pj_sockaddr_set_port(&stun_sock->srv_addr, (pj_uint16_t)default_port);

	/* Start sending Binding request */
	return get_mapped_addr(stun_sock);
    }
}
예제 #4
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 */
}
예제 #5
0
/*
 * This is the main function for performing server resolution.
 */
PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
			    pj_pool_t *pool,
			    const pjsip_host_info *target,
			    void *token,
			    pjsip_resolver_callback *cb)
{
    pjsip_server_addresses svr_addr;
    pj_status_t status = PJ_SUCCESS;
    int ip_addr_ver;
    struct query *query;
    pjsip_transport_type_e type = target->type;

    /* Is it IP address or hostname? And if it's an IP, which version? */
    ip_addr_ver = get_ip_addr_ver(&target->addr.host);

    /* Set the transport type if not explicitly specified. 
     * RFC 3263 section 4.1 specify rules to set up this.
     */
    if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
	if (ip_addr_ver || (target->addr.port != 0)) {
#if PJ_HAS_TCP
	    if (target->flag & PJSIP_TRANSPORT_SECURE) 
	    {
		type = PJSIP_TRANSPORT_TLS;
	    } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) 
	    {
		type = PJSIP_TRANSPORT_TCP;
	    } else 
#endif
	    {
		type = PJSIP_TRANSPORT_UDP;
	    }
	} else {
	    /* No type or explicit port is specified, and the address is
	     * not IP address.
	     * In this case, full NAPTR resolution must be performed.
	     * But we don't support it (yet).
	     */
#if PJ_HAS_TCP
	    if (target->flag & PJSIP_TRANSPORT_SECURE) 
	    {
		type = PJSIP_TRANSPORT_TLS;
	    } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) 
	    {
		type = PJSIP_TRANSPORT_TCP;
	    } else 
#endif
	    {
		type = PJSIP_TRANSPORT_UDP;
	    }
	}

	/* Add IPv6 flag for IPv6 address */
	if (ip_addr_ver == 6)
	    type = (pjsip_transport_type_e)((int)type + PJSIP_TRANSPORT_IPV6);
    }


    /* If target is an IP address, or if resolver is not configured, 
     * we can just finish the resolution now using pj_gethostbyname()
     */
    if (ip_addr_ver || resolver->res == NULL) {
	char addr_str[PJ_INET6_ADDRSTRLEN+10];
	pj_uint16_t srv_port;

	if (ip_addr_ver != 0) {
	    /* Target is an IP address, no need to resolve */
	    if (ip_addr_ver == 4) {
		pj_sockaddr_init(pj_AF_INET(), &svr_addr.entry[0].addr, 
				 NULL, 0);
		pj_inet_aton(&target->addr.host,
			     &svr_addr.entry[0].addr.ipv4.sin_addr);
	    } else {
		pj_sockaddr_init(pj_AF_INET6(), &svr_addr.entry[0].addr, 
				 NULL, 0);
		pj_inet_pton(pj_AF_INET6(), &target->addr.host,
			     &svr_addr.entry[0].addr.ipv6.sin6_addr);
	    }
	} else {
	    pj_addrinfo ai;
	    unsigned count;
	    int af;

	    PJ_LOG(5,(THIS_FILE,
		      "DNS resolver not available, target '%.*s:%d' type=%s "
		      "will be resolved with getaddrinfo()",
		      target->addr.host.slen,
		      target->addr.host.ptr,
		      target->addr.port,
		      pjsip_transport_get_type_name(target->type)));

	    if (type & PJSIP_TRANSPORT_IPV6) {
		af = pj_AF_INET6();
	    } else {
		af = pj_AF_INET();
	    }

	    /* Resolve */
	    count = 1;
	    status = pj_getaddrinfo(af, &target->addr.host, &count, &ai);
	    if (status != PJ_SUCCESS)
		goto on_error;

	    svr_addr.entry[0].addr.addr.sa_family = (pj_uint16_t)af;
	    pj_memcpy(&svr_addr.entry[0].addr, &ai.ai_addr,
		      sizeof(pj_sockaddr));
	}

	/* Set the port number */
	if (target->addr.port == 0) {
	   srv_port = (pj_uint16_t)
		      pjsip_transport_get_default_port_for_type(type);
	} else {
	   srv_port = (pj_uint16_t)target->addr.port;
	}
	pj_sockaddr_set_port(&svr_addr.entry[0].addr, srv_port);

	/* Call the callback. */
	PJ_LOG(5,(THIS_FILE, 
		  "Target '%.*s:%d' type=%s resolved to "
		  "'%s' type=%s (%s)",
		  (int)target->addr.host.slen,
		  target->addr.host.ptr,
		  target->addr.port,
		  pjsip_transport_get_type_name(target->type),
		  pj_sockaddr_print(&svr_addr.entry[0].addr, addr_str,
				    sizeof(addr_str), 3),
		  pjsip_transport_get_type_name(type),
		  pjsip_transport_get_type_desc(type)));
	svr_addr.count = 1;
	svr_addr.entry[0].priority = 0;
	svr_addr.entry[0].weight = 0;
	svr_addr.entry[0].type = type;
	svr_addr.entry[0].addr_len = pj_sockaddr_get_len(&svr_addr.entry[0].addr);
	(*cb)(status, token, &svr_addr);

	/* Done. */
	return;
    }

    /* Target is not an IP address so we need to resolve it. */
#if PJSIP_HAS_RESOLVER

    /* Build the query state */
    query = PJ_POOL_ZALLOC_T(pool, struct query);
    query->objname = THIS_FILE;
    query->token = token;
    query->cb = cb;
    query->req.target = *target;
    pj_strdup(pool, &query->req.target.addr.host, &target->addr.host);

    /* If port is not specified, start with SRV resolution
     * (should be with NAPTR, but we'll do that later)
     */
    PJ_TODO(SUPPORT_DNS_NAPTR);

    /* Build dummy NAPTR entry */
    query->naptr_cnt = 1;
    pj_bzero(&query->naptr[0], sizeof(query->naptr[0]));
    query->naptr[0].order = 0;
    query->naptr[0].pref = 0;
    query->naptr[0].type = type;
    pj_strdup(pool, &query->naptr[0].name, &target->addr.host);


    /* Start DNS SRV or A resolution, depending on whether port is specified */
    if (target->addr.port == 0) {
	query->query_type = PJ_DNS_TYPE_SRV;

	query->req.def_port = 5060;

	if (type == PJSIP_TRANSPORT_TLS) {
	    query->naptr[0].res_type = pj_str("_sips._tcp.");
	    query->req.def_port = 5061;
	} else if (type == PJSIP_TRANSPORT_TCP)
	    query->naptr[0].res_type = pj_str("_sip._tcp.");
	else if (type == PJSIP_TRANSPORT_UDP)
	    query->naptr[0].res_type = pj_str("_sip._udp.");
	else {
	    pj_assert(!"Unknown transport type");
	    query->naptr[0].res_type = pj_str("_sip._udp.");
	    
	}

    } else {
	/* Otherwise if port is specified, start with A (or AAAA) host 
	 * resolution 
	 */
	query->query_type = PJ_DNS_TYPE_A;
	query->naptr[0].res_type.slen = 0;
	query->req.def_port = target->addr.port;
    }

    /* Start the asynchronous query */
    PJ_LOG(5, (query->objname, 
	       "Starting async DNS %s query: target=%.*s%.*s, transport=%s, "
	       "port=%d",
	       pj_dns_get_type_name(query->query_type),
	       (int)query->naptr[0].res_type.slen,
	       query->naptr[0].res_type.ptr,
	       (int)query->naptr[0].name.slen, query->naptr[0].name.ptr,
	       pjsip_transport_get_type_name(target->type),
	       target->addr.port));

    if (query->query_type == PJ_DNS_TYPE_SRV) {

    		unsigned option = PJ_TRUE;
    	        if (type & PJSIP_TRANSPORT_IPV6) {
    	            option |= PJ_DNS_SRV_FALLBACK_GETADDRINFO_IPV6;
    	        } else {
    	            option |= PJ_DNS_SRV_FALLBACK_GETADDRINFO_IPV4;
    	        }

    	        status = pj_dns_srv_resolve(&query->naptr[0].name,
    	        			    &query->naptr[0].res_type,
    	        			    query->req.def_port, pool, resolver->res,
    	        			    option, query, &srv_resolver_cb, NULL);

    } else if (query->query_type == PJ_DNS_TYPE_A) {

    	 status = pj_dns_resolver_start_query(resolver->res,
					     &query->naptr[0].name,
					     PJ_DNS_TYPE_A, 0, 
					     &dns_a_callback,
    					     query, &query->object);

    } else {
	pj_assert(!"Unexpected");
	status = PJ_EBUG;
    }

    if (status != PJ_SUCCESS)
	goto on_error;

    return;

#else /* PJSIP_HAS_RESOLVER */
    PJ_UNUSED_ARG(pool);
    PJ_UNUSED_ARG(query);
    PJ_UNUSED_ARG(srv_name);
#endif /* PJSIP_HAS_RESOLVER */

on_error:
    if (status != PJ_SUCCESS) {
	char errmsg[PJ_ERR_MSG_SIZE];
	PJ_LOG(4,(THIS_FILE, "Failed to resolve '%.*s'. Err=%d (%s)",
			     (int)target->addr.host.slen,
			     target->addr.host.ptr,
			     status,
			     pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
	(*cb)(status, token, NULL);
	return;
    }
}
예제 #6
0
파일: sock.c 프로젝트: AmoebaLabs/pjsip
static int format_test(void)
{
    pj_str_t s = pj_str(ADDRESS);
    unsigned char *p;
    pj_in_addr addr;
    char zero[64];
    pj_sockaddr_in addr2;
    const pj_str_t *hostname;
    const unsigned char A[] = {127, 0, 0, 1};

    PJ_LOG(3,("test", "...format_test()"));
    
    /* pj_inet_aton() */
    if (pj_inet_aton(&s, &addr) != 1)
	return -10;
    
    /* Check the result. */
    p = (unsigned char*)&addr;
    if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) {
	PJ_LOG(3,("test", "  error: mismatched address. p0=%d, p1=%d, "
			  "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF, 
			   p[2] & 0xFF, p[3] & 0xFF));
	return -15;
    }

    /* pj_inet_ntoa() */
    p = (unsigned char*) pj_inet_ntoa(addr);
    if (!p)
	return -20;

    if (pj_strcmp2(&s, (char*)p) != 0)
	return -22;

#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
    /* pj_inet_pton() */
    /* pj_inet_ntop() */
    {
	const pj_str_t s_ipv4 = pj_str("127.0.0.1");
	const pj_str_t s_ipv6 = pj_str("fe80::2ff:83ff:fe7c:8b42");
	char buf_ipv4[PJ_INET_ADDRSTRLEN];
	char buf_ipv6[PJ_INET6_ADDRSTRLEN];
	pj_in_addr ipv4;
	pj_in6_addr ipv6;

	if (pj_inet_pton(pj_AF_INET(), &s_ipv4, &ipv4) != PJ_SUCCESS)
	    return -24;

	p = (unsigned char*)&ipv4;
	if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) {
	    return -25;
	}

	if (pj_inet_pton(pj_AF_INET6(), &s_ipv6, &ipv6) != PJ_SUCCESS)
	    return -26;

	p = (unsigned char*)&ipv6;
	if (p[0] != 0xfe || p[1] != 0x80 || p[2] != 0 || p[3] != 0 ||
	    p[4] != 0 || p[5] != 0 || p[6] != 0 || p[7] != 0 ||
	    p[8] != 0x02 || p[9] != 0xff || p[10] != 0x83 || p[11] != 0xff ||
	    p[12]!=0xfe || p[13]!=0x7c || p[14] != 0x8b || p[15]!=0x42)
	{
	    return -27;
	}

	if (pj_inet_ntop(pj_AF_INET(), &ipv4, buf_ipv4, sizeof(buf_ipv4)) != PJ_SUCCESS)
	    return -28;
	if (pj_stricmp2(&s_ipv4, buf_ipv4) != 0)
	    return -29;

	if (pj_inet_ntop(pj_AF_INET6(), &ipv6, buf_ipv6, sizeof(buf_ipv6)) != PJ_SUCCESS)
	    return -30;
	if (pj_stricmp2(&s_ipv6, buf_ipv6) != 0)
	    return -31;
    }

#endif	/* PJ_HAS_IPV6 */

    /* Test that pj_sockaddr_in_init() initialize the whole structure, 
     * including sin_zero.
     */
    pj_sockaddr_in_init(&addr2, 0, 1000);
    pj_bzero(zero, sizeof(zero));
    if (pj_memcmp(addr2.sin_zero, zero, sizeof(addr2.sin_zero)) != 0)
	return -35;

    /* pj_gethostname() */
    hostname = pj_gethostname();
    if (!hostname || !hostname->ptr || !hostname->slen)
	return -40;

    PJ_LOG(3,("test", "....hostname is %.*s", 
	      (int)hostname->slen, hostname->ptr));

    /* pj_gethostaddr() */

    /* Various constants */
#if !defined(PJ_SYMBIAN) || PJ_SYMBIAN==0
    if (PJ_AF_INET==0xFFFF) return -5500;
    if (PJ_AF_INET6==0xFFFF) return -5501;
    
    /* 0xFFFF could be a valid SOL_SOCKET (e.g: on some Win or Mac) */
    //if (PJ_SOL_SOCKET==0xFFFF) return -5503;
    
    if (PJ_SOL_IP==0xFFFF) return -5502;
    if (PJ_SOL_TCP==0xFFFF) return -5510;
    if (PJ_SOL_UDP==0xFFFF) return -5520;
    if (PJ_SOL_IPV6==0xFFFF) return -5530;

    if (PJ_SO_TYPE==0xFFFF) return -5540;
    if (PJ_SO_RCVBUF==0xFFFF) return -5550;
    if (PJ_SO_SNDBUF==0xFFFF) return -5560;
    if (PJ_TCP_NODELAY==0xFFFF) return -5570;
    if (PJ_SO_REUSEADDR==0xFFFF) return -5580;

    if (PJ_MSG_OOB==0xFFFF) return -5590;
    if (PJ_MSG_PEEK==0xFFFF) return -5600;
#endif

    return 0;
}
예제 #7
0
/* Get IP interface for sending to the specified destination */
PJ_DEF(pj_status_t) pj_getipinterface(int af,
                                      const pj_str_t *dst,
                                      pj_sockaddr *itf_addr,
                                      pj_bool_t allow_resolve,
                                      pj_sockaddr *p_dst_addr)
{
    pj_sockaddr dst_addr;
    pj_sock_t fd;
    int len;
    pj_uint8_t zero[64];
    pj_status_t status;

    pj_sockaddr_init(af, &dst_addr, NULL, 53);
    status = pj_inet_pton(af, dst, pj_sockaddr_get_addr(&dst_addr));
    if (status != PJ_SUCCESS) {
	/* "dst" is not an IP address. */
	if (allow_resolve) {
	    status = pj_sockaddr_init(af, &dst_addr, dst, 53);
	} else {
	    pj_str_t cp;

	    if (af == PJ_AF_INET) {
		cp = pj_str("1.1.1.1");
	    } else {
		cp = pj_str("1::1");
	    }
	    status = pj_sockaddr_init(af, &dst_addr, &cp, 53);
	}

	if (status != PJ_SUCCESS)
	    return status;
    }

    /* Create UDP socket and connect() to the destination IP */
    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd);
    if (status != PJ_SUCCESS) {
	return status;
    }

    status = pj_sock_connect(fd, &dst_addr, pj_sockaddr_get_len(&dst_addr));
    if (status != PJ_SUCCESS) {
	pj_sock_close(fd);
	return status;
    }

    len = sizeof(*itf_addr);
    status = pj_sock_getsockname(fd, itf_addr, &len);
    if (status != PJ_SUCCESS) {
	pj_sock_close(fd);
	return status;
    }

    pj_sock_close(fd);

    /* Check that the address returned is not zero */
    pj_bzero(zero, sizeof(zero));
    if (pj_memcmp(pj_sockaddr_get_addr(itf_addr), zero,
		  pj_sockaddr_get_addr_len(itf_addr))==0)
    {
	return PJ_ENOTFOUND;
    }

    if (p_dst_addr)
	*p_dst_addr = dst_addr;

    return PJ_SUCCESS;
}
예제 #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];
    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 {
예제 #9
0
/*
 * pjsip_udp_transport_attach()
 *
 * Attach UDP socket and start transport.
 */
static pj_status_t transport_attach( pjsip_endpoint *endpt,
				     pjsip_transport_type_e type,
				     pj_sock_t sock,
				     const pjsip_host_port *a_name,
				     unsigned async_cnt,
				     pjsip_transport **p_transport)
{
    pj_pool_t *pool;
    struct udp_transport *tp;
    const char *format, *ipv6_quoteb = "", *ipv6_quotee = "";
    unsigned i;
    pj_status_t status;

    PJ_ASSERT_RETURN(endpt && sock!=PJ_INVALID_SOCKET && a_name && async_cnt>0,
		     PJ_EINVAL);

    /* Object name. */
    if (type & PJSIP_TRANSPORT_IPV6) {
        pj_in6_addr dummy6;

	format = "udpv6%p";
	/* We don't need to add quote if the transport type is IPv6, but
	 * actually translated to IPv4.
	 */
        if (pj_inet_pton(pj_AF_INET6(), &a_name->host, &dummy6)==PJ_SUCCESS) {
	    ipv6_quoteb = "[";
	    ipv6_quotee = "]";
	}
    } else {
	format = "udp%p";
    }

    /* Create pool. */
    pool = pjsip_endpt_create_pool(endpt, format, PJSIP_POOL_LEN_TRANSPORT, 
				   PJSIP_POOL_INC_TRANSPORT);
    if (!pool)
	return PJ_ENOMEM;

    /* Create the UDP transport object. */
    tp = PJ_POOL_ZALLOC_T(pool, struct udp_transport);

    /* Save pool. */
    tp->base.pool = pool;

    pj_memcpy(tp->base.obj_name, pool->obj_name, PJ_MAX_OBJ_NAME);

    /* Init reference counter. */
    status = pj_atomic_create(pool, 0, &tp->base.ref_cnt);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Init lock. */
    status = pj_lock_create_recursive_mutex(pool, pool->obj_name, 
					    &tp->base.lock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Set type. */
    tp->base.key.type = type;

    /* Remote address is left zero (except the family) */
    tp->base.key.rem_addr.addr.sa_family = (pj_uint16_t)
	((type & PJSIP_TRANSPORT_IPV6) ? pj_AF_INET6() : pj_AF_INET());

    /* Type name. */
    tp->base.type_name = "UDP";

    /* Transport flag */
    tp->base.flag = pjsip_transport_get_flag_from_type(type);


    /* Length of addressess. */
    tp->base.addr_len = sizeof(tp->base.local_addr);

    /* Init local address. */
    status = pj_sock_getsockname(sock, &tp->base.local_addr, 
				 &tp->base.addr_len);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Init remote name. */
    if (type == PJSIP_TRANSPORT_UDP)
	tp->base.remote_name.host = pj_str("0.0.0.0");
    else
	tp->base.remote_name.host = pj_str("::0");
    tp->base.remote_name.port = 0;

    /* Init direction */
    tp->base.dir = PJSIP_TP_DIR_NONE;

    /* Set endpoint. */
    tp->base.endpt = endpt;

    /* Transport manager and timer will be initialized by tpmgr */

    /* Attach socket and assign name. */
    udp_set_socket(tp, sock, a_name);

    /* Register to ioqueue */
    status = register_to_ioqueue(tp);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Set functions. */
    tp->base.send_msg = &udp_send_msg;
    tp->base.do_shutdown = &udp_shutdown;
    tp->base.destroy = &udp_destroy;

    /* This is a permanent transport, so we initialize the ref count
     * to one so that transport manager don't destroy this transport
     * when there's no user!
     */
    pj_atomic_inc(tp->base.ref_cnt);

    /* Register to transport manager. */
    tp->base.tpmgr = pjsip_endpt_get_tpmgr(endpt);
    status = pjsip_transport_register( tp->base.tpmgr, (pjsip_transport*)tp);
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Create rdata and put it in the array. */
    tp->rdata_cnt = 0;
    tp->rdata = (pjsip_rx_data**)
    		pj_pool_calloc(tp->base.pool, async_cnt, 
			       sizeof(pjsip_rx_data*));
    for (i=0; i<async_cnt; ++i) {
	pj_pool_t *rdata_pool = pjsip_endpt_create_pool(endpt, "rtd%p", 
							PJSIP_POOL_RDATA_LEN,
							PJSIP_POOL_RDATA_INC);
	if (!rdata_pool) {
	    pj_atomic_set(tp->base.ref_cnt, 0);
	    pjsip_transport_destroy(&tp->base);
	    return PJ_ENOMEM;
	}

	init_rdata(tp, i, rdata_pool, NULL);
	tp->rdata_cnt++;
    }

    /* Start reading the ioqueue. */
    status = start_async_read(tp);
    if (status != PJ_SUCCESS) {
	pjsip_transport_destroy(&tp->base);
	return status;
    }

    /* Done. */
    if (p_transport)
	*p_transport = &tp->base;
    
    PJ_LOG(4,(tp->base.obj_name, 
	      "SIP %s started, published address is %s%.*s%s:%d",
	      pjsip_transport_get_type_desc((pjsip_transport_type_e)tp->base.key.type),
	      ipv6_quoteb,
	      (int)tp->base.local_name.host.slen,
	      tp->base.local_name.host.ptr,
	      ipv6_quotee,
	      tp->base.local_name.port));

    return PJ_SUCCESS;

on_error:
    udp_destroy((pjsip_transport*)tp);
    return status;
}
예제 #10
0
/*
 * This is the main function for performing server resolution.
 */
PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
			    pj_pool_t *pool,
			    const pjsip_host_info *target,
			    void *token,
			    pjsip_resolver_callback *cb)
{
    pjsip_server_addresses svr_addr;
    pj_status_t status = PJ_SUCCESS;
    int ip_addr_ver;
    struct query *query;
    pjsip_transport_type_e type = target->type;
    int af = pj_AF_UNSPEC();

    /* If an external implementation has been provided use it instead */
    if (resolver->ext_res) {
        (*resolver->ext_res->resolve)(resolver, pool, target, token, cb);
        return;
    }

    /* Is it IP address or hostname? And if it's an IP, which version? */
    ip_addr_ver = get_ip_addr_ver(&target->addr.host);

    /* Initialize address family type. Unfortunately, target type doesn't
     * really tell the address family type, except when IPv6 flag is
     * explicitly set.
     */
#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6==1
    if ((ip_addr_ver == 6) || (type & PJSIP_TRANSPORT_IPV6))
	af = pj_AF_INET6();
    else if (ip_addr_ver == 4)
	af = pj_AF_INET();
#else
    /* IPv6 is disabled, will resolving IPv6 address be useful? */
    af = pj_AF_INET();
#endif

    /* Set the transport type if not explicitly specified. 
     * RFC 3263 section 4.1 specify rules to set up this.
     */
    if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
	if (ip_addr_ver || (target->addr.port != 0)) {
#if PJ_HAS_TCP
	    if (target->flag & PJSIP_TRANSPORT_SECURE) 
	    {
		type = PJSIP_TRANSPORT_TLS;
	    } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) 
	    {
		type = PJSIP_TRANSPORT_TCP;
	    } else 
#endif
	    {
		type = PJSIP_TRANSPORT_UDP;
	    }
	} else {
	    /* No type or explicit port is specified, and the address is
	     * not IP address.
	     * In this case, full NAPTR resolution must be performed.
	     * But we don't support it (yet).
	     */
#if PJ_HAS_TCP
	    if (target->flag & PJSIP_TRANSPORT_SECURE) 
	    {
		type = PJSIP_TRANSPORT_TLS;
	    } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) 
	    {
		type = PJSIP_TRANSPORT_TCP;
	    } else 
#endif
	    {
		type = PJSIP_TRANSPORT_UDP;
	    }
	}
    }


    /* If target is an IP address, or if resolver is not configured, 
     * we can just finish the resolution now using pj_gethostbyname()
     */
    if (ip_addr_ver || resolver->res == NULL) {
	char addr_str[PJ_INET6_ADDRSTRLEN+10];
	pj_uint16_t srv_port;

	if (ip_addr_ver != 0) {
	    /* Target is an IP address, no need to resolve */
	    if (ip_addr_ver == 4) {
		pj_sockaddr_init(pj_AF_INET(), &svr_addr.entry[0].addr, 
				 NULL, 0);
		pj_inet_pton(pj_AF_INET(), &target->addr.host,
			     &svr_addr.entry[0].addr.ipv4.sin_addr);
	    } else {
		pj_sockaddr_init(pj_AF_INET6(), &svr_addr.entry[0].addr, 
				 NULL, 0);
		pj_inet_pton(pj_AF_INET6(), &target->addr.host,
			     &svr_addr.entry[0].addr.ipv6.sin6_addr);
	    }
	} else {
	    pj_addrinfo ai;
	    unsigned count;

	    PJ_LOG(5,(THIS_FILE,
		      "DNS resolver not available, target '%.*s:%d' type=%s "
		      "will be resolved with getaddrinfo()",
		      target->addr.host.slen,
		      target->addr.host.ptr,
		      target->addr.port,
		      pjsip_transport_get_type_name(target->type)));

	    /* Resolve */
	    count = 1;
	    status = pj_getaddrinfo(af, &target->addr.host, &count, &ai);
	    if (status != PJ_SUCCESS) {
		/* "Normalize" error to PJ_ERESOLVE. This is a special error
		 * because it will be translated to SIP status 502 by
		 * sip_transaction.c
		 */
		status = PJ_ERESOLVE;
		goto on_error;
	    }

	    pj_sockaddr_cp(&svr_addr.entry[0].addr, &ai.ai_addr);
	    if (af == pj_AF_UNSPEC())
		af = ai.ai_addr.addr.sa_family;
	}

	/* After address resolution, update IPv6 bitflag in transport type. */
	if (af == pj_AF_INET6())
	    type |= PJSIP_TRANSPORT_IPV6;

	/* Set the port number */
	if (target->addr.port == 0) {
	   srv_port = (pj_uint16_t)
		      pjsip_transport_get_default_port_for_type(type);
	} else {
	   srv_port = (pj_uint16_t)target->addr.port;
	}
	pj_sockaddr_set_port(&svr_addr.entry[0].addr, srv_port);

	/* Call the callback. */
	PJ_LOG(5,(THIS_FILE, 
		  "Target '%.*s:%d' type=%s resolved to "
		  "'%s' type=%s (%s)",
		  (int)target->addr.host.slen,
		  target->addr.host.ptr,
		  target->addr.port,
		  pjsip_transport_get_type_name(target->type),
		  pj_sockaddr_print(&svr_addr.entry[0].addr, addr_str,
				    sizeof(addr_str), 3),
		  pjsip_transport_get_type_name(type),
		  pjsip_transport_get_type_desc(type)));
	svr_addr.count = 1;
	svr_addr.entry[0].priority = 0;
	svr_addr.entry[0].weight = 0;
	svr_addr.entry[0].type = type;
	svr_addr.entry[0].addr_len = 
				pj_sockaddr_get_len(&svr_addr.entry[0].addr);
	(*cb)(status, token, &svr_addr);

	/* Done. */
	return;
    }

    /* Target is not an IP address so we need to resolve it. */
#if PJSIP_HAS_RESOLVER

    /* Build the query state */
    query = PJ_POOL_ZALLOC_T(pool, struct query);
    query->objname = THIS_FILE;
    query->token = token;
    query->cb = cb;
    query->req.target = *target;
    pj_strdup(pool, &query->req.target.addr.host, &target->addr.host);

    /* If port is not specified, start with SRV resolution
     * (should be with NAPTR, but we'll do that later)
     */
    PJ_TODO(SUPPORT_DNS_NAPTR);

    /* Build dummy NAPTR entry */
    query->naptr_cnt = 1;
    pj_bzero(&query->naptr[0], sizeof(query->naptr[0]));
    query->naptr[0].order = 0;
    query->naptr[0].pref = 0;
    query->naptr[0].type = type;
    pj_strdup(pool, &query->naptr[0].name, &target->addr.host);


    /* Start DNS SRV or A resolution, depending on whether port is specified */
    if (target->addr.port == 0) {
	query->query_type = PJ_DNS_TYPE_SRV;

	query->req.def_port = 5060;

	if (type == PJSIP_TRANSPORT_TLS || type == PJSIP_TRANSPORT_TLS6) {
	    query->naptr[0].res_type = pj_str("_sips._tcp.");
	    query->req.def_port = 5061;
	} else if (type == PJSIP_TRANSPORT_TCP || type == PJSIP_TRANSPORT_TCP6)
	    query->naptr[0].res_type = pj_str("_sip._tcp.");
	else if (type == PJSIP_TRANSPORT_UDP || type == PJSIP_TRANSPORT_UDP6)
	    query->naptr[0].res_type = pj_str("_sip._udp.");
	else {
	    pj_assert(!"Unknown transport type");
	    query->naptr[0].res_type = pj_str("_sip._udp.");
	    
	}

    } else {
	/* Otherwise if port is specified, start with A (or AAAA) host 
	 * resolution 
	 */
	query->query_type = PJ_DNS_TYPE_A;
	query->naptr[0].res_type.slen = 0;
	query->req.def_port = target->addr.port;
    }

    /* Start the asynchronous query */
    PJ_LOG(5, (query->objname, 
	       "Starting async DNS %s query: target=%.*s%.*s, transport=%s, "
	       "port=%d",
	       pj_dns_get_type_name(query->query_type),
	       (int)query->naptr[0].res_type.slen,
	       query->naptr[0].res_type.ptr,
	       (int)query->naptr[0].name.slen, query->naptr[0].name.ptr,
	       pjsip_transport_get_type_name(target->type),
	       target->addr.port));

    if (query->query_type == PJ_DNS_TYPE_SRV) {
	int opt = 0;

	if (af == pj_AF_UNSPEC())
	    opt = PJ_DNS_SRV_FALLBACK_A | PJ_DNS_SRV_FALLBACK_AAAA |
		  PJ_DNS_SRV_RESOLVE_AAAA;
	else if (af == pj_AF_INET6())
	    opt = PJ_DNS_SRV_FALLBACK_AAAA | PJ_DNS_SRV_RESOLVE_AAAA_ONLY;
	else /* af == pj_AF_INET() */
	    opt = PJ_DNS_SRV_FALLBACK_A;

	status = pj_dns_srv_resolve(&query->naptr[0].name,
				    &query->naptr[0].res_type,
				    query->req.def_port, pool, resolver->res,
				    opt, query, &srv_resolver_cb, NULL);

    } else if (query->query_type == PJ_DNS_TYPE_A) {

	/* Resolve DNS A record if address family is not fixed to IPv6 */
	if (af != pj_AF_INET6()) {

	    /* If there will be DNS AAAA query too, let's setup a dummy one
	     * here, otherwise app callback may be called immediately (before
	     * DNS AAAA query is sent) when DNS A record is available in the
	     * cache.
	     */
	    if (af == pj_AF_UNSPEC())
		query->object6 = (pj_dns_async_query*)0x1;

	    status = pj_dns_resolver_start_query(resolver->res, 
						 &query->naptr[0].name,
						 PJ_DNS_TYPE_A, 0, 
						 &dns_a_callback,
    						 query, &query->object);
	}

	/* Resolve DNS AAAA record if address family is not fixed to IPv4 */
	if (af != pj_AF_INET() && status == PJ_SUCCESS) {
	    status = pj_dns_resolver_start_query(resolver->res, 
						 &query->naptr[0].name,
						 PJ_DNS_TYPE_AAAA, 0, 
						 &dns_aaaa_callback,
    						 query, &query->object6);
	}

    } else {
	pj_assert(!"Unexpected");
	status = PJ_EBUG;
    }

    if (status != PJ_SUCCESS)
	goto on_error;

    return;

#else /* PJSIP_HAS_RESOLVER */
    PJ_UNUSED_ARG(pool);
    PJ_UNUSED_ARG(query);
    PJ_UNUSED_ARG(srv_name);
#endif /* PJSIP_HAS_RESOLVER */

on_error:
    if (status != PJ_SUCCESS) {
	char errmsg[PJ_ERR_MSG_SIZE];
	PJ_LOG(4,(THIS_FILE, "Failed to resolve '%.*s'. Err=%d (%s)",
			     (int)target->addr.host.slen,
			     target->addr.host.ptr,
			     status,
			     pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
	(*cb)(status, token, NULL);
	return;
    }
}
예제 #11
0
파일: sock.c 프로젝트: Jopie64/pjsip
static int format_test(void)
{
    pj_str_t s = pj_str(ADDRESS);
    unsigned char *p;
    pj_in_addr addr;
    char zero[64];
    pj_sockaddr_in addr2;
    const pj_str_t *hostname;
    const unsigned char A[] = {127, 0, 0, 1};

    PJ_LOG(3,("test", "...format_test()"));

    /* pj_inet_aton() */
    if (pj_inet_aton(&s, &addr) != 1)
        return -10;

    /* Check the result. */
    p = (unsigned char*)&addr;
    if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) {
        PJ_LOG(3,("test", "  error: mismatched address. p0=%d, p1=%d, "
                  "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF,
                  p[2] & 0xFF, p[3] & 0xFF));
        return -15;
    }

    /* pj_inet_ntoa() */
    p = (unsigned char*) pj_inet_ntoa(addr);
    if (!p)
        return -20;

    if (pj_strcmp2(&s, (char*)p) != 0)
        return -22;

#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
    /* pj_inet_pton() */
    /* pj_inet_ntop() */
    {
        const pj_str_t s_ipv4 = pj_str("127.0.0.1");
        const pj_str_t s_ipv6 = pj_str("fe80::2ff:83ff:fe7c:8b42");
        char buf_ipv4[PJ_INET_ADDRSTRLEN];
        char buf_ipv6[PJ_INET6_ADDRSTRLEN];
        pj_in_addr ipv4;
        pj_in6_addr ipv6;

        if (pj_inet_pton(pj_AF_INET(), &s_ipv4, &ipv4) != PJ_SUCCESS)
            return -24;

        p = (unsigned char*)&ipv4;
        if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) {
            return -25;
        }

        if (pj_inet_pton(pj_AF_INET6(), &s_ipv6, &ipv6) != PJ_SUCCESS)
            return -26;

        p = (unsigned char*)&ipv6;
        if (p[0] != 0xfe || p[1] != 0x80 || p[2] != 0 || p[3] != 0 ||
                p[4] != 0 || p[5] != 0 || p[6] != 0 || p[7] != 0 ||
                p[8] != 0x02 || p[9] != 0xff || p[10] != 0x83 || p[11] != 0xff ||
                p[12]!=0xfe || p[13]!=0x7c || p[14] != 0x8b || p[15]!=0x42)
        {
            return -27;
        }

        if (pj_inet_ntop(pj_AF_INET(), &ipv4, buf_ipv4, sizeof(buf_ipv4)) != PJ_SUCCESS)
            return -28;
        if (pj_stricmp2(&s_ipv4, buf_ipv4) != 0)
            return -29;

        if (pj_inet_ntop(pj_AF_INET6(), &ipv6, buf_ipv6, sizeof(buf_ipv6)) != PJ_SUCCESS)
            return -30;
        if (pj_stricmp2(&s_ipv6, buf_ipv6) != 0)
            return -31;
    }

#endif	/* PJ_HAS_IPV6 */

    /* Test that pj_sockaddr_in_init() initialize the whole structure,
     * including sin_zero.
     */
    pj_sockaddr_in_init(&addr2, 0, 1000);
    pj_bzero(zero, sizeof(zero));
    if (pj_memcmp(addr2.sin_zero, zero, sizeof(addr2.sin_zero)) != 0)
        return -35;

    /* pj_gethostname() */
    hostname = pj_gethostname();
    if (!hostname || !hostname->ptr || !hostname->slen)
        return -40;

    PJ_LOG(3,("test", "....hostname is %.*s",
              (int)hostname->slen, hostname->ptr));

    /* pj_gethostaddr() */


    return 0;
}
예제 #12
0
/**
 * Set the server or domain name of the server.
 */
PJ_DEF(pj_status_t) pj_tcp_session_set_server( pj_tcp_session *sess,
        const pj_str_t *domain,
        int default_port,
        pj_dns_resolver *resolver)
{
    pj_sockaddr tmp_addr;
    pj_bool_t is_ip_addr;
    pj_status_t status;

    PJ_ASSERT_RETURN(sess && domain, PJ_EINVAL);
    PJ_ASSERT_RETURN(sess->state == PJ_TCP_STATE_NULL, PJ_EINVALIDOP);

    pj_lock_acquire(sess->lock);

    /* See if "domain" contains just IP address */
    tmp_addr.addr.sa_family = sess->af;
    status = pj_inet_pton(sess->af, domain,
                          pj_sockaddr_get_addr(&tmp_addr));
    is_ip_addr = (status == PJ_SUCCESS);

    if (!is_ip_addr && resolver) {
        /* Resolve with DNS SRV resolution, and fallback to DNS A resolution
         * if default_port is specified.
         */
        unsigned opt = 0;
        pj_str_t res_name;

        res_name = pj_str("_tcps._tcp.");

        /* Fallback to DNS A only if default port is specified */
        if (default_port>0 && default_port<65536) {
            opt = PJ_DNS_SRV_FALLBACK_A;
            sess->default_port = (pj_uint16_t)default_port;
        }

        PJ_LOG(5,(sess->obj_name, "Resolving %.*s%.*s with DNS SRV",
                  (int)res_name.slen, res_name.ptr,
                  (int)domain->slen, domain->ptr));
        pj_tcp_session_set_state(sess, PJ_TCP_STATE_RESOLVING);

        /* User may have destroyed us in the callback */
        if (sess->state != PJ_TCP_STATE_RESOLVING) {
            status = PJ_ECANCELLED;
            goto on_return;
        }

        status = pj_dns_srv_resolve(domain, &res_name, default_port,
                                    sess->pool, resolver, opt, sess,
                                    &dns_srv_resolver_cb, &sess->dns_async);
        if (status != PJ_SUCCESS) {
            pj_tcp_session_set_state(sess, PJ_TCP_STATE_NULL);
            goto on_return;
        }

    } else {
        /* Resolver is not specified, resolve with standard gethostbyname().
         * The default_port MUST be specified in this case.
         */
        pj_addrinfo *ai;
        unsigned i, cnt;

        /* Default port must be specified */
        PJ_ASSERT_RETURN(default_port>0 && default_port<65536, PJ_EINVAL);
        sess->default_port = (pj_uint16_t)default_port;

        cnt = PJ_TCP_MAX_DNS_SRV_CNT;
        ai = (pj_addrinfo*)
             pj_pool_calloc(sess->pool, cnt, sizeof(pj_addrinfo));

        PJ_LOG(5,(sess->obj_name, "Resolving %.*s with DNS A",
                  (int)domain->slen, domain->ptr));
        pj_tcp_session_set_state(sess, PJ_TCP_STATE_RESOLVING);

        /* User may have destroyed us in the callback */
        if (sess->state != PJ_TCP_STATE_RESOLVING) {
            status = PJ_ECANCELLED;
            goto on_return;
        }

        status = pj_getaddrinfo(sess->af, domain, &cnt, ai);
        if (status != PJ_SUCCESS)
            goto on_return;

        sess->srv_addr_cnt = (pj_uint16_t)cnt;
        sess->srv_addr_list = (pj_sockaddr*)
                              pj_pool_calloc(sess->pool, cnt,
                                             sizeof(pj_sockaddr));
        for (i=0; i<cnt; ++i) {
            pj_sockaddr *addr = &sess->srv_addr_list[i];
            pj_memcpy(addr, &ai[i].ai_addr, sizeof(pj_sockaddr));
            addr->addr.sa_family = sess->af;
            addr->ipv4.sin_port = pj_htons(sess->default_port);
        }

        sess->srv_addr = &sess->srv_addr_list[0];
        pj_tcp_session_set_state(sess, PJ_TCP_STATE_RESOLVED);
    }

on_return:
    pj_lock_release(sess->lock);
    return status;
}