⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 transport_ice.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
    host = strtok(NULL, " ");
    if (!host)
	goto on_return;
    if (pj_sockaddr_in_init(&cand->addr.ipv4, pj_cstr(&s, host), 0))
	goto on_return;

    /* Port */
    token = strtok(NULL, " ");
    if (!token)
	goto on_return;
    cand->addr.ipv4.sin_port = pj_htons((pj_uint16_t)atoi(token));

    /* typ */
    token = strtok(NULL, " ");
    if (!token)
	goto on_return;
    if (strcmp(token, "typ") != 0)
	goto on_return;

    /* candidate type */
    token = strtok(NULL, " ");
    if (!token)
	goto on_return;

    if (strcmp(token, "host") == 0) {
	cand->type = PJ_ICE_CAND_TYPE_HOST;

    } else if (strcmp(token, "srflx") == 0) {
	cand->type = PJ_ICE_CAND_TYPE_SRFLX;

    } else if (strcmp(token, "relay") == 0) {
	cand->type = PJ_ICE_CAND_TYPE_RELAYED;

    } else if (strcmp(token, "prflx") == 0) {
	cand->type = PJ_ICE_CAND_TYPE_PRFLX;

    } else {
	goto on_return;
    }


    status = PJ_SUCCESS;

on_return:
    return status;
}


/* Disable ICE when SDP from remote doesn't contain a=candidate line */
static void set_no_ice(struct transport_ice *tp_ice, const char *reason)
{
    PJ_LOG(4,(tp_ice->ice_st->obj_name, 
	      "Disabling local ICE, reason=%s", reason));
    pjmedia_ice_stop_ice(&tp_ice->base);
}


/*
 * Start ICE checks when both offer and answer are available.
 */
