📄 transport_ice.c
字号:
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 + -