diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-03-26 13:25:07 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-03-26 13:25:07 +0000 |
commit | 63bbc72f8536347656ac59dea7fb9576c82ac55d (patch) | |
tree | 4a8b7fbb7b357b82cdeb49c44672439843155785 /pjnath/src/pjnath | |
parent | 84b0defcf6903a8b014ab1ba38d8923282f230ed (diff) |
ICE: implement RTCP component and cancelling check in progress
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1106 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjnath/src/pjnath')
-rw-r--r-- | pjnath/src/pjnath/ice.c | 139 | ||||
-rw-r--r-- | pjnath/src/pjnath/ice_stream_transport.c | 154 | ||||
-rw-r--r-- | pjnath/src/pjnath/stun_session.c | 25 |
3 files changed, 218 insertions, 100 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: diff --git a/pjnath/src/pjnath/ice_stream_transport.c b/pjnath/src/pjnath/ice_stream_transport.c index 86dcab37..f9748d25 100644 --- a/pjnath/src/pjnath/ice_stream_transport.c +++ b/pjnath/src/pjnath/ice_stream_transport.c @@ -60,14 +60,18 @@ static void stun_on_request_complete(pj_stun_session *sess, const pj_stun_msg *response); /* Utility: print error */ +#if PJ_LOG_MAX_LEVEL >= 3 static void ice_st_perror(pj_ice_st *ice_st, const char *title, pj_status_t status) { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(status, errmsg, sizeof(errmsg)); - PJ_LOG(1,(ice_st->obj_name, "%s: %s", title, errmsg)); + PJ_LOG(3,(ice_st->obj_name, "%s: %s", title, errmsg)); } +#else +# define ice_st_perror(ice_st, title, status) +#endif /* Get the prefix for the foundation */ @@ -224,6 +228,44 @@ static pj_str_t calc_foundation(pj_pool_t *pool, return result; } +/* Add new candidate */ +static pj_status_t add_cand( pj_ice_st *ice_st, + pj_ice_st_comp *comp, + unsigned comp_id, + pj_ice_cand_type type, + pj_uint16_t local_pref, + const pj_sockaddr_in *addr, + pj_bool_t set_default) +{ + pj_ice_st_cand *cand; + + PJ_ASSERT_RETURN(ice_st && comp && addr, PJ_EINVAL); + PJ_ASSERT_RETURN(comp->cand_cnt < PJ_ICE_ST_MAX_ALIASES, PJ_ETOOMANY); + + cand = &comp->cand_list[comp->cand_cnt]; + + pj_bzero(cand, sizeof(*cand)); + cand->type = type; + cand->status = PJ_SUCCESS; + pj_memcpy(&cand->addr, addr, sizeof(pj_sockaddr_in)); + cand->cand_id = -1; + cand->local_pref = local_pref; + cand->foundation = calc_foundation(ice_st->pool, type, &addr->sin_addr); + + if (set_default) + comp->default_cand = comp->cand_cnt; + + PJ_LOG(5,(ice_st->obj_name, + "Candidate %s:%d (type=%s) added to component %d", + pj_inet_ntoa(addr->sin_addr), + (int)pj_ntohs(addr->sin_port), + pj_ice_get_cand_type_name(type), + comp_id)); + + comp->cand_cnt++; + return PJ_SUCCESS; +} + /* Create new component (i.e. socket) */ static pj_status_t create_component(pj_ice_st *ice_st, unsigned comp_id, @@ -300,7 +342,9 @@ static pj_status_t create_component(pj_ice_st *ice_st, * to a specific interface, then only add that specific interface to * cand_list. */ - if (comp->local_addr.ipv4.sin_addr.s_addr == 0) { + if (((options & PJ_ICE_ST_OPT_DONT_ADD_CAND)==0) && + comp->local_addr.ipv4.sin_addr.s_addr == 0) + { /* Socket is bound to INADDR_ANY */ unsigned i, ifs_cnt; pj_in_addr ifs[PJ_ICE_ST_MAX_ALIASES-2]; @@ -317,65 +361,63 @@ static pj_status_t create_component(pj_ice_st *ice_st, /* Set default IP interface as the base address */ status = pj_gethostip(&comp->local_addr.ipv4.sin_addr); if (status != PJ_SUCCESS) - return status; + goto on_error; /* Add candidate entry for each interface */ for (i=0; i<ifs_cnt; ++i) { - pj_ice_st_cand *cand = &comp->cand_list[i]; - - cand->type = PJ_ICE_CAND_TYPE_HOST; - cand->status = PJ_SUCCESS; - pj_memcpy(&cand->addr, &comp->local_addr, sizeof(pj_sockaddr_in)); - cand->addr.ipv4.sin_addr.s_addr = ifs[i].s_addr; - cand->cand_id = -1; - cand->local_pref = 65535; - cand->foundation = calc_foundation(ice_st->pool, - PJ_ICE_CAND_TYPE_HOST, - &cand->addr.ipv4.sin_addr); + pj_sockaddr_in cand_addr; + pj_bool_t set_default; + + /* Ignore 127.0.0.0/24 address */ + if ((pj_ntohl(ifs[i].s_addr) >> 24)==127) + continue; + + pj_memcpy(&cand_addr, &comp->local_addr, sizeof(pj_sockaddr_in)); + cand_addr.sin_addr.s_addr = ifs[i].s_addr; + /* If the IP address is equal to local address, assign it * as default candidate. */ - if (cand->addr.ipv4.sin_addr.s_addr == - comp->local_addr.ipv4.sin_addr.s_addr) - { - comp->default_cand = i; + if (ifs[i].s_addr == comp->local_addr.ipv4.sin_addr.s_addr) { + set_default = PJ_TRUE; + } else { + set_default = PJ_FALSE; } - PJ_LOG(5,(ice_st->obj_name, - "Interface %s:%d added to component %d", - pj_inet_ntoa(cand->addr.ipv4.sin_addr), - (int)pj_ntohs(cand->addr.ipv4.sin_port), comp_id)); + status = add_cand(ice_st, comp, comp_id, + PJ_ICE_CAND_TYPE_HOST, + (pj_uint16_t)(65535-i), &cand_addr, + set_default); + if (status != PJ_SUCCESS) + goto on_error; } - comp->cand_cnt = ifs_cnt; - } else { + } else if ((options & PJ_ICE_ST_OPT_DONT_ADD_CAND)==0) { /* Socket is bound to specific address. * In this case only add that address as a single entry in the * cand_list table. */ - pj_ice_st_cand *cand = &comp->cand_list[0]; - - cand->type = PJ_ICE_CAND_TYPE_HOST; - cand->status = PJ_SUCCESS; - pj_memcpy(&cand->addr, &comp->local_addr, sizeof(pj_sockaddr_in)); - cand->cand_id = -1; - cand->local_pref = 65535; - cand->foundation = calc_foundation(ice_st->pool, - PJ_ICE_CAND_TYPE_HOST, - &cand->addr.ipv4.sin_addr); - - comp->cand_cnt = 1; - comp->default_cand = 0; - - PJ_LOG(5,(ice_st->obj_name, - "Interface %s:%d added to component %d", - pj_inet_ntoa(cand->addr.ipv4.sin_addr), - (int)pj_ntohs(cand->addr.ipv4.sin_port), comp_id)); + status = add_cand(ice_st, comp, comp_id, + PJ_ICE_CAND_TYPE_HOST, + 65535, &comp->local_addr.ipv4, + PJ_TRUE); + if (status != PJ_SUCCESS) + goto on_error; + } else if (options & PJ_ICE_ST_OPT_DONT_ADD_CAND) { + /* If application doesn't want to add candidate, just fix local_addr + * in case its value is zero. + */ + if (comp->local_addr.ipv4.sin_addr.s_addr == 0) { + status = pj_gethostip(&comp->local_addr.ipv4.sin_addr); + if (status != PJ_SUCCESS) + return status; + } } + /* Done */ if (p_comp) *p_comp = comp; @@ -568,8 +610,7 @@ static pj_status_t get_stun_mapped_addr(pj_ice_st *ice_st, PJ_DEF(pj_status_t) pj_ice_st_create_comp(pj_ice_st *ice_st, unsigned comp_id, pj_uint32_t options, - const pj_sockaddr_in *addr, - unsigned *p_itf_id) + const pj_sockaddr_in *addr) { pj_ice_st_comp *comp; pj_status_t status; @@ -601,15 +642,32 @@ PJ_DEF(pj_status_t) pj_ice_st_create_comp(pj_ice_st *ice_st, } /* Store this component */ - if (p_itf_id) - *p_itf_id = ice_st->comp_cnt; - ice_st->comp[comp_id-1] = comp; return PJ_SUCCESS; } +PJ_DEF(pj_status_t) pj_ice_st_add_cand( pj_ice_st *ice_st, + unsigned comp_id, + pj_ice_cand_type type, + pj_uint16_t local_pref, + const pj_sockaddr_in *addr, + pj_bool_t set_default) +{ + pj_ice_st_comp *comp; + + + PJ_ASSERT_RETURN(ice_st && comp_id && addr, PJ_EINVAL); + PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJ_EINVAL); + PJ_ASSERT_RETURN(ice_st->comp[comp_id-1] != NULL, PJ_EINVALIDOP); + + comp = ice_st->comp[comp_id-1]; + return add_cand(ice_st, comp, comp_id, type, local_pref, addr, + set_default); +} + + PJ_DEF(pj_status_t) pj_ice_st_get_comps_status(pj_ice_st *ice_st) { unsigned i; @@ -651,6 +709,8 @@ PJ_DEF(pj_status_t) pj_ice_st_init_ice(pj_ice_st *ice_st, PJ_ASSERT_RETURN(ice_st, PJ_EINVAL); /* Must not have ICE */ PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EINVALIDOP); + /* Components must have been created */ + PJ_ASSERT_RETURN(ice_st->comp[0] != NULL, PJ_EINVALIDOP); /* Init callback */ pj_bzero(&ice_cb, sizeof(ice_cb)); diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c index 1a048f2c..9c275a11 100644 --- a/pjnath/src/pjnath/stun_session.c +++ b/pjnath/src/pjnath/stun_session.c @@ -677,6 +677,31 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, return status; } +/* + * Cancel outgoing STUN transaction. + */ +PJ_DEF(pj_status_t) pj_stun_session_cancel_req( pj_stun_session *sess, + pj_stun_tx_data *tdata, + pj_bool_t notify, + pj_status_t notify_status) +{ + PJ_ASSERT_RETURN(sess && tdata, PJ_EINVAL); + PJ_ASSERT_RETURN(!notify || notify_status!=PJ_SUCCESS, PJ_EINVAL); + PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(tdata->msg->hdr.type), PJ_EINVAL); + + pj_mutex_lock(sess->mutex); + + if (notify) { + (sess->cb.on_request_complete)(sess, notify_status, tdata, NULL); + } + + /* Just destroy tdata. This will destroy the transaction as well */ + pj_stun_msg_destroy_tdata(sess, tdata); + + pj_mutex_unlock(sess->mutex); + return PJ_SUCCESS; + +} /* Send response */ static pj_status_t send_response(pj_stun_session *sess, |