From 7c7dd8a6151a607ac7fda3da0a657fddd07be8d1 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Wed, 19 Feb 2014 04:11:43 +0000 Subject: Fixed #1738: Infinite loop when re-INVITE is received while adding new media git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4750 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/include/pjsua-lib/pjsua_internal.h | 6 ++++++ pjsip/src/pjsua-lib/pjsua_call.c | 24 +++++++++++++++++++++++- pjsip/src/pjsua-lib/pjsua_media.c | 14 ++++++++++++++ pjsip/src/pjsua-lib/pjsua_vid.c | 10 ++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) (limited to 'pjsip') diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index dcf50209..ff414ea8 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -635,6 +635,12 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, const pjmedia_sdp_session *remote_sdp); pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id); +/* + * Error message when media operation is requested while another is in progress + */ +#define ERR_MEDIA_CHANGING " because another media operation is in progress" + +pj_bool_t pjsua_call_media_is_changing(pjsua_call *call); pj_status_t pjsua_call_media_init(pjsua_call_media *call_med, pjmedia_type type, const pjsua_transport_config *tcfg, diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index 733bc599..db8bfa11 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -34,7 +34,6 @@ */ #define LOCK_CODEC_MAX_RETRY 5 - /* * The INFO method. */ @@ -2392,6 +2391,12 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite2(pjsua_call_id call_id, if (status != PJ_SUCCESS) goto on_return; + if (pjsua_call_media_is_changing(call)) { + PJ_LOG(1,(THIS_FILE, "Unable to reinvite" ERR_MEDIA_CHANGING)); + status = PJ_EINVALIDOP; + goto on_return; + } + if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed")); status = PJSIP_ESESSIONSTATE; @@ -2499,6 +2504,12 @@ PJ_DEF(pj_status_t) pjsua_call_update2(pjsua_call_id call_id, if (status != PJ_SUCCESS) goto on_return; + if (pjsua_call_media_is_changing(call)) { + PJ_LOG(1,(THIS_FILE, "Unable to send UPDATE" ERR_MEDIA_CHANGING)); + status = PJ_EINVALIDOP; + goto on_return; + } + status = apply_call_setting(call, opt, NULL); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Failed to apply call setting", status); @@ -3878,8 +3889,14 @@ static void pjsua_call_on_rx_offer(pjsip_inv_session *inv, /* Supply candidate answer */ PJ_LOG(4,(THIS_FILE, "Call %d: received updated media offer", call->index)); + pj_log_push_indent(); + if (pjsua_call_media_is_changing(call)) { + PJ_LOG(1,(THIS_FILE, "Unable to process offer" ERR_MEDIA_CHANGING)); + goto on_return; + } + if (pjsua_var.ua_cfg.cb.on_call_rx_offer) { pjsip_status_code code = PJSIP_SC_OK; pjsua_call_setting opt = call->opt; @@ -3969,6 +3986,11 @@ static void pjsua_call_on_create_offer(pjsip_inv_session *inv, pj_log_push_indent(); call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id]; + if (pjsua_call_media_is_changing(call)) { + *offer = NULL; + PJ_LOG(1,(THIS_FILE, "Unable to create offer" ERR_MEDIA_CHANGING)); + goto on_return; + } /* See if we've put call on hold. */ if (call->local_hold) { diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index ab4c4bde..4beb821c 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -1304,6 +1304,20 @@ on_return: return status; } +/* Determine if call's media is being changed, for example when video is being + * added. Then we can reject incoming re-INVITE, for example. This is the + * solution for https://trac.pjsip.org/repos/ticket/1738 + */ +pj_bool_t pjsua_call_media_is_changing(pjsua_call *call) +{ + /* The problem in #1738 occurs because we do handle_events() loop while + * adding media, which could cause incoming re-INVITE to be processed and + * cause havoc. Since the handle_events() loop only happens while adding + * media, it is sufficient to only check if "prov > cnt" for now. + */ + return call->med_prov_cnt > call->med_cnt; +} + /* Initialize the media line */ pj_status_t pjsua_call_media_init(pjsua_call_media *call_med, pjmedia_type type, diff --git a/pjsip/src/pjsua-lib/pjsua_vid.c b/pjsip/src/pjsua-lib/pjsua_vid.c index 0096acab..026942d1 100644 --- a/pjsip/src/pjsua-lib/pjsua_vid.c +++ b/pjsip/src/pjsua-lib/pjsua_vid.c @@ -1535,6 +1535,11 @@ static pj_status_t call_add_video(pjsua_call *call, if (call->med_cnt == PJSUA_MAX_CALL_MEDIA) return PJ_ETOOMANY; + if (pjsua_call_media_is_changing(call)) { + PJ_LOG(1,(THIS_FILE, "Unable to add video" ERR_MEDIA_CHANGING)); + return PJ_EINVALIDOP; + } + /* Get active local SDP and clone it */ status = pjmedia_sdp_neg_get_active_local(call->inv->neg, ¤t_sdp); if (status != PJ_SUCCESS) @@ -1636,6 +1641,11 @@ static pj_status_t call_modify_video(pjsua_call *call, pjmedia_sdp_session *sdp; pj_status_t status; + if (pjsua_call_media_is_changing(call)) { + PJ_LOG(1,(THIS_FILE, "Unable to modify video" ERR_MEDIA_CHANGING)); + return PJ_EINVALIDOP; + } + /* Verify and normalize media index */ if (med_idx == -1) { int first_active; -- cgit v1.2.3