static pj_status_t create_sip_udp_sock(int af,
				       const pjsua_transport_config *cfg,
				       pj_sock_t *p_sock,
				       pj_sockaddr *p_pub_addr)
{
    char stun_ip_addr[PJ_INET6_ADDRSTRLEN];
    unsigned port = cfg->port;
    pj_str_t stun_srv;
    pj_sock_t sock;
    pj_sockaddr bind_addr;
    pj_status_t status;

    /* Make sure STUN server resolution has completed */
    status = resolve_stun_server(PJ_TRUE, PJ_TRUE, 0);
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
	return status;
    }

    /* Initialize bound address */
    if (cfg->bound_addr.slen) {
	status = pj_sockaddr_init(af, &bind_addr, &cfg->bound_addr, 
				  (pj_uint16_t)port);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, 
			 "Unable to resolve transport bound address", 
			 status);
	    return status;
	}
    } else {
	pj_sockaddr_init(af, &bind_addr, NULL, (pj_uint16_t)port);
    }

    /* Create socket */
    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock);
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "socket() error", status);
	return status;
    }

    /* Apply QoS, if specified */
    status = pj_sock_apply_qos2(sock, cfg->qos_type, 
				&cfg->qos_params, 
				2, THIS_FILE, "SIP UDP socket");

    /* Apply sockopt, if specified */
    if (cfg->sockopt_params.cnt)
	status = pj_sock_setsockopt_params(sock, &cfg->sockopt_params);

    /* Bind socket */
    status = pj_sock_bind(sock, &bind_addr, pj_sockaddr_get_len(&bind_addr));
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "bind() error", status);
	pj_sock_close(sock);
	return status;
    }

    /* If port is zero, get the bound port */
    if (port == 0) {
	pj_sockaddr bound_addr;
	int namelen = sizeof(bound_addr);
	status = pj_sock_getsockname(sock, &bound_addr, &namelen);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "getsockname() error", status);
	    pj_sock_close(sock);
	    return status;
	}

	port = pj_sockaddr_get_port(&bound_addr);
    }

    if (pjsua_var.stun_srv.addr.sa_family != 0) {
    	pj_sockaddr_print(&pjsua_var.stun_srv,
    		     	  stun_ip_addr, sizeof(stun_ip_addr), 0);
	stun_srv = pj_str(stun_ip_addr);
    } else {
	stun_srv.slen = 0;
    }

    /* Get the published address, either by STUN or by resolving
     * the name of local host.
     */
    if (pj_sockaddr_has_addr(p_pub_addr)) {
	/*
	 * Public address is already specified, no need to resolve the 
	 * address, only set the port.
	 */
	if (pj_sockaddr_get_port(p_pub_addr) == 0)
	    pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);

    } else if (stun_srv.slen &&
               (af == pj_AF_INET() || pjsua_var.ua_cfg.stun_try_ipv6))
    {
	pjstun_setting stun_opt;

	/*
	 * STUN is specified, resolve the address with STUN.
	 * Currently, this is only to get IPv4 mapped address
	 * (does IPv6 still need a mapped address?).
	 */
	pj_bzero(&stun_opt, sizeof(stun_opt));
	stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
	stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
	stun_opt.srv1  = stun_opt.srv2  = stun_srv;
	stun_opt.port1 = stun_opt.port2 = 
			 pj_sockaddr_get_port(&pjsua_var.stun_srv);
	status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
					 1, &sock, &p_pub_addr->ipv4);
	if (status != PJ_SUCCESS) {
	    /* Failed getting mapped address via STUN */
	    pjsua_perror(THIS_FILE, "Error contacting STUN server", status);
	    
	    /* Return error if configured to not ignore STUN failure */
	    if (!pjsua_var.ua_cfg.stun_ignore_failure) {
		pj_sock_close(sock);
		return status;
	    }

	    /* Otherwise, just use host IP */
	    pj_sockaddr_init(af, p_pub_addr, NULL, (pj_uint16_t)port);
	    status = pj_gethostip(af, p_pub_addr);
	    if (status != PJ_SUCCESS) {
		pjsua_perror(THIS_FILE, "Unable to get local host IP", status);
		pj_sock_close(sock);
		return status;
	    }
	}

    } else {

	pj_bzero(p_pub_addr, sizeof(pj_sockaddr));

	if (pj_sockaddr_has_addr(&bind_addr)) {
	    pj_sockaddr_copy_addr(p_pub_addr, &bind_addr);
	} else {
	    status = pj_gethostip(af, p_pub_addr);
	    if (status != PJ_SUCCESS) {
		pjsua_perror(THIS_FILE, "Unable to get local host IP", status);
		pj_sock_close(sock);
		return status;
	    }
	}

	p_pub_addr->addr.sa_family = (pj_uint16_t)af;
	pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);

	if (stun_srv.slen && af != pj_AF_INET()) {
	    /* STUN is specified, but it is not IPv4, just print warning */
	    PJ_PERROR(2, (THIS_FILE, PJ_EAFNOTSUP,
		          "Cannot use STUN for SIP UDP socket %s:%d",
		          addr_string(p_pub_addr),
		          (int)pj_sockaddr_get_port(p_pub_addr)));
	}

    }

    *p_sock = sock;

    PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
	      addr_string(p_pub_addr),
	      (int)pj_sockaddr_get_port(p_pub_addr)));

    return PJ_SUCCESS;
}
static pj_status_t create_sip_udp_sock(int af,
				       const pjsua_transport_config *cfg,
				       pj_sock_t *p_sock,
				       pj_sockaddr *p_pub_addr)
{
    char stun_ip_addr[PJ_INET6_ADDRSTRLEN];
    unsigned port = cfg->port;
    pj_str_t stun_srv;
    pj_sock_t sock;
    pj_sockaddr bind_addr;
    pj_status_t status;

     
    status = resolve_stun_server(PJ_TRUE, PJ_TRUE, 0);
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
	return status;
    }

     
    if (cfg->bound_addr.slen) {
	status = pj_sockaddr_init(af, &bind_addr, &cfg->bound_addr, 
				  (pj_uint16_t)port);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, 
			 "Unable to resolve transport bound address", 
			 status);
	    return status;
	}
    } else {
	pj_sockaddr_init(af, &bind_addr, NULL, (pj_uint16_t)port);
    }

     
    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock);
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "socket() error", status);
	return status;
    }

     
    status = pj_sock_apply_qos2(sock, cfg->qos_type, 
				&cfg->qos_params, 
				2, THIS_FILE, "SIP UDP socket");

     
    if (cfg->sockopt_params.cnt)
	status = pj_sock_setsockopt_params(sock, &cfg->sockopt_params);

     
    status = pj_sock_bind(sock, &bind_addr, pj_sockaddr_get_len(&bind_addr));
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "bind() error", status);
	pj_sock_close(sock);
	return status;
    }

     
    if (port == 0) {
	pj_sockaddr bound_addr;
	int namelen = sizeof(bound_addr);
	status = pj_sock_getsockname(sock, &bound_addr, &namelen);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "getsockname() error", status);
	    pj_sock_close(sock);
	    return status;
	}

	port = pj_sockaddr_get_port(&bound_addr);
    }

    if (pjsua_var.stun_srv.addr.sa_family != 0) {
    	pj_sockaddr_print(&pjsua_var.stun_srv,
    		     	  stun_ip_addr, sizeof(stun_ip_addr), 0);
	stun_srv = pj_str(stun_ip_addr);
    } else {
	stun_srv.slen = 0;
    }

     
    if (pj_sockaddr_has_addr(p_pub_addr)) {
	 
	if (pj_sockaddr_get_port(p_pub_addr) == 0)
	    pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);

    } else if (stun_srv.slen &&
               (af == pj_AF_INET() || pjsua_var.ua_cfg.stun_try_ipv6))
    {
	pjstun_setting stun_opt;

	 
	pj_bzero(&stun_opt, sizeof(stun_opt));
	stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
	stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
	stun_opt.srv1  = stun_opt.srv2  = stun_srv;
	stun_opt.port1 = stun_opt.port2 = 
			 pj_sockaddr_get_port(&pjsua_var.stun_srv);
	status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
					 1, &sock, &p_pub_addr->ipv4);
	if (status != PJ_SUCCESS) {
	     
	    pjsua_perror(THIS_FILE, "Error contacting STUN server", status);
	    
	     
	    if (!pjsua_var.ua_cfg.stun_ignore_failure) {
		pj_sock_close(sock);
		return status;
	    }

	     
	    pj_sockaddr_init(af, p_pub_addr, NULL, (pj_uint16_t)port);
	    status = pj_gethostip(af, p_pub_addr);
	    if (status != PJ_SUCCESS) {
		pjsua_perror(THIS_FILE, "Unable to get local host IP", status);
		pj_sock_close(sock);
		return status;
	    }
	}

    } else {

	pj_bzero(p_pub_addr, sizeof(pj_sockaddr));

	if (pj_sockaddr_has_addr(&bind_addr)) {
	    pj_sockaddr_copy_addr(p_pub_addr, &bind_addr);
	} else {
	    status = pj_gethostip(af, p_pub_addr);
	    if (status != PJ_SUCCESS) {
		pjsua_perror(THIS_FILE, "Unable to get local host IP", status);
		pj_sock_close(sock);
		return status;
	    }
	}

	p_pub_addr->addr.sa_family = (pj_uint16_t)af;
	pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);

	if (stun_srv.slen && af != pj_AF_INET()) {
	     
	    PJ_PERROR(2, (THIS_FILE, PJ_EAFNOTSUP,
		          "Cannot use STUN for SIP UDP socket %s:%d",
		          addr_string(p_pub_addr),
		          (int)pj_sockaddr_get_port(p_pub_addr)));
	}

    }

    *p_sock = sock;

    PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
	      addr_string(p_pub_addr),
	      (int)pj_sockaddr_get_port(p_pub_addr)));

    return PJ_SUCCESS;
}