From ee0a12f26b6636a3ef17975b46007b5980d2bdfb Mon Sep 17 00:00:00 2001 From: Andrea Gianarda <andrea.gianarda@belledonne-communications.com> Date: Thu, 25 May 2023 11:19:13 +0200 Subject: [PATCH] Add test to verify behaviour when multiple INFO messages are sent back to back by both parties almost at the same time. --- src/conference/session/call-session.cpp | 11 +++- src/conference/session/media-session.cpp | 11 ++++ tester/call_race_conditions.c | 78 ++++++++++++++++++++---- tester/call_single_tester.c | 12 ++-- tester/call_video_tester.cpp | 2 +- tester/liblinphone_tester.h | 2 +- tester/message_tester.c | 2 +- tester/tester.c | 2 +- tools/python/unittests/linphonetester.py | 2 +- 9 files changed, 96 insertions(+), 26 deletions(-) diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 158232011b..125438d44f 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -635,15 +635,22 @@ void CallSessionPrivate::updated(bool isUpdate) { "Call updated by remote while in transcient state (Pausing/Updating/Resuming)"); acceptUpdate(nullptr, localState, Utils::toString(localState)); break; + case CallSession::State::End: + case CallSession::State::Released: + lWarning() << "Session [" << q + << "] is going to reject the reINVITE or UPDATE because it is already in state [" + << Utils::toString(state) << "]"; + sal_error_info_set(&sei, SalReasonNoMatch, "SIP", 0, "Incompatible SDP", nullptr); + op->declineWithErrorInfo(&sei, nullptr); + sal_error_info_reset(&sei); + break; case CallSession::State::Idle: case CallSession::State::OutgoingInit: - case CallSession::State::End: case CallSession::State::IncomingReceived: case CallSession::State::PushIncomingReceived: case CallSession::State::OutgoingProgress: case CallSession::State::Referred: case CallSession::State::Error: - case CallSession::State::Released: case CallSession::State::EarlyUpdatedByRemote: case CallSession::State::EarlyUpdating: lWarning() << "Receiving reINVITE or UPDATE while in state [" << Utils::toString(state) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index e71bd7d687..29ced9f0fb 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -696,6 +696,17 @@ bool MediaSessionPrivate::incompatibleSecurity(const std::shared_ptr<SalMediaDes void MediaSessionPrivate::updating(bool isUpdate) { L_Q(); + if ((state == CallSession::State::End) || (state == CallSession::State::Released)) { + lWarning() << "Session [" << q << "] is going to reject the reINVITE or UPDATE because it is already in state [" + << Utils::toString(state) << "]"; + SalErrorInfo sei; + memset(&sei, 0, sizeof(sei)); + sal_error_info_set(&sei, SalReasonNoMatch, "SIP", 0, "Incompatible SDP", nullptr); + op->declineWithErrorInfo(&sei, nullptr); + sal_error_info_reset(&sei); + return; + } + std::shared_ptr<SalMediaDescription> rmd = op->getRemoteMediaDescription(); // Fix local parameter before creating new local media description in order to have it consistent with the offer. // Note that in some case such as if we are the offerer or transition from the state UpdateByRemote to diff --git a/tester/call_race_conditions.c b/tester/call_race_conditions.c index daa487b5a9..4cc44081d9 100644 --- a/tester/call_race_conditions.c +++ b/tester/call_race_conditions.c @@ -65,19 +65,24 @@ static void call_with_video_added_by_both_parties(void) { linphone_call_params_unref(pauline_params); linphone_call_params_unref(marie_params); - BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallUpdating, 1, 10000)); - BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallUpdating, 1, 10000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallUpdating, 1, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE( + wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallUpdating, 1, liblinphone_tester_sip_timeout)); /* Marie shall transition to UpdatedByRemote (Pauline has priority per RFC3261 since she is the call-id owner)*/ - BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1, 10000)); + BC_ASSERT_TRUE( + wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1, liblinphone_tester_sip_timeout)); /* Marie will succeed with its re INVITE transaction */ - BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2, 10000)); + BC_ASSERT_TRUE( + wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout)); /* Pauline shall return to Updating state*/ - BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallUpdating, 2, 10000)); + BC_ASSERT_TRUE( + wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallUpdating, 2, liblinphone_tester_sip_timeout)); /* And finally succeed too */ - BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000)); + BC_ASSERT_TRUE( + wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout)); ei = linphone_call_get_error_info(marie_call); BC_ASSERT_TRUE(linphone_error_info_get_protocol_code(ei) == 0); @@ -93,6 +98,51 @@ end: linphone_core_manager_destroy(pauline); } +static void call_with_info_sent_by_both_parties(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = + linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall *marie_call, *pauline_call; + LinphoneInfoMessage *marie_info, *pauline_info; + bctbx_list_t *lcs = NULL; + bool_t call_ok; + int number_of_infos = 4; + + lcs = bctbx_list_append(lcs, marie->lc); + lcs = bctbx_list_append(lcs, pauline->lc); + + BC_ASSERT_TRUE(call_ok = call(pauline, marie)); + if (!call_ok) goto end; + + marie_call = linphone_core_get_current_call(marie->lc); + BC_ASSERT_PTR_NOT_NULL(marie_call); + pauline_call = linphone_core_get_current_call(pauline->lc); + BC_ASSERT_PTR_NOT_NULL(pauline_call); + + // Send multiple INFO messages in order to be sure to have at least one 491 request pending + for (int i = 0; i < number_of_infos; i++) { + marie_info = linphone_core_create_info_message(marie->lc); + pauline_info = linphone_core_create_info_message(pauline->lc); + + linphone_call_send_info_message(pauline_call, pauline_info); + linphone_call_send_info_message(marie_call, marie_info); + + linphone_info_message_unref(marie_info); + linphone_info_message_unref(pauline_info); + } + + BC_ASSERT_TRUE( + wait_for_list(lcs, &pauline->stat.number_of_InfoReceived, number_of_infos, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE( + wait_for_list(lcs, &marie->stat.number_of_InfoReceived, number_of_infos, liblinphone_tester_sip_timeout)); + + end_call(pauline, marie); +end: + bctbx_list_free(lcs); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void call_paused_by_both_parties(void) { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager *pauline = @@ -113,11 +163,11 @@ static void call_paused_by_both_parties(void) { linphone_call_pause(marie_call); linphone_call_pause(pauline_call); - BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPausing, 1, 10000)); - BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallPausing, 1, 10000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPausing, 1, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallPausing, 1, liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPaused, 1, 10000)); - BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallPaused, 1, 10000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPaused, 1, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallPaused, 1, liblinphone_tester_sip_timeout)); BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1, int, "%d"); BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallPausing, 2, int, "%d"); @@ -128,8 +178,10 @@ static void call_paused_by_both_parties(void) { /* both resume the call at the same time */ linphone_call_resume(marie_call); linphone_call_resume(pauline_call); - BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2, 10000)); - BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000)); + BC_ASSERT_TRUE( + wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE( + wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout)); liblinphone_tester_check_rtcp(pauline, marie); end_call(pauline, marie); @@ -168,7 +220,6 @@ static void call_end_and_reinvite(void) { BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, 10000)); BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, 1, 10000)); BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, 10000)); - end: bctbx_list_free(lcs); linphone_core_manager_destroy(marie); @@ -177,6 +228,7 @@ end: static test_t call_race_conditions_tests[] = { TEST_NO_TAG("Call with video added by both parties", call_with_video_added_by_both_parties), + TEST_NO_TAG("Call with INFO sent by both parties", call_with_info_sent_by_both_parties), TEST_NO_TAG("Call paused by both parties", call_paused_by_both_parties), TEST_NO_TAG("Call ended and re-invited at the same time", call_end_and_reinvite)}; diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 44d73626a4..308d8f8c06 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -4314,8 +4314,8 @@ static void call_established_with_rejected_info(void) { im2 = linphone_core_create_info_message(pauline->lc); linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc), im2); - BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_inforeceived, 1)); - BC_ASSERT_EQUAL(marie->stat.number_of_inforeceived, 1, int, "%d"); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_InfoReceived, 1)); + BC_ASSERT_EQUAL(marie->stat.number_of_InfoReceived, 1, int, "%d"); linphone_info_message_unref(im2); check_call_state(pauline, LinphoneCallStreamsRunning); @@ -4354,8 +4354,8 @@ static void call_established_with_complex_rejected_operation(void) { info = linphone_core_create_info_message(marie->lc); linphone_call_send_info_message(linphone_core_get_current_call(marie->lc), info); linphone_info_message_unref(info); - BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_inforeceived, 1)); - BC_ASSERT_EQUAL(pauline->stat.number_of_inforeceived, 1, int, "%d"); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_InfoReceived, 1)); + BC_ASSERT_EQUAL(pauline->stat.number_of_InfoReceived, 1, int, "%d"); /*to give time for 200ok to arrive*/ wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000); @@ -4425,8 +4425,8 @@ static void call_established_with_rejected_info_during_reinvite(void) { info = linphone_core_create_info_message(marie->lc); linphone_call_send_info_message(linphone_core_get_current_call(marie->lc), info); linphone_info_message_unref(info); - BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_inforeceived, 1)); - BC_ASSERT_EQUAL(pauline->stat.number_of_inforeceived, 1, int, "%d"); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_InfoReceived, 1)); + BC_ASSERT_EQUAL(pauline->stat.number_of_InfoReceived, 1, int, "%d"); /*to give time for 200ok to arrive*/ wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000); diff --git a/tester/call_video_tester.cpp b/tester/call_video_tester.cpp index c28114e83d..5df9ee23a4 100644 --- a/tester/call_video_tester.cpp +++ b/tester/call_video_tester.cpp @@ -1789,7 +1789,7 @@ static void multiple_early_media(void) { info = linphone_core_create_info_message(marie1->lc); linphone_call_send_info_message(marie1_call, info); linphone_info_message_unref(info); - BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_inforeceived, 1, 3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_InfoReceived, 1, 3000)); } end_call(pauline, marie1); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 224722283b..dac5b88d40 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -380,7 +380,7 @@ typedef struct _stats { int number_of_LinphoneConsolidatedPresenceDoNotDisturb; int number_of_LinphoneConsolidatedPresenceOffline; - int number_of_inforeceived; + int number_of_InfoReceived; LinphoneInfoMessage *last_received_info_message; int number_of_LinphoneSubscriptionIncomingReceived; diff --git a/tester/message_tester.c b/tester/message_tester.c index 487b775fd6..548eb48742 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -2347,7 +2347,7 @@ void info_message_base(bool_t with_content) { linphone_call_send_info_message(linphone_core_get_current_call(marie->lc), info); linphone_info_message_unref(info); - BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_inforeceived, 1)); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_InfoReceived, 1)); BC_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_info_message); hvalue = linphone_info_message_get_header(pauline->stat.last_received_info_message, "Weather"); diff --git a/tester/tester.c b/tester/tester.c index ca36c07dd6..97d8bb1683 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -3517,7 +3517,7 @@ void info_message_received(LinphoneCore *lc, BCTBX_UNUSED(LinphoneCall *call), c linphone_info_message_unref(counters->last_received_info_message); } counters->last_received_info_message = linphone_info_message_copy(msg); - counters->number_of_inforeceived++; + counters->number_of_InfoReceived++; } void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { diff --git a/tools/python/unittests/linphonetester.py b/tools/python/unittests/linphonetester.py index 15eb9ab4e1..2430823311 100644 --- a/tools/python/unittests/linphonetester.py +++ b/tools/python/unittests/linphonetester.py @@ -281,7 +281,7 @@ class CoreManagerStats: self.number_of_LinphonePresenceActivityWorship = 0 self.last_received_presence = None - self.number_of_inforeceived = 0 + self.number_of_InfoReceived = 0 self.number_of_LinphoneSubscriptionIncomingReceived = 0 self.number_of_LinphoneSubscriptionOutgoingInit = 0 -- GitLab