diff --git a/src/conference/handlers/client-conference-event-handler.cpp b/src/conference/handlers/client-conference-event-handler.cpp index c257badc59b0570c9877338851c10d7b0078ab62..5a99f850cf2272b66827bce8df096966768b54bd 100644 --- a/src/conference/handlers/client-conference-event-handler.cpp +++ b/src/conference/handlers/client-conference-event-handler.cpp @@ -151,8 +151,17 @@ void ClientConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm } try { + bool isFullState = (confInfo->getState() == StateType::full); + const auto conference = getConference(); + if (waitingFullState && !isFullState) { + // No need to do any processing if the client is waiting a full state + lError() << "Unable to process received NOTIFY because " << *conference << " is waiting a full state"; + return; + } else { + waitingFullState = false; + } + const auto &core = getCore(); - const auto &conference = getConference(); const auto &chatRoom = conference->getChatRoom(); const auto &conferenceAddress = conference->getConferenceAddress(); std::shared_ptr<Address> entityAddress = Address::create(confInfo->getEntity()); @@ -160,29 +169,25 @@ void ClientConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm auto prunedConferenceAddress = conferenceAddress ? conferenceAddress->getUriWithoutGruu() : Address(); if (!conferenceAddress || (prunedEntityAddress != prunedConferenceAddress)) { - lError() << "Unable to process received NOTIFY because the entity address " << prunedEntityAddress + lError() << "Unable to process received NOTIFY for conference " << *conference + << " because the entity address " << prunedEntityAddress << " doesn't match the conference address " << prunedConferenceAddress << " or the conference address is not valid"; return; } - bool isFullState = confInfo->getState() == StateType::full; - if (isFullState) { setInitialSubscriptionUnderWayFlag(false); } - bool synchronizing = fullStateRequested; + + // The client is synchronizing when it requested a full state as there was a discrepancy between its last notify + // ID and the one from the server or the server sent a full state to catch up a big number of missed events + const auto currentNotifyVersion = getLastNotify(); + bool synchronizing = fullStateRequested || (isFullState && (currentNotifyVersion != 0)); if (isFullState && fullStateRequested) { fullStateRequested = false; } - if (waitingFullState && !isFullState) { - lError() << "Unable to process received NOTIFY because " << *conference << " is waiting a full state"; - return; - } else { - waitingFullState = false; - } - auto &confDescription = confInfo->getConferenceDescription(); // 1. Compute event time. @@ -196,15 +201,14 @@ void ClientConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm // 2. Update last notify. { - const auto previousLastNotify = getLastNotify(); auto &version = confInfo->getVersion(); if (version.present()) { unsigned int notifyVersion = version.get(); - synchronizing |= isFullState && (previousLastNotify >= notifyVersion); - if (!isFullState && (previousLastNotify >= notifyVersion)) { - lWarning() << "Ignoring conference notify for: " << getConferenceId() - << ", notify version received is: " << notifyVersion - << ", should be stricly more than last notify id of conference: " << previousLastNotify; + if (!isFullState && (currentNotifyVersion >= notifyVersion)) { + lWarning() << "Ignoring conference notify for " << *conference << " (" << getConferenceId() + << "): notify version received (" << notifyVersion + << ") should be stricly larger than the current notify version (" << currentNotifyVersion + << ")"; requestFullState(); return; } @@ -798,9 +802,7 @@ void ClientConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm void ClientConferenceEventHandler::requestFullState() { auto conference = getConference(); - lInfo() << "Requesting full state for conference " - << (conference->getConferenceAddress() ? conference->getConferenceAddress()->toString() - : std::string("sip:")); + lInfo() << "Requesting full state for " << *conference; unsubscribe(); conference->setLastNotify(0); subscribe(getConferenceId()); diff --git a/tester/local-chat-tester.cpp b/tester/local-chat-tester.cpp index be1f6d882d36ad81fb9ec75226de6715b405ac73..1d1e60ee3290bd10d86f30f6e655393939a1da78 100644 --- a/tester/local-chat-tester.cpp +++ b/tester/local-chat-tester.cpp @@ -2277,13 +2277,18 @@ static void group_chat_room_with_server_database_corruption(void) { } } -static void group_chat_room_bulk_notify_to_participant(void) { +static void group_chat_room_bulk_notify_to_participant_base(bool_t trigger_full_state) { Focus focus("chloe_rc"); { // to make sure focus is destroyed after clients. ClientConference marie("marie_rc", focus.getConferenceFactoryAddress()); ClientConference pauline("pauline_rc", focus.getConferenceFactoryAddress()); ClientConference michelle("michelle_rc", focus.getConferenceFactoryAddress()); + if (trigger_full_state) { + linphone_config_set_int(linphone_core_get_config(focus.getLc()), "misc", + "full_state_trigger_due_to_missing_updates", 1); + } + focus.registerAsParticipantDevice(marie); focus.registerAsParticipantDevice(pauline); focus.registerAsParticipantDevice(michelle); @@ -2485,28 +2490,37 @@ static void group_chat_room_bulk_notify_to_participant(void) { initialPaulineStats = pauline.getStats(); // Pauline comes up online + ms_message("%s turns network on again", linphone_core_get_identity(pauline.getLc())); linphone_core_set_network_reachable(pauline.getLc(), TRUE); BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneRegistrationOk, initialPaulineStats.number_of_LinphoneRegistrationOk + 1, liblinphone_tester_sip_timeout)); - // Check that Pauline receives the backlog of events occurred while she was offline - BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added, - initialPaulineStats.number_of_participants_added + 1, - liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added, - initialPaulineStats.number_of_participant_devices_added + 1, - liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed, - initialPaulineStats.number_of_subject_changed + 1, - liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_removed, - initialPaulineStats.number_of_participant_devices_removed + 1, - liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_removed, - initialPaulineStats.number_of_participants_removed + 1, - liblinphone_tester_sip_timeout)); + if (trigger_full_state) { + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_NotifyFullStateReceived, + initialPaulineStats.number_of_NotifyFullStateReceived + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneChatRoomConferenceJoined, + initialPaulineStats.number_of_LinphoneChatRoomConferenceJoined + 1, 2000)); + } else { + // Check that Pauline receives the backlog of events occurred while she was offline + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added, + initialPaulineStats.number_of_participants_added + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added, + initialPaulineStats.number_of_participant_devices_added + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed, + initialPaulineStats.number_of_subject_changed + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_removed, + initialPaulineStats.number_of_participant_devices_removed + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_removed, + initialPaulineStats.number_of_participants_removed + 1, + liblinphone_tester_sip_timeout)); + } BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d"); BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(paulineCr), newSubject2); @@ -2540,6 +2554,14 @@ static void group_chat_room_bulk_notify_to_participant(void) { } } +static void group_chat_room_bulk_notify_to_participant(void) { + group_chat_room_bulk_notify_to_participant_base(FALSE); +} + +static void group_chat_room_bulk_notify_full_state_to_participant(void) { + group_chat_room_bulk_notify_to_participant_base(TRUE); +} + static void one_to_one_chatroom_backward_compatibility_base(const char *groupchat_spec) { Focus focus("chloe_rc"); { // to make sure focus is destroyed after clients. @@ -3742,8 +3764,9 @@ static test_t local_conference_chat_basic_tests[] = { TEST_ONE_TAG("Group chat with client restart", LinphoneTest::group_chat_room_with_client_restart, "LeaksMemory"), /* beacause of coreMgr restart*/ - TEST_NO_TAG("Group chat room bulk notify to participant", - LinphoneTest::group_chat_room_bulk_notify_to_participant), /* because of network up and down*/ + TEST_NO_TAG("Group chat room bulk notify to participant", LinphoneTest::group_chat_room_bulk_notify_to_participant), + TEST_NO_TAG("Group chat room bulk notify full state to participant", + LinphoneTest::group_chat_room_bulk_notify_full_state_to_participant), TEST_ONE_TAG("One to one chatroom exhumed while participant is offline", LinphoneTest::one_to_one_chatroom_exhumed_while_offline, "LeaksMemory"), /* because of network up and down*/