PJ_DEF(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp,
					  pj_pool_t *pool,
					  const pjmedia_sdp_session *rem_sdp,
					  unsigned media_index)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    const pjmedia_sdp_attr *attr;
    unsigned i, cand_cnt;
    pj_ice_sess_cand cand[PJ_ICE_MAX_CAND];
    const pjmedia_sdp_media *sdp_med;
    pj_bool_t remote_is_lite = PJ_FALSE;
    pj_bool_t ice_mismatch = PJ_FALSE;
    pjmedia_sdp_conn *conn = NULL;
    pj_sockaddr conn_addr;
    pj_bool_t conn_found_in_candidate = PJ_FALSE;
    const pj_str_t STR_CANDIDATE = {"candidate", 9};
    const pj_str_t STR_ICE_LITE = {"ice-lite", 8};
    const pj_str_t STR_ICE_MISMATCH = {"ice-mismatch", 12};
    pj_str_t uname, pass;
    pj_status_t status;

    PJ_ASSERT_RETURN(tp && pool && rem_sdp, PJ_EINVAL);
    PJ_ASSERT_RETURN(media_index < rem_sdp->media_count, PJ_EINVAL);

    sdp_med = rem_sdp->media[media_index];

    /* Get the SDP connection for the media stream.
     * We'll verify later if the SDP connection address is specified 
     * as one of the candidate.
     */
    conn = sdp_med->conn;
    if (conn == NULL)
	conn = rem_sdp->conn;

    if (conn == NULL) {
	/* Unable to find SDP connection */
	return PJMEDIA_SDP_EMISSINGCONN;
    }

    pj_sockaddr_in_init(&conn_addr.ipv4, &conn->addr, 
			(pj_uint16_t)sdp_med->desc.port);

    /* Find ice-ufrag attribute in media descriptor */
    attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr,
				  "ice-ufrag", NULL);
    if (attr == NULL) {
	/* Find ice-ufrag attribute in session descriptor */
	attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr,
				      "ice-ufrag", NULL);
	if (attr == NULL) {
	    set_no_ice(tp_ice, "ice-ufrag attribute not found");
	    return PJ_SUCCESS;
	}
    }
    uname = attr->value;

    /* Find ice-pwd attribute in media descriptor */
    attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr,
				  "ice-pwd", NULL);
    if (attr == NULL) {
	/* Find ice-pwd attribute in session descriptor */
	attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr,
				      "ice-pwd", NULL);
	if (attr == NULL) {
	    set_no_ice(tp_ice, "ice-pwd attribute not found");
	    return PJ_SUCCESS;
	}
    }
    pass = attr->value;

    /* Get all candidates in the media */
    cand_cnt = 0;
    for (i=0; i<sdp_med->attr_count; ++i) {
	pjmedia_sdp_attr *attr;

	attr = sdp_med->attr[i];

	/* Detect if remote is ICE lite */
	if (pj_strcmp(&attr->name, &STR_ICE_LITE)==0) {
	    remote_is_lite = PJ_TRUE;
	    continue;
	}

	/* Detect if remote has reported ICE mismatch */
	if (pj_strcmp(&attr->name, &STR_ICE_MISMATCH)==0) {
	    ice_mismatch = PJ_TRUE;
	    continue;
	}

	if (pj_strcmp(&attr->name, &STR_CANDIDATE)!=0)
	    continue;

	/* Parse candidate */
	status = parse_cand(pool, &attr->value, &cand[cand_cnt]);
	if (status != PJ_SUCCESS)
	    return status;

	/* Check if this candidate is equal to the connection line */
	if (!conn_found_in_candidate &&
	    pj_memcmp(&conn_addr.ipv4, &cand[cand_cnt].addr.ipv4,
		      sizeof(pj_sockaddr_in))==0)
	{
	    conn_found_in_candidate = PJ_TRUE;
	}

	cand_cnt++;
    }

    /* Handle ice-mismatch case */
    if (ice_mismatch) {
	set_no_ice(tp_ice, "remote reported ice-mismatch");
	return PJ_SUCCESS;
    }

    /* Handle case where SDP connection address is not specified as
     * one of the candidate.
     */
    if (!conn_found_in_candidate) {
	set_no_ice(tp_ice, "local reported ice-mismatch");
	return PJ_SUCCESS;
    }

    /* Mark start time */
    pj_gettimeofday(&tp_ice->start_ice);

    /* If our role was controlled but it turns out that remote is 
     * a lite implementation, change our role to controlling.
     */
    if (remote_is_lite && 
	tp_ice->ice_st->ice->role == PJ_ICE_SESS_ROLE_CONTROLLED)
    {
	pj_ice_sess_change_role(tp_ice->ice_st->ice, 
				PJ_ICE_SESS_ROLE_CONTROLLING);
    }

    /* Start ICE */
    return pj_ice_strans_start_ice(tp_ice->ice_st, &uname, &pass, cand_cnt, cand);
}


PJ_DEF(pj_status_t) pjmedia_ice_stop_ice(pjmedia_transport *tp)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    return pj_ice_strans_stop_ice(tp_ice->ice_st);
}


static pj_status_t tp_get_info(pjmedia_transport *tp,
			       pjmedia_sock_info *info)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    pj_ice_strans *ice_st = tp_ice->ice_st;
    pj_ice_strans_comp *comp;

    pj_bzero(info, sizeof(*info));
    info->rtp_sock = info->rtcp_sock = PJ_INVALID_SOCKET;

    /* Retrieve address of default candidate for component 1 (RTP) */
    comp = ice_st->comp[0];
    pj_assert(comp->default_cand >= 0);
    info->rtp_sock = comp->sock;
    pj_memcpy(&info->rtp_addr_name, 
	      &comp->cand_list[comp->default_cand].addr,
	      sizeof(pj_sockaddr_in));

    /* Retrieve address of default candidate for component 12(RTCP) */
    if (ice_st->comp_cnt > 1) {
	comp = ice_st->comp[1];
	pj_assert(comp->default_cand >= 0);
	info->rtp_sock = comp->sock;
	pj_memcpy(&info->rtcp_addr_name, 
		  &comp->cand_list[comp->default_cand].addr,
		  sizeof(pj_sockaddr_in));
    }


    return PJ_SUCCESS;
}


