PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr2(pjsip_tpmgr *tpmgr,
						 pj_pool_t *pool,
						 pjsip_tpmgr_fla2_param *prm)
{
    char tmp_buf[PJ_INET6_ADDRSTRLEN+10];
    pj_str_t tmp_str;
    pj_status_t status = PJSIP_EUNSUPTRANSPORT;
    unsigned flag;

    /* Sanity checks */
    PJ_ASSERT_RETURN(tpmgr && pool && prm, PJ_EINVAL);

    pj_strset(&tmp_str, tmp_buf, 0);
    prm->ret_addr.slen = 0;
    prm->ret_port = 0;
    prm->ret_tp = NULL;

    flag = pjsip_transport_get_flag_from_type(prm->tp_type);

    if (prm->tp_sel && prm->tp_sel->type == PJSIP_TPSELECTOR_TRANSPORT &&
	prm->tp_sel->u.transport)
    {
	const pjsip_transport *tp = prm->tp_sel->u.transport;
	if (prm->local_if) {
	    status = get_net_interface((pjsip_transport_type_e)tp->key.type,
				       &prm->dst_host, &tmp_str);
	    if (status != PJ_SUCCESS)
		goto on_return;
	    pj_strdup(pool, &prm->ret_addr, &tmp_str);
	    prm->ret_port = pj_sockaddr_get_port(&tp->local_addr);
	    prm->ret_tp = tp;
	} else {
	    pj_strdup(pool, &prm->ret_addr, &tp->local_name.host);
	    prm->ret_port = (pj_uint16_t)tp->local_name.port;
	}
	status = PJ_SUCCESS;

    } else if (prm->tp_sel && prm->tp_sel->type == PJSIP_TPSELECTOR_LISTENER &&
	       prm->tp_sel->u.listener)
    {
	if (prm->local_if) {
	    status = get_net_interface(prm->tp_sel->u.listener->type,
	                               &prm->dst_host, &tmp_str);
	    if (status != PJ_SUCCESS)
		goto on_return;
	    pj_strdup(pool, &prm->ret_addr, &tmp_str);
	} else {
	    pj_strdup(pool, &prm->ret_addr,
		      &prm->tp_sel->u.listener->addr_name.host);
	}
	prm->ret_port = (pj_uint16_t)prm->tp_sel->u.listener->addr_name.port;
	status = PJ_SUCCESS;

    } else if ((flag & PJSIP_TRANSPORT_DATAGRAM) != 0) {
	pj_sockaddr remote;
	int addr_len;
	pjsip_transport *tp;

	pj_bzero(&remote, sizeof(remote));
	if (prm->tp_type & PJSIP_TRANSPORT_IPV6) {
	    addr_len = sizeof(pj_sockaddr_in6);
	    remote.addr.sa_family = pj_AF_INET6();
	} else {
	    addr_len = sizeof(pj_sockaddr_in);
	    remote.addr.sa_family = pj_AF_INET();
	}

	status = pjsip_tpmgr_acquire_transport(tpmgr, prm->tp_type, &remote,
					       addr_len, NULL, &tp);

	if (status == PJ_SUCCESS) {
	    if (prm->local_if) {
		status = get_net_interface((pjsip_transport_type_e)
					   tp->key.type,
					   &prm->dst_host, &tmp_str);
		if (status != PJ_SUCCESS)
		    goto on_return;
		pj_strdup(pool, &prm->ret_addr, &tmp_str);
		prm->ret_port = pj_sockaddr_get_port(&tp->local_addr);
		prm->ret_tp = tp;
	    } else {
		pj_strdup(pool, &prm->ret_addr, &tp->local_name.host);
		prm->ret_port = (pj_uint16_t)tp->local_name.port;
	    }

	    pjsip_transport_dec_ref(tp);
	}

    } else {
	/* For connection oriented transport, enum the factories */
	pjsip_tpfactory *f;

	pj_lock_acquire(tpmgr->lock);

	f = tpmgr->factory_list.next;
	while (f != &tpmgr->factory_list) {
	    if (f->type == prm->tp_type)
		break;
	    f = f->next;
	}

	if (f != &tpmgr->factory_list) {
	    if (prm->local_if) {
		status = get_net_interface(f->type, &prm->dst_host,
					   &tmp_str);
		if (status == PJ_SUCCESS) {
		    pj_strdup(pool, &prm->ret_addr, &tmp_str);
		} else {
		    /* It could fail "normally" on certain cases, e.g.
		     * when connecting to IPv6 link local address, it
		     * will wail with EINVAL.
		     * In this case, fallback to use the default interface
		     * rather than failing the call.
		     */
		    PJ_PERROR(5,(THIS_FILE, status, "Warning: unable to "
			         "determine local interface"));
		    pj_strdup(pool, &prm->ret_addr, &f->addr_name.host);
		    status = PJ_SUCCESS;
		}
	    } else {
		pj_strdup(pool, &prm->ret_addr, &f->addr_name.host);
	    }
	    prm->ret_port = (pj_uint16_t)f->addr_name.port;
	    status = PJ_SUCCESS;
	}
	pj_lock_release(tpmgr->lock);
    }

on_return:
    return status;
}
PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr2(pjsip_tpmgr *tpmgr,
						 pj_pool_t *pool,
						 pjsip_tpmgr_fla2_param *prm)
{
    char tmp_buf[PJ_INET6_ADDRSTRLEN+10];
    pj_str_t tmp_str;
    pj_status_t status = PJSIP_EUNSUPTRANSPORT;
    unsigned flag;

     
    PJ_ASSERT_RETURN(tpmgr && pool && prm, PJ_EINVAL);

    pj_strset(&tmp_str, tmp_buf, 0);
    prm->ret_addr.slen = 0;
    prm->ret_port = 0;
    prm->ret_tp = NULL;

    flag = pjsip_transport_get_flag_from_type(prm->tp_type);

    if (prm->tp_sel && prm->tp_sel->type == PJSIP_TPSELECTOR_TRANSPORT &&
	prm->tp_sel->u.transport)
    {
	const pjsip_transport *tp = prm->tp_sel->u.transport;
	if (prm->local_if) {
	    status = get_net_interface((pjsip_transport_type_e)tp->key.type,
				       &prm->dst_host, &tmp_str);
	    if (status != PJ_SUCCESS)
		goto on_return;
	    pj_strdup(pool, &prm->ret_addr, &tmp_str);
	    prm->ret_port = pj_sockaddr_get_port(&tp->local_addr);
	    prm->ret_tp = tp;
	} else {
	    pj_strdup(pool, &prm->ret_addr, &tp->local_name.host);
	    prm->ret_port = (pj_uint16_t)tp->local_name.port;
	}
	status = PJ_SUCCESS;

    } else if (prm->tp_sel && prm->tp_sel->type == PJSIP_TPSELECTOR_LISTENER &&
	       prm->tp_sel->u.listener)
    {
	if (prm->local_if) {
	    status = get_net_interface(prm->tp_sel->u.listener->type,
	                               &prm->dst_host, &tmp_str);
	    if (status != PJ_SUCCESS)
		goto on_return;
	    pj_strdup(pool, &prm->ret_addr, &tmp_str);
	} else {
	    pj_strdup(pool, &prm->ret_addr,
		      &prm->tp_sel->u.listener->addr_name.host);
	}
	prm->ret_port = (pj_uint16_t)prm->tp_sel->u.listener->addr_name.port;
	status = PJ_SUCCESS;

    } else if ((flag & PJSIP_TRANSPORT_DATAGRAM) != 0) {
	pj_sockaddr remote;
	int addr_len;
	pjsip_transport *tp;

	pj_bzero(&remote, sizeof(remote));
	if (prm->tp_type & PJSIP_TRANSPORT_IPV6) {
	    addr_len = sizeof(pj_sockaddr_in6);
	    remote.addr.sa_family = pj_AF_INET6();
	} else {
	    addr_len = sizeof(pj_sockaddr_in);
	    remote.addr.sa_family = pj_AF_INET();
	}

	status = pjsip_tpmgr_acquire_transport(tpmgr, prm->tp_type, &remote,
					       addr_len, NULL, &tp);

	if (status == PJ_SUCCESS) {
	    if (prm->local_if) {
		status = get_net_interface((pjsip_transport_type_e)
					   tp->key.type,
					   &prm->dst_host, &tmp_str);
		if (status != PJ_SUCCESS)
		    goto on_return;
		pj_strdup(pool, &prm->ret_addr, &tmp_str);
		prm->ret_port = pj_sockaddr_get_port(&tp->local_addr);
		prm->ret_tp = tp;
	    } else {
		pj_strdup(pool, &prm->ret_addr, &tp->local_name.host);
		prm->ret_port = (pj_uint16_t)tp->local_name.port;
	    }

	    pjsip_transport_dec_ref(tp);
	}

    } else {
	 
	pjsip_tpfactory *f;

	pj_lock_acquire(tpmgr->lock);

	f = tpmgr->factory_list.next;
	while (f != &tpmgr->factory_list) {
	    if (f->type == prm->tp_type)
		break;
	    f = f->next;
	}

	if (f != &tpmgr->factory_list) {
	    if (prm->local_if) {
		status = get_net_interface(f->type, &prm->dst_host,
					   &tmp_str);
		if (status == PJ_SUCCESS) {
		    pj_strdup(pool, &prm->ret_addr, &tmp_str);
		} else {
		     
		    PJ_PERROR(5,(THIS_FILE, status, "Warning: unable to "
			         "determine local interface"));
		    pj_strdup(pool, &prm->ret_addr, &f->addr_name.host);
		    status = PJ_SUCCESS;
		}
	    } else {
		pj_strdup(pool, &prm->ret_addr, &f->addr_name.host);
	    }
	    prm->ret_port = (pj_uint16_t)f->addr_name.port;
	    status = PJ_SUCCESS;
	}
	pj_lock_release(tpmgr->lock);
    }

on_return:
    return status;
}