diff options
Diffstat (limited to 'pjnath/src/pjnath/ice.c')
-rw-r--r-- | pjnath/src/pjnath/ice.c | 139 |
1 files changed, 86 insertions, 53 deletions
diff --git a/pjnath/src/pjnath/ice.c b/pjnath/src/pjnath/ice.c index bfae8dae..3dc92646 100644 --- a/pjnath/src/pjnath/ice.c +++ b/pjnath/src/pjnath/ice.c @@ -56,11 +56,11 @@ static const char *clist_state_name[] = "Completed" }; -#define CHECK_NAME_LEN 128 -#define LOG4(expr) PJ_LOG(4,expr) -#define LOG5(expr) PJ_LOG(4,expr) -#define GET_LCAND_ID(cand) (cand - ice->lcand) -#define GET_CHECK_ID(chk) (chk - ice->clist.checks) +#define CHECK_NAME_LEN 128 +#define LOG4(expr) PJ_LOG(4,expr) +#define LOG5(expr) PJ_LOG(4,expr) +#define GET_LCAND_ID(cand) (cand - ice->lcand) +#define GET_CHECK_ID(cl, chk) (chk - (cl)->checks) typedef struct stun_data @@ -130,6 +130,12 @@ static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg, const pj_str_t *nonce); +PJ_DEF(const char*) pj_ice_get_cand_type_name(pj_ice_cand_type type) +{ + return cand_type_names[type]; +} + + /* * Create ICE stream session. */ @@ -176,8 +182,7 @@ PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg, for (i=0; i<comp_cnt; ++i) { pj_ice_comp *comp; comp = &ice->comp[i]; - comp->comp_id = i+1; - comp->nominated_check_id = -1; + comp->valid_check = NULL; } if (local_ufrag == NULL) { @@ -411,6 +416,7 @@ PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice, PJ_ASSERT_RETURN(ice && comp_id && local_pref && foundation && addr && base_addr && addr_len, PJ_EINVAL); + PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL); pj_mutex_lock(ice->mutex); @@ -498,6 +504,7 @@ PJ_DEF(pj_status_t) pj_ice_find_default_cand(pj_ice *ice, unsigned i; PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL); + PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL); *cand_id = -1; @@ -585,7 +592,7 @@ static pj_uint64_t CALC_CHECK_PRIO(const pj_ice *ice, } static const char *dump_check(char *buffer, unsigned bufsize, - const pj_ice *ice, + const pj_ice_checklist *clist, const pj_ice_check *check) { const pj_ice_cand *lcand = check->lcand; @@ -597,8 +604,9 @@ static const char *dump_check(char *buffer, unsigned bufsize, if (lcand->addr.addr.sa_family == PJ_AF_INET) { len = pj_ansi_snprintf(buffer, bufsize, - "%d: %s:%d-->%s:%d", - GET_CHECK_ID(check), + "%d: [%d] %s:%d-->%s:%d", + GET_CHECK_ID(clist, check), + check->lcand->comp_id, laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port), pj_inet_ntoa(rcand->addr.ipv4.sin_addr), (int)pj_ntohs(rcand->addr.ipv4.sin_port)); @@ -627,7 +635,7 @@ static void dump_checklist(const char *title, const pj_ice *ice, for (i=0; i<clist->count; ++i) { const pj_ice_check *c = &clist->checks[i]; LOG4((ice->obj_name, " %s (%s, state=%s)", - dump_check(buffer, sizeof(buffer), ice, c), + dump_check(buffer, sizeof(buffer), clist, c), (c->nominated ? "nominated" : "not nominated"), check_state_name[c->state])); } @@ -646,7 +654,7 @@ static void check_set_state(pj_ice *ice, pj_ice_check *check, pj_assert(check->state < PJ_ICE_CHECK_STATE_SUCCEEDED); LOG5((ice->obj_name, "Check %s: state changed from %s to %s", - dump_check(buf, sizeof(buf), ice, check), + dump_check(buf, sizeof(buf), &ice->clist, check), check_state_name[check->state], check_state_name[st])); check->state = st; @@ -759,7 +767,8 @@ static void prune_checklist(pj_ice *ice, pj_ice_checklist *clist) char buf[CHECK_NAME_LEN]; LOG5((ice->obj_name, "Check %s pruned", - dump_check(buf, sizeof(buf), ice, &clist->checks[j]))); + dump_check(buf, sizeof(buf), &ice->clist, + &clist->checks[j]))); pj_array_erase(clist->checks, sizeof(clist->checks[0]), clist->count, j); @@ -812,33 +821,46 @@ static pj_bool_t on_check_complete(pj_ice *ice, */ if (check->err_code==PJ_SUCCESS && check->nominated) { pj_ice_comp *comp; + char buf[CHECK_NAME_LEN]; LOG5((ice->obj_name, "Check %d is successful and nominated", - GET_CHECK_ID(check))); + GET_CHECK_ID(&ice->clist, check))); for (i=0; i<ice->clist.count; ++i) { pj_ice_check *c = &ice->clist.checks[i]; - if (c->lcand->comp_id == check->lcand->comp_id && - (c->state==PJ_ICE_CHECK_STATE_FROZEN || - c->state==PJ_ICE_CHECK_STATE_WAITING)) - { - LOG5((ice->obj_name, - "Check %d to be failed because state is %s", - i, check_state_name[c->state])); - check_set_state(ice, c, PJ_ICE_CHECK_STATE_FAILED, - PJ_ECANCELLED); + if (c->lcand->comp_id == check->lcand->comp_id) { + if (c->state < PJ_ICE_CHECK_STATE_IN_PROGRESS) { + /* Just fail Frozen/Waiting check */ + LOG5((ice->obj_name, + "Check %s to be failed because state is %s", + dump_check(buf, sizeof(buf), &ice->clist, c), + check_state_name[c->state])); + check_set_state(ice, c, PJ_ICE_CHECK_STATE_FAILED, + PJ_ECANCELLED); + + } else if (c->state == PJ_ICE_CHECK_STATE_IN_PROGRESS) { + /* State is IN_PROGRESS, cancel transaction */ + if (c->tdata) { + LOG5((ice->obj_name, + "Cancelling check %s (In Progress)", + dump_check(buf, sizeof(buf), &ice->clist, c))); + pj_stun_session_cancel_req(c->lcand->stun_sess, + c->tdata, PJ_FALSE, 0); + c->tdata = NULL; + check_set_state(ice, c, PJ_ICE_CHECK_STATE_FAILED, + PJ_ECANCELLED); + } + } } } /* Update the nominated check for the component */ comp = find_comp(ice, check->lcand->comp_id); - if (comp->nominated_check_id < 0) { - comp->nominated_check_id = GET_CHECK_ID(check); + if (comp->valid_check == NULL) { + comp->valid_check = check; } else { - pj_ice_check *nom_check; - nom_check = &ice->clist.checks[comp->nominated_check_id]; - if (nom_check->prio < check->prio) - comp->nominated_check_id = GET_CHECK_ID(check); + if (comp->valid_check->prio < check->prio) + comp->valid_check = check; } } @@ -877,7 +899,7 @@ static pj_bool_t on_check_complete(pj_ice *ice, * ICE processing as success, otherwise wait. */ for (i=0; i<ice->comp_cnt; ++i) { - if (ice->comp[i].nominated_check_id == -1) + if (ice->comp[i].valid_check == NULL) break; } if (i == ice->comp_cnt) { @@ -949,9 +971,17 @@ PJ_DEF(pj_status_t) pj_ice_create_check_list(pj_ice *ice, /* Save remote candidates */ ice->rcand_cnt = 0; for (i=0; i<rcand_cnt; ++i) { - pj_ice_cand *cn = &ice->rcand[ice->rcand_cnt++]; + pj_ice_cand *cn = &ice->rcand[ice->rcand_cnt]; + + /* Ignore candidate which has no matching component ID */ + pj_assert(rcand[i].comp_id > 0); + if (rcand[i].comp_id==0 || rcand[i].comp_id > ice->comp_cnt) { + continue; + } + pj_memcpy(cn, &rcand[i], sizeof(pj_ice_cand)); pj_strdup(ice->pool, &cn->foundation, &rcand[i].foundation); + ice->rcand_cnt++; } /* Generate checklist */ @@ -966,9 +996,7 @@ PJ_DEF(pj_status_t) pj_ice_create_check_list(pj_ice *ice, if (clist->count > PJ_ICE_MAX_CHECKS) { pj_mutex_unlock(ice->mutex); return PJ_ETOOMANY; - } else { - clist->count++; - } + } /* A local candidate is paired with a remote candidate if * and only if the two candidates have the same component ID @@ -986,6 +1014,8 @@ PJ_DEF(pj_status_t) pj_ice_create_check_list(pj_ice *ice, chk->state = PJ_ICE_CHECK_STATE_FROZEN; chk->prio = CALC_CHECK_PRIO(ice, lcand, rcand); + + clist->count++; } } @@ -1026,7 +1056,6 @@ struct req_data static pj_status_t perform_check(pj_ice *ice, pj_ice_checklist *clist, unsigned check_id) { - pj_stun_tx_data *tdata; pj_ice_comp *comp; struct req_data *rd; pj_ice_check *check; @@ -1043,32 +1072,33 @@ static pj_status_t perform_check(pj_ice *ice, pj_ice_checklist *clist, LOG5((ice->obj_name, "Sending connectivity check for check %s", - dump_check(buffer, sizeof(buffer), ice, check))); + dump_check(buffer, sizeof(buffer), clist, check))); /* Create request */ status = pj_stun_session_create_req(lcand->stun_sess, - PJ_STUN_BINDING_REQUEST, &tdata); + PJ_STUN_BINDING_REQUEST, + &check->tdata); if (status != PJ_SUCCESS) return status; /* Attach data to be retrieved later when STUN request transaction * completes and on_stun_request_complete() callback is called. */ - rd = PJ_POOL_ZALLOC_T(tdata->pool, struct req_data); + rd = PJ_POOL_ZALLOC_T(check->tdata->pool, struct req_data); rd->ice = ice; rd->clist = clist; rd->ckid = check_id; - tdata->user_data = (void*) rd; + check->tdata->user_data = (void*) rd; /* Add PRIORITY */ prio = CALC_CAND_PRIO(PJ_ICE_CAND_TYPE_PRFLX, 65535, lcand->comp_id); - pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_PRIORITY, - prio); + pj_stun_msg_add_uint_attr(check->tdata->pool, check->tdata->msg, + PJ_STUN_ATTR_PRIORITY, prio); /* Add USE-CANDIDATE and set this check to nominated */ if (ice->role == PJ_ICE_ROLE_CONTROLLING) { - pj_stun_msg_add_empty_attr(tdata->pool, tdata->msg, + pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg, PJ_STUN_ATTR_USE_CANDIDATE); check->nominated = PJ_TRUE; } @@ -1080,9 +1110,11 @@ static pj_status_t perform_check(pj_ice *ice, pj_ice_checklist *clist, /* Initiate STUN transaction to send the request */ status = pj_stun_session_send_msg(lcand->stun_sess, PJ_FALSE, &rcand->addr, - sizeof(pj_sockaddr_in), tdata); - if (status != PJ_SUCCESS) + sizeof(pj_sockaddr_in), check->tdata); + if (status != PJ_SUCCESS) { + check->tdata = NULL; return status; + } check_set_state(ice, check, PJ_ICE_CHECK_STATE_IN_PROGRESS, PJ_SUCCESS); return PJ_SUCCESS; @@ -1249,6 +1281,10 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, check = &rd->clist->checks[rd->ckid]; clist = rd->clist; + /* Mark STUN transaction as complete */ + pj_assert(tdata == check->tdata); + check->tdata = NULL; + pj_mutex_lock(ice->mutex); /* Init lcand to NULL. lcand will be found from the mapped address @@ -1258,7 +1294,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, LOG4((ice->obj_name, "Check %s%s: connectivity check %s", - dump_check(buffer, sizeof(buffer), ice, check), + dump_check(buffer, sizeof(buffer), &ice->clist, check), (check->nominated ? " (nominated)" : " (not nominated)"), (status==PJ_SUCCESS ? "SUCCESS" : "FAILED"))); @@ -1500,7 +1536,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, */ if (i == ice->rcand_cnt) { rcand = &ice->rcand[ice->rcand_cnt++]; - rcand->comp_id = comp->comp_id; + rcand->comp_id = lcand->comp_id; rcand->type = PJ_ICE_CAND_TYPE_PRFLX; rcand->prio = ap->value; pj_memcpy(&rcand->addr, src_addr, src_addr_len); @@ -1648,9 +1684,8 @@ PJ_DEF(pj_status_t) pj_ice_send_data( pj_ice *ice, pj_status_t status = PJ_SUCCESS; pj_ice_comp *comp; unsigned cand_id; - pj_ice_check *check; - PJ_ASSERT_RETURN(ice, PJ_EINVAL); + PJ_ASSERT_RETURN(ice && comp_id && comp_id <= ice->comp_cnt, PJ_EINVAL); pj_mutex_lock(ice->mutex); @@ -1660,16 +1695,14 @@ PJ_DEF(pj_status_t) pj_ice_send_data( pj_ice *ice, goto on_return; } - if (comp->nominated_check_id == -1) { + if (comp->valid_check == NULL) { status = PJNATH_EICEINPROGRESS; goto on_return; } - check = &ice->clist.checks[comp->nominated_check_id]; - cand_id = GET_LCAND_ID(check->lcand); - + cand_id = GET_LCAND_ID(comp->valid_check->lcand); status = (*ice->cb.on_tx_pkt)(ice, comp_id, cand_id, data, data_len, - &check->rcand->addr, + &comp->valid_check->rcand->addr, sizeof(pj_sockaddr_in)); on_return: |