static pj_status_t tp_attach( pjmedia_transport *tp,
			      void *stream,
			      const pj_sockaddr_t *rem_addr,
			      const pj_sockaddr_t *rem_rtcp,
			      unsigned addr_len,
			      void (*rtp_cb)(void*,
					     const void*,
					     pj_ssize_t),
			      void (*rtcp_cb)(void*,
					      const void*,
					      pj_ssize_t))
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;

    tp_ice->stream = stream;
    tp_ice->rtp_cb = rtp_cb;
    tp_ice->rtcp_cb = rtcp_cb;

    pj_memcpy(&tp_ice->remote_rtp, rem_addr, addr_len);
    pj_memcpy(&tp_ice->remote_rtcp, rem_rtcp, addr_len);

    return PJ_SUCCESS;
}


static void tp_detach(pjmedia_transport *tp,
		      void *strm)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;

    tp_ice->rtp_cb = NULL;
    tp_ice->rtcp_cb = NULL;
    tp_ice->stream = NULL;

    PJ_UNUSED_ARG(strm);
}


static pj_status_t tp_send_rtp(pjmedia_transport *tp,
			       const void *pkt,
			       pj_size_t size)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    return pj_ice_strans_sendto(tp_ice->ice_st, 1, 
			        pkt, size, &tp_ice->remote_rtp,
				sizeof(pj_sockaddr_in));
}


static pj_status_t tp_send_rtcp(pjmedia_transport *tp,
			        const void *pkt,
			        pj_size_t size)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    if (tp_ice->ice_st->comp_cnt > 1) {
	return pj_ice_strans_sendto(tp_ice->ice_st, 2, 
				    pkt, size, &tp_ice->remote_rtcp,
				    sizeof(pj_sockaddr_in));
    } else {
	return PJ_SUCCESS;
    }
}


static void ice_on_rx_data(pj_ice_strans *ice_st, unsigned comp_id, 
			   void *pkt, pj_size_t size,
			   const pj_sockaddr_t *src_addr,
			   unsigned src_addr_len)
{
    struct transport_ice *tp_ice = (struct transport_ice*) ice_st->user_data;

    if (comp_id==1 && tp_ice->rtp_cb)
	(*tp_ice->rtp_cb)(tp_ice->stream, pkt, size);
    else if (comp_id==2 && tp_ice->rtcp_cb)
	(*tp_ice->rtcp_cb)(tp_ice->stream, pkt, size);

    PJ_UNUSED_ARG(src_addr);
    PJ_UNUSED_ARG(src_addr_len);

    PJ_TODO(SWITCH_SOURCE_ADDRESS);
}


static void ice_on_ice_complete(pj_ice_strans *ice_st, 
			        pj_status_t status)
{
    struct transport_ice *tp_ice = (struct transport_ice*) ice_st->user_data;
    pj_time_val end_ice;
    pj_ice_sess_cand *lcand, *rcand;
    pj_ice_sess_check *check;
    char src_addr[32];
    char dst_addr[32];

    pj_gettimeofday(&end_ice);
    PJ_TIME_VAL_SUB(end_ice, tp_ice->start_ice);

    if (status != PJ_SUCCESS) {
	char errmsg[PJ_ERR_MSG_SIZE];
	pj_strerror(status, errmsg, sizeof(errmsg));
	PJ_LOG(1,(ice_st->obj_name, 
		  "ICE negotiation failed after %d:%03ds: %s", 
		  (int)end_ice.sec, (int)end_ice.msec,
		  errmsg));
	return;
    }

    check = &ice_st->ice->valid_list.checks[0];
    
    lcand = check->lcand;
    rcand = check->rcand;

    pj_ansi_strcpy(src_addr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
    pj_ansi_strcpy(dst_addr, pj_inet_ntoa(rcand->addr.ipv4.sin_addr));

    PJ_LOG(3,(ice_st->obj_name, 
	      "ICE negotiation completed in %d.%03ds. Sending from "
	      "%s:%d to %s:%d",
	      (int)end_ice.sec, (int)end_ice.msec,
	      src_addr, pj_ntohs(lcand->addr.ipv4.sin_port),
	      dst_addr, pj_ntohs(rcand->addr.ipv4.sin_port)));
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -