diff --git a/src/chat/encryption/lime-x3dh-encryption-engine.cpp b/src/chat/encryption/lime-x3dh-encryption-engine.cpp index 48e24de69465663f0ec3fd7a669256fc9af477c3..f36025eafe15973598106f8b11519bab313bf9ea 100644 --- a/src/chat/encryption/lime-x3dh-encryption-engine.cpp +++ b/src/chat/encryption/lime-x3dh-encryption-engine.cpp @@ -231,16 +231,12 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processOutgoingMessage(con } const auto &chatRoomParams = chatRoom->getCurrentParams(); - auto conferenceAddress = chatRoom->getConferenceAddress(); - auto conferenceAddressStr = conferenceAddress ? conferenceAddress->asString() : std::string("sip:"); // Check if chatroom is encrypted or not if (chatRoomParams->getChatParams()->isEncrypted()) { - lInfo() << "[LIME] chatroom " << chatRoom << " (address " << conferenceAddressStr - << ") is encrypted, proceed to encrypt outgoing message"; + lInfo() << "[LIME] " << *chatRoom << " is encrypted, proceed to encrypt outgoing message"; } else { - lInfo() << "[LIME] chatroom " << chatRoom << " (address " << conferenceAddressStr - << ") is not encrypted, no need to encrypt outgoing message"; + lInfo() << "[LIME] " << *chatRoom << " is not encrypted, no need to encrypt outgoing message"; return ChatMessageModifier::Result::Skipped; } @@ -279,7 +275,7 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processOutgoingMessage(con nbDevice++; } else { lWarning() << "Multiple instances of participant device with address " << address - << " have been found in chat room " << conferenceAddressStr; + << " have been found in " << *chatRoom; requestFullState = true; } } @@ -306,7 +302,7 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processOutgoingMessage(con nbDevice++; } else { lWarning() << "Multiple instances of me participant device with address " << address - << " have been found in chat room " << conferenceAddressStr; + << " have been found in " << *chatRoom; requestFullState = true; } } @@ -315,8 +311,7 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processOutgoingMessage(con // Check if there is at least one recipient if (recipientAddresses.empty()) { - lError() << "[LIME] encrypting message on chatroom " << chatRoom << " (address " << conferenceAddressStr - << ") with no recipient"; + lError() << "[LIME] encrypting message on " << *chatRoom << " with no recipient"; errorCode = 488; return ChatMessageModifier::Result::Error; } @@ -489,9 +484,9 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con // Check if chatroom is encrypted or not const auto &chatRoomParams = chatRoom->getCurrentParams(); if (chatRoomParams->getChatParams()->isEncrypted()) { - lInfo() << "[LIME] this chatroom is encrypted, proceed to decrypt incoming message"; + lInfo() << "[LIME] " << *chatRoom << " is encrypted, proceed to decrypt incoming message"; } else { - lInfo() << "[LIME] this chatroom is not encrypted, no need to decrypt incoming message"; + lInfo() << "[LIME] " << *chatRoom << " is not encrypted, no need to decrypt incoming message"; return ChatMessageModifier::Result::Skipped; } @@ -501,7 +496,7 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con // Check if the message is encrypted and unwrap the multipart if (!isMessageEncrypted(*internalContent)) { - lError() << "[LIME] unexpected content-type: " << internalContent->getContentType(); + lError() << "[LIME] " << *chatRoom << ": unexpected content-type: " << internalContent->getContentType(); // Set unencrypted content warning flag because incoming message type is unexpected message->getPrivate()->setUnencryptedContentWarning(true); // Disable sender authentication otherwise the unexpected message will always be discarded @@ -512,7 +507,7 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con const auto &account = chatRoom->getAccount(); if (!account) { - lWarning() << "Receiving encrypted message with unknown account"; + lWarning() << "[LIME] " << *chatRoom << ": Receiving encrypted message with unknown account"; errorCode = 488; // Not Acceptable return ChatMessageModifier::Result::Error; } @@ -520,7 +515,7 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con const auto &localDevice = accountContactAddress ? accountContactAddress : chatRoom->getConferenceId().getLocalAddress(); if (!localDevice) { - lWarning() << "Receiving encrypted message but the local device address is unknown"; + lWarning() << "[LIME] " << *chatRoom << ": Receiving encrypted message but the local device address is unknown"; errorCode = 488; // Not Acceptable return ChatMessageModifier::Result::Error; } @@ -554,8 +549,7 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con // Early discard of malformed incoming message: we must have a sender Id to decrypt the message if (senderDeviceId.empty()) { - lWarning() << "[LIME] discard malformed incoming message [" << message << "] for [" << localDeviceId - << "]: no sender Device Id found "; + lWarning() << "[LIME] " << *chatRoom << " for [" << localDeviceId << "]: no sender Device Id found "; errorCode = 488; // Not Acceptable return ChatMessageModifier::Result::Error; } @@ -565,7 +559,8 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con if (linphone_config_get_int(linphone_core_get_config(chatRoom->getCore()->getCCore()), "lime", "allow_message_in_unsafe_chatroom", 0) == 0) { if (peerDeviceStatus == lime::PeerDeviceStatus::unsafe) { - lWarning() << "[LIME] discard incoming message from unsafe sender device " << senderDeviceId; + lWarning() << "[LIME] " << *chatRoom << ": discard incoming message from unsafe sender device " + << senderDeviceId; errorCode = 488; // Not Acceptable return ChatMessageModifier::Result::Error; } @@ -598,13 +593,15 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con } if (forceFailure) { - lError() << "No key found (on purpose for tests) for [" << localDeviceId << "] for message [" << message << "]"; + lError() << "[LIME] " << *chatRoom << ": No key found (on purpose for tests) for [" << localDeviceId + << "] for message [" << message << "]"; errorCode = 488; // Not Acceptable return ChatMessageModifier::Result::Error; } if (cipherHeader.empty()) { - lError() << "No key found for [" << localDeviceId << "] for message [" << message << "]"; + lError() << "[LIME] " << *chatRoom << ": No key found for [" << localDeviceId << "] for message [" << message + << "]"; errorCode = 488; // Not Acceptable return ChatMessageModifier::Result::Error; } @@ -619,12 +616,12 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con peerDeviceStatus = limeManager->decrypt(localDeviceId, recipientUserId, senderDeviceId, decodedCipherHeader, decodedCipherMessage, plainMessage); } catch (const exception &e) { - lError() << e.what() << " while decrypting message"; + lError() << "[LIME] " << *chatRoom << ": " << e.what() << " while decrypting message"; peerDeviceStatus = lime::PeerDeviceStatus::fail; } if (peerDeviceStatus == lime::PeerDeviceStatus::fail) { - lError() << "Failed to decrypt message from " << senderDeviceId; + lError() << "[LIME] " << *chatRoom << ": Failed to decrypt message from " << senderDeviceId; errorCode = 488; // Not Acceptable return ChatMessageModifier::Result::Error; } diff --git a/src/chat/encryption/lime-x3dh-server-engine.cpp b/src/chat/encryption/lime-x3dh-server-engine.cpp index 820b0efbfe71f58838892232174ed6a084bbb479..65cc47e03ffee2922fa9c0bbf33ef8e7e752740d 100644 --- a/src/chat/encryption/lime-x3dh-server-engine.cpp +++ b/src/chat/encryption/lime-x3dh-server-engine.cpp @@ -63,9 +63,9 @@ LimeX3dhEncryptionServerEngine::processOutgoingMessage(const std::shared_ptr<Cha // Check if chatroom is encrypted or not const auto &chatRoomParams = chatRoom->getCurrentParams(); if (chatRoomParams->getChatParams()->isEncrypted()) { - lInfo() << "[LIME][server] this chatroom is encrypted, proceed to encrypt outgoing message"; + lInfo() << "[LIME][server] " << *chatRoom << " is encrypted, proceed to encrypt outgoing message"; } else { - lInfo() << "[LIME][server] this chatroom is not encrypted, no need to encrypt outgoing message"; + lInfo() << "[LIME][server] " << *chatRoom << " is not encrypted, no need to encrypt outgoing message"; return ChatMessageModifier::Result::Skipped; } @@ -92,7 +92,8 @@ LimeX3dhEncryptionServerEngine::processOutgoingMessage(const std::shared_ptr<Cha } if (!hasKey) { - lError() << "[LIME][server] this message doesn't contain the cipher key for participant " << toDeviceId; + lError() << "[LIME][server] " << *chatRoom << ": message [" << message + << "] doesn't contain the cipher key for participant " << toDeviceId; return ChatMessageModifier::Result::Error; } @@ -105,7 +106,9 @@ LimeX3dhEncryptionServerEngine::processOutgoingMessage(const std::shared_ptr<Cha if (linphone_core_content_encoding_supported(message->getChatRoom()->getCore()->getCCore(), "deflate")) { finalContent.setContentEncoding("deflate"); } else { - lWarning() << "Cannot use 'deflate' Content-Encoding to compress body - consider rebuilding with libz support."; + lWarning() + << "[LIME][server] " << *chatRoom + << ": Cannot use 'deflate' Content-Encoding to compress body - consider rebuilding with libz support."; } message->setInternalContent(finalContent); return ChatMessageModifier::Result::Done; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5bdf60abd69054879b88f81195a1a8390d5df68e..447931206c2bd15c7a710be1096f1a2737a58933 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -7155,7 +7155,7 @@ void MainDb::cleanupConferenceInfo(time_t expiredBeforeThisTime) { ? "(julianday(:maxExpireTime) - julianday(conference_info.start_time)) * 24 * 60" : "TIMESTAMPDIFF(MINUTES, :maxExpireTime, conference_info.start_time)"; // The logic to find conference that may be deleted because their end time is in the past is the following: - // - compute how much time has elapsed since the start of the conference ans verify yhay this value is larger or + // - compute how much time has elapsed since the start of the conference and verify that this value is larger or // equal to the duration. // - verify that the duration is larger than 0 std::string findQuery = "SELECT conference_info.id, uri_sip_address.value FROM conference_info, sip_address AS " diff --git a/tester/local-conference-tester-functions.cpp b/tester/local-conference-tester-functions.cpp index 6703f14c609531c0851bab6e98625cf4443a1db0..1eed350f5839268fcfe5a0a91b9e9d8c8b5e4a72 100644 --- a/tester/local-conference-tester-functions.cpp +++ b/tester/local-conference-tester-functions.cpp @@ -1440,6 +1440,8 @@ void create_conference_base(time_t start_time, std::list<LinphoneCoreManager *> participants{laure.getCMgr(), pauline.getCMgr()}; std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}; + std::list<LinphoneCoreManager *> allConferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), + laure.getCMgr()}; std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}; time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60); @@ -2819,12 +2821,27 @@ void create_conference_base(time_t start_time, int no_local_participants = 3; if (uninvited_participant_dials) { if (end_time > 0) { + for (auto mgr : conferenceMgrs) { + LinphoneConferenceInfo *info = + linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); + if (BC_ASSERT_PTR_NOT_NULL(info)) { + linphone_conference_info_unref(info); + } + } time_t now = ms_time(NULL); time_t time_left = end_time - now + linphone_core_get_conference_cleanup_period(focus.getLc()); + // Verify that a participant can be added after the conference ends if the conference is active if (add_participant_after_end && (time_left > 0)) { // wait for the conference to end CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}) .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); + for (auto mgr : conferenceMgrs) { + LinphoneConferenceInfo *info = + linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); + if (BC_ASSERT_PTR_NOT_NULL(info)) { + linphone_conference_info_unref(info); + } + } } } stats marie_stat2 = marie.getStats(); @@ -2861,6 +2878,7 @@ void create_conference_base(time_t start_time, } conferenceMgrs.push_back(michelle.getCMgr()); + allConferenceMgrs.push_back(michelle.getCMgr()); members.push_back(michelle.getCMgr()); participantList.insert(std::make_pair( michelle.getCMgr(), add_participant_info_to_list(&participants_info, michelle.getCMgr()->identity, @@ -3371,6 +3389,7 @@ void create_conference_base(time_t start_time, extraParticipantMgrs.push_back(berthe.getCMgr()); conferenceMgrs.push_back(berthe.getCMgr()); + allConferenceMgrs.push_back(berthe.getCMgr()); members.push_back(berthe.getCMgr()); participantList.insert(std::make_pair( berthe.getCMgr(), add_participant_info_to_list(&participants_info, berthe.getCMgr()->identity, @@ -4061,6 +4080,26 @@ void create_conference_base(time_t start_time, liblinphone_tester_sip_timeout)); } + if (end_time > 0) { + time_t now = ms_time(NULL); + time_t time_left = end_time - now + linphone_core_get_conference_cleanup_period(focus.getLc()); + if (time_left < 0) { + time_left = 0; + } + for (auto mgr : allConferenceMgrs) { + LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); + if (BC_ASSERT_PTR_NOT_NULL(info)) { + linphone_conference_info_unref(info); + } + } + // wait for the conference to end + CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}) + .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); + LinphoneConferenceInfo *focus_info = + linphone_core_find_conference_information_from_uri(focus.getLc(), confAddr); + BC_ASSERT_PTR_NULL(focus_info); + } + std::list<LinphoneCoreManager *> allMembers{marie.getCMgr(), pauline.getCMgr()}; if (!version_mismatch) allMembers.push_back(laure.getCMgr()); if ((participant_list_type == LinphoneConferenceParticipantListTypeOpen) && uninvited_participant_dials) { @@ -7063,7 +7102,9 @@ void create_conference_with_chat_base(LinphoneConferenceSecurityLevel security_l long cleanup_window, bool_t use_relay_ice_candidates, bool_t client_reenter_conference, - bool_t network_drops) { + bool_t network_drops, + time_t start_time) { + Focus focus("chloe_rc"); { // to make sure focus is destroyed after clients. bool_t enable_lime = (security_level == LinphoneConferenceSecurityLevelEndToEnd ? TRUE : FALSE); @@ -7148,7 +7189,6 @@ void create_conference_with_chat_base(LinphoneConferenceSecurityLevel security_l configure_end_to_end_encrypted_conference_server(focus); } - time_t start_time = ms_time(NULL) - 45; int duration = 1; time_t end_time = (start_time + duration * 60); const char *initialSubject = "Test characters: ^ :) ¤ çà @"; @@ -7993,9 +8033,25 @@ void create_conference_with_chat_base(LinphoneConferenceSecurityLevel security_l time_left += focus_cleanup_window; } if (time_left > 0) { + for (auto mgr : conferenceMgrs) { + LinphoneConferenceInfo *info = + linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); + if (BC_ASSERT_PTR_NOT_NULL(info)) { + linphone_conference_info_unref(info); + } + } // wait for the conference to end CoreManagerAssert({focus, marie, pauline, michelle, laure, berthe}) .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); + LinphoneConferenceInfo *focus_info = + linphone_core_find_conference_information_from_uri(focus.getLc(), confAddr); + if (focus_cleanup_window > 0) { + BC_ASSERT_PTR_NULL(focus_info); + } else { + if (BC_ASSERT_PTR_NOT_NULL(focus_info)) { + linphone_conference_info_unref(focus_info); + } + } } } @@ -8225,6 +8281,486 @@ void create_conference_with_chat_base(LinphoneConferenceSecurityLevel security_l } } +void conference_joined_multiple_times(LinphoneConferenceSecurityLevel security_level, + bool_t enable_chat, + long cleanup_window) { + Focus focus("chloe_rc"); + { // to make sure focus is destroyed after clients. + bool_t enable_lime = (security_level == LinphoneConferenceSecurityLevelEndToEnd ? TRUE : FALSE); + ClientConference marie("marie_rc", focus.getConferenceFactoryAddress(), enable_lime); + ClientConference pauline("pauline_rc", focus.getConferenceFactoryAddress(), enable_lime); + ClientConference laure("laure_tcp_rc", focus.getConferenceFactoryAddress(), enable_lime); + ClientConference michelle("michelle_rc", focus.getConferenceFactoryAddress(), enable_lime); + ClientConference berthe("berthe_rc", focus.getConferenceFactoryAddress(), enable_lime); + + focus.registerAsParticipantDevice(marie); + focus.registerAsParticipantDevice(pauline); + focus.registerAsParticipantDevice(laure); + focus.registerAsParticipantDevice(michelle); + focus.registerAsParticipantDevice(berthe); + + setup_conference_info_cbs(marie.getCMgr()); + + bctbx_list_t *coresList = NULL; + + for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(), + berthe.getCMgr()}) { + LinphoneVideoActivationPolicy *pol = + linphone_factory_create_video_activation_policy(linphone_factory_get()); + linphone_video_activation_policy_set_automatically_accept(pol, TRUE); + linphone_video_activation_policy_set_automatically_initiate(pol, TRUE); + linphone_core_set_video_activation_policy(mgr->lc, pol); + linphone_video_activation_policy_unref(pol); + + linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id); + linphone_core_enable_video_capture(mgr->lc, TRUE); + linphone_core_enable_video_display(mgr->lc, TRUE); + + if (mgr != focus.getCMgr()) { + linphone_core_set_default_conference_layout(mgr->lc, LinphoneConferenceLayoutActiveSpeaker); + linphone_core_set_media_encryption(mgr->lc, enable_lime ? LinphoneMediaEncryptionZRTP + : LinphoneMediaEncryptionNone); + linphone_config_set_bool(linphone_core_get_config(mgr->lc), "sip", "chat_messages_aggregation", TRUE); + linphone_config_set_int(linphone_core_get_config(mgr->lc), "sip", "chat_messages_aggregation_delay", + 2000); + + LinphoneAccount *account = linphone_core_get_default_account(mgr->lc); + const LinphoneAccountParams *account_params = linphone_account_get_params(account); + LinphoneAccountParams *new_account_params = linphone_account_params_clone(account_params); + linphone_account_params_set_conference_factory_address(new_account_params, + focus.getConferenceFactoryAddress().toC()); + linphone_account_params_set_audio_video_conference_factory_address( + new_account_params, focus.getConferenceFactoryAddress().toC()); + linphone_account_set_params(account, new_account_params); + linphone_account_params_unref(new_account_params); + } + + // Enable ICE at the account level but not at the core level + enable_stun_in_mgr(mgr, TRUE, TRUE, FALSE, FALSE); + + linphone_config_set_int(linphone_core_get_config(mgr->lc), "sip", "update_call_when_ice_completed", TRUE); + linphone_config_set_int(linphone_core_get_config(mgr->lc), "sip", + "update_call_when_ice_completed_with_dtls", FALSE); + + coresList = bctbx_list_append(coresList, mgr->lc); + } + + int nortp_timeout = 10; + linphone_core_set_nortp_timeout(marie.getLc(), nortp_timeout); + linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url); + linphone_core_set_conference_participant_list_type(focus.getLc(), LinphoneConferenceParticipantListTypeClosed); + linphone_core_set_conference_cleanup_period(focus.getLc(), cleanup_window); + + std::list<LinphoneCoreManager *> participants{laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr(), + berthe.getCMgr()}; + std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), + laure.getCMgr(), michelle.getCMgr(), berthe.getCMgr()}; + std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), + michelle.getCMgr(), berthe.getCMgr()}; + + if (security_level == LinphoneConferenceSecurityLevelEndToEnd) { + configure_end_to_end_encrypted_conference_server(focus); + } + + time_t start_time = ms_time(NULL); + int duration = 2; + time_t end_time = (start_time + duration * 60); + const char *initialSubject = "Test characters: ^ :) ¤ çà @"; + const char *description = "Paris Baker"; + + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; + participantList.insert( + std::make_pair(laure.getCMgr(), add_participant_info_to_list(&participants_info, laure.getCMgr()->identity, + LinphoneParticipantRoleSpeaker, -1))); + participantList.insert(std::make_pair( + pauline.getCMgr(), add_participant_info_to_list(&participants_info, pauline.getCMgr()->identity, + LinphoneParticipantRoleListener, -1))); + participantList.insert(std::make_pair( + michelle.getCMgr(), add_participant_info_to_list(&participants_info, michelle.getCMgr()->identity, + LinphoneParticipantRoleSpeaker, -1))); + participantList.insert(std::make_pair( + berthe.getCMgr(), add_participant_info_to_list(&participants_info, berthe.getCMgr()->identity, + LinphoneParticipantRoleListener, -1))); + participantList.insert( + std::make_pair(laure.getCMgr(), add_participant_info_to_list(&participants_info, laure.getCMgr()->identity, + LinphoneParticipantRoleSpeaker, -1))); + + LinphoneAddress *confAddr = + create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, + description, TRUE, security_level, TRUE, enable_chat, NULL); + BC_ASSERT_PTR_NOT_NULL(confAddr); + char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("sip:"); + + // Chat room creation to send ICS + BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneChatRoomStateCreated, 4, + liblinphone_tester_sip_timeout)); + + int nb_client_subscribes = (security_level == LinphoneConferenceSecurityLevelEndToEnd) ? 2 : 1; + const LinphoneMediaEncryption encryption = (security_level == LinphoneConferenceSecurityLevelNone) + ? LinphoneMediaEncryptionNone + : LinphoneMediaEncryptionZRTP; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_member_list(members, participantList, marie.getCMgr(), participants_info); + + long focus_cleanup_window = linphone_core_get_conference_cleanup_period(focus.getLc()); + + // Client will join and leave the conference a number of times + for (int attempt = 1; attempt <= 5; attempt++) { + if ((focus_cleanup_window > 0) && (end_time > 0)) { + time_t now = ms_time(NULL); + time_t time_left = end_time - now; + if (time_left < 0) { + ms_message("Attempt #%0d - conference %s already ended %ld seconds ago", attempt, + conference_address_str, -time_left); + // In order to verify the rejoining of conferences, the loop must have at least 2 iterations + BC_ASSERT_GREATER_STRICT(attempt, 2, int, "%0d"); + break; + } + } + stats focus_stat = focus.getStats(); + for (auto mgr : members) { + LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr); + linphone_call_params_set_media_encryption(new_params, encryption); + linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionSendRecv); + ms_message("Attempt #%0d - %s is entering conference %s", attempt, linphone_core_get_identity(mgr->lc), + conference_address_str); + linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr); + linphone_call_params_unref(new_params); + LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); + BC_ASSERT_PTR_NOT_NULL(pcall); + if (pcall) { + LinphoneCallLog *call_log = linphone_call_get_call_log(pcall); + BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); + } + } + + for (auto mgr : members) { + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, attempt, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, attempt, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2 * attempt, + liblinphone_tester_sip_timeout)); + // Update to add to conference. + // If ICE is enabled, the addition to a conference may go through a resume of the call + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, attempt, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneChatRoomStateCreated, + ((mgr == marie.getCMgr()) ? 4 : 1), liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, + attempt * nb_client_subscribes, 5000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, + attempt * nb_client_subscribes, 5000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_NotifyFullStateReceived, attempt, + liblinphone_tester_sip_timeout)); + if (security_level == LinphoneConferenceSecurityLevelEndToEnd) { + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_NotifyEktReceived, attempt, + liblinphone_tester_sip_timeout)); + } + + if ((encryption == LinphoneMediaEncryptionDTLS) || (encryption == LinphoneMediaEncryptionZRTP)) { + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEncryptedOn, attempt, + liblinphone_tester_sip_timeout)); + } + + LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); + BC_ASSERT_PTR_NOT_NULL(pcall); + if (pcall) { + const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall); + const LinphoneMediaEncryption pcall_enc = linphone_call_params_get_media_encryption(call_cparams); + BC_ASSERT_EQUAL(pcall_enc, encryption, int, "%d"); + } + LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity); + BC_ASSERT_PTR_NOT_NULL(ccall); + if (ccall) { + const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall); + const LinphoneMediaEncryption ccall_enc = linphone_call_params_get_media_encryption(call_cparams); + BC_ASSERT_EQUAL(ccall_enc, encryption, int, "%d"); + } + + LinphoneAddress *deviceAddr = + linphone_account_get_contact_address(linphone_core_get_default_account(mgr->lc)); + LinphoneChatRoom *core_chat_room = + linphone_core_search_chat_room(mgr->lc, NULL, deviceAddr, confAddr, NULL); + if (enable_chat) { + BC_ASSERT_PTR_NOT_NULL(core_chat_room); + } else { + BC_ASSERT_PTR_NULL(core_chat_room); + } + + LinphoneChatRoom *conference_chat_room = NULL; + LinphoneConference *pconference = + linphone_core_search_conference(mgr->lc, NULL, mgr->identity, confAddr, NULL); + BC_ASSERT_PTR_NOT_NULL(pconference); + if (pconference) { + conference_chat_room = linphone_conference_get_chat_room(pconference); + if (enable_chat) { + BC_ASSERT_PTR_NOT_NULL(conference_chat_room); + } else { + BC_ASSERT_PTR_NULL(conference_chat_room); + } + if (conference_chat_room) { + BC_ASSERT_FALSE(linphone_chat_room_is_read_only(conference_chat_room)); + } + } + BC_ASSERT_PTR_EQUAL(conference_chat_room, core_chat_room); + } + + if ((encryption == LinphoneMediaEncryptionDTLS) || (encryption == LinphoneMediaEncryptionZRTP)) { + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEncryptedOn, + attempt * static_cast<int>(members.size()), + liblinphone_tester_sip_timeout)); + } + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived, + focus_stat.number_of_LinphoneCallIncomingReceived + 5, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote, + focus_stat.number_of_LinphoneCallUpdatedByRemote + 5, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning, + focus_stat.number_of_LinphoneCallStreamsRunning + 10, + liblinphone_tester_sip_timeout)); + // If ICE is enabled, the addition to a conference may go through a resume of the call + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated, + focus_stat.number_of_LinphoneConferenceStateCreated + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list( + coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived, + focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 5 * nb_client_subscribes, 5000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive, + focus_stat.number_of_LinphoneSubscriptionActive + 5 * nb_client_subscribes, + 5000)); + + if (enable_chat) { + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_chat_room_participants_added, + focus_stat.number_of_chat_room_participants_added + 5, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_chat_room_participant_devices_added, + focus_stat.number_of_chat_room_participant_devices_added + 5, + liblinphone_tester_sip_timeout)); + } + + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added, + focus_stat.number_of_participants_added + 5, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added, + focus_stat.number_of_participant_devices_added + 5, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_conference_participant_devices_present, + focus_stat.number_of_conference_participant_devices_present + 5, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_present, + focus_stat.number_of_participant_devices_present + 5, + liblinphone_tester_sip_timeout)); + + wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, + focus.getCMgr(), memberList, confAddr, TRUE); + + for (auto mgr : members) { + LinphoneConference *pconference = + linphone_core_search_conference(mgr->lc, NULL, mgr->identity, confAddr, NULL); + BC_ASSERT_PTR_NOT_NULL(pconference); + if (pconference) { + LinphoneChatRoom *chat_room = linphone_conference_get_chat_room(pconference); + if (enable_chat) { + BC_ASSERT_PTR_NOT_NULL(chat_room); + } else { + BC_ASSERT_PTR_NULL(chat_room); + } + if (chat_room) { + bctbx_list_t *chat_room_participants = linphone_chat_room_get_participants(chat_room); + BC_ASSERT_EQUAL(bctbx_list_size(chat_room_participants), 4, size_t, "%zu"); + bctbx_list_free_with_data(chat_room_participants, + (bctbx_list_free_func)linphone_participant_unref); + BC_ASSERT_FALSE(linphone_chat_room_is_read_only(chat_room)); + const LinphoneChatRoomParams *params = linphone_chat_room_get_current_params(chat_room); + LinphoneChatParams *chat_params = linphone_conference_params_get_chat_params(params); + BC_ASSERT_PTR_NOT_NULL(chat_params); + if (chat_params) { + LinphoneChatRoomEncryptionBackend encryption_backend = + enable_lime ? LinphoneChatRoomEncryptionBackendLime + : LinphoneChatRoomEncryptionBackendNone; + BC_ASSERT_EQUAL(linphone_chat_params_get_encryption_backend(chat_params), + encryption_backend, int, "%d"); + BC_ASSERT_EQUAL(linphone_chat_params_encryption_enabled(chat_params), !!enable_lime, int, + "%d"); + } + } + BC_ASSERT_TRUE( + CoreManagerAssert({focus, marie, pauline, michelle, laure, berthe}).wait([&pconference] { + bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference); + size_t nb_devices = bctbx_list_size(devices); + if (devices) { + bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref); + } + return nb_devices == 5; + })); + } + } + + // wait a bit more to detect side effect if any + CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] { + return false; + }); + + auto remaining_members = members; + for (auto mgr : members) { + stats focus_stat2 = focus.getStats(); + remaining_members.pop_front(); + std::list<stats> remaining_members_stats; + int nb_members = 0; + for (auto remaining_mgr : remaining_members) { + remaining_members_stats.push_back(remaining_mgr->stat); + LinphoneCall *pcall = + linphone_core_get_call_by_remote_address2(remaining_mgr->lc, focus.getCMgr()->identity); + BC_ASSERT_PTR_NOT_NULL(pcall); + if (pcall) { + const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall); + if (linphone_call_params_video_enabled(call_cparams)) { + nb_members++; + } + } + } + const bctbx_list_t *participant_calls = linphone_core_get_calls(mgr->lc); + int participant_calls_nb = static_cast<int>(bctbx_list_size(participant_calls)); + BC_ASSERT_EQUAL(participant_calls_nb, 1, int, "%d"); + + LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity); + BC_ASSERT_PTR_NOT_NULL(call); + if (call) { + ms_message("Attempt #%0d - %s is terminating call with %s", attempt, + linphone_core_get_identity(mgr->lc), linphone_core_get_identity(focus.getLc())); + linphone_call_terminate(call); + } + + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, attempt, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, attempt, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, + attempt * nb_client_subscribes, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending, + attempt, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, attempt, + liblinphone_tester_sip_timeout)); + if (!enable_chat) { + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, + attempt, liblinphone_tester_sip_timeout)); + } + + LinphoneConference *pconference = + linphone_core_search_conference(mgr->lc, NULL, mgr->identity, confAddr, NULL); + if (enable_chat) { + BC_ASSERT_PTR_NOT_NULL(pconference); + if (pconference) { + BC_ASSERT_PTR_NOT_NULL(linphone_conference_get_chat_room(pconference)); + } + } else { + BC_ASSERT_PTR_NULL(pconference); + } + + participant_calls = linphone_core_get_calls(mgr->lc); + participant_calls_nb = static_cast<int>(bctbx_list_size(participant_calls)); + BC_ASSERT_EQUAL(participant_calls_nb, 0, int, "%d"); + + for (auto remaining_mgr : remaining_members) { + stats stat = remaining_members_stats.front(); + remaining_members_stats.pop_front(); + if (enable_chat) { + BC_ASSERT_TRUE(wait_for_list( + coresList, &remaining_mgr->stat.number_of_chat_room_participants_removed, + stat.number_of_chat_room_participants_removed + 1, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list( + coresList, &remaining_mgr->stat.number_of_chat_room_participant_devices_removed, + stat.number_of_chat_room_participant_devices_removed + 1, liblinphone_tester_sip_timeout)); + } + + BC_ASSERT_TRUE(wait_for_list(coresList, &remaining_mgr->stat.number_of_participants_removed, + stat.number_of_participants_removed + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &remaining_mgr->stat.number_of_participant_devices_removed, + stat.number_of_participant_devices_removed + 1, + liblinphone_tester_sip_timeout)); + } + + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote, + focus_stat2.number_of_LinphoneCallUpdatedByRemote + nb_members, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning, + focus_stat2.number_of_LinphoneCallStreamsRunning + nb_members, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed, + focus_stat2.number_of_participants_removed + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed, + focus_stat2.number_of_participant_devices_removed + 1, + liblinphone_tester_sip_timeout)); + } + + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd, + focus_stat.number_of_LinphoneCallEnd + 5, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased, + focus_stat.number_of_LinphoneCallReleased + 5, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionTerminated, + focus_stat.number_of_LinphoneSubscriptionTerminated + 5, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed, + focus_stat.number_of_participants_removed + 5, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed, + focus_stat.number_of_participant_devices_removed + 5, + liblinphone_tester_sip_timeout)); + + BC_ASSERT_TRUE(wait_for_list(coresList, + &focus.getStats().number_of_LinphoneConferenceStateTerminationPending, 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1, + liblinphone_tester_sip_timeout)); + + for (auto mgr : conferenceMgrs) { + LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); + if (BC_ASSERT_PTR_NOT_NULL(info)) { + linphone_conference_info_unref(info); + } + } + + // wait a bit more to detect side effect if any + CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(5), [] { + return false; + }); + } + + if ((focus_cleanup_window > 0) && (end_time > 0)) { + time_t now = ms_time(NULL); + time_t time_left = end_time - now + focus_cleanup_window; + if (time_left < 0) { + time_left = 0; + } + // wait for the conference to end + CoreManagerAssert({focus, marie, pauline, michelle, laure, berthe}) + .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); + } + + LinphoneConferenceInfo *focus_info = + linphone_core_find_conference_information_from_uri(focus.getLc(), confAddr); + if (focus_cleanup_window > 0) { + BC_ASSERT_PTR_NULL(focus_info); + } else { + if (BC_ASSERT_PTR_NOT_NULL(focus_info)) { + linphone_conference_info_unref(focus_info); + } + } + + ms_free(conference_address_str); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); + linphone_address_unref(confAddr); + bctbx_list_free(coresList); + } +} + void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) { Focus focus("chloe_rc"); { // to make sure focus is destroyed after clients. diff --git a/tester/local-conference-tester-functions.h b/tester/local-conference-tester-functions.h index 14f63fc3027c76549e85aeee976d47bb642d26ce..fe14f065757843c07dd604090d29f9d829b2f3ed 100644 --- a/tester/local-conference-tester-functions.h +++ b/tester/local-conference-tester-functions.h @@ -305,6 +305,10 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice, LinphoneConferenceSecurityLevel security_level, bool_t enable_screen_sharing); +void conference_joined_multiple_times(LinphoneConferenceSecurityLevel security_level, + bool_t enable_chat, + long cleanup_window); + void create_conference_base(time_t start_time, int duration, bool_t uninvited_participant_dials, @@ -352,7 +356,8 @@ void create_conference_with_chat_base(LinphoneConferenceSecurityLevel security_l long cleanup_window, bool_t slow_ice_negotiation, bool_t client_reenter_conference, - bool_t network_drops); + bool_t network_drops, + time_t start_time); void configure_end_to_end_encrypted_conference_server(Focus &focus); diff --git a/tester/local-encrypted-conference-tester.cpp b/tester/local-encrypted-conference-tester.cpp index ca230e88eb613eb13c866346b20f2a3f9d78bed6..1ea12665e9f8d8c78f939e1e967e4338e4060a8c 100644 --- a/tester/local-encrypted-conference-tester.cpp +++ b/tester/local-encrypted-conference-tester.cpp @@ -893,17 +893,18 @@ static void create_simple_end_to_end_encrypted_conference_with_participant_added } static void create_encrypted_conference_with_chat() { - create_conference_with_chat_base(LinphoneConferenceSecurityLevelEndToEnd, FALSE, FALSE, TRUE, 1, FALSE, TRUE, - FALSE); + create_conference_with_chat_base(LinphoneConferenceSecurityLevelEndToEnd, FALSE, FALSE, TRUE, 1, FALSE, TRUE, FALSE, + ms_time(NULL)); } static void create_encrypted_conference_with_chat_and_cores_restart(void) { - create_conference_with_chat_base(LinphoneConferenceSecurityLevelEndToEnd, TRUE, TRUE, TRUE, 1, FALSE, TRUE, FALSE); + create_conference_with_chat_base(LinphoneConferenceSecurityLevelEndToEnd, TRUE, TRUE, TRUE, 1, FALSE, TRUE, FALSE, + (ms_time(NULL) - 45)); } static void create_encrypted_conference_with_chat_network_drops_and_participant_rejoining(void) { - create_conference_with_chat_base(LinphoneConferenceSecurityLevelEndToEnd, FALSE, FALSE, FALSE, -1, TRUE, TRUE, - TRUE); + create_conference_with_chat_base(LinphoneConferenceSecurityLevelEndToEnd, FALSE, FALSE, FALSE, -1, TRUE, TRUE, TRUE, + (ms_time(NULL) - 45)); } static void scheduling_failure_check(LinphoneConferenceScheduler *scheduler, LinphoneConferenceSchedulerState state) { @@ -1157,12 +1158,19 @@ static void create_simple_end_to_end_encrypted_conference_merging_calls() { LinphoneConferenceSecurityLevelEndToEnd, FALSE); } +static void encrypted_conference_joined_multiple_times(void) { + conference_joined_multiple_times(LinphoneConferenceSecurityLevelEndToEnd, FALSE, -1); +} + } // namespace LinphoneTest static test_t local_conference_end_to_end_encryption_scheduled_conference_tests[] = { TEST_ONE_TAG("First notify", LinphoneTest::first_notify_ekt_xml_composing_parsing_test, "End2EndConf"), TEST_ONE_TAG("SPI info", LinphoneTest::spi_info_ekt_xml_composing_parsing_test, "End2EndConf"), TEST_ONE_TAG("Cipher transport", LinphoneTest::cipher_transport_ekt_xml_composing_parsing_test, "End2EndConf"), + TEST_ONE_TAG("End-to-End Conference joined multiple times", + LinphoneTest::encrypted_conference_joined_multiple_times, + "End2EndConf"), TEST_ONE_TAG("Create simple end-to-end encrypted conference", LinphoneTest::create_simple_end_to_end_encrypted_conference, "End2EndConf"), diff --git a/tester/local-scheduled-conference-tester.cpp b/tester/local-scheduled-conference-tester.cpp index 6262051b5b0dd13e860a6becb8fc8c02a46ea0c7..e8ed163a408c073d7beef8200cef5fa4cae647f7 100644 --- a/tester/local-scheduled-conference-tester.cpp +++ b/tester/local-scheduled-conference-tester.cpp @@ -1721,7 +1721,7 @@ static void schedule_simple_conference_db_conference_scheduler(void) { } static void create_simple_conference(void) { - create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE, + create_conference_base(ms_time(NULL), 1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE, LinphoneMediaEncryptionNone, FALSE, LinphoneConferenceLayoutGrid, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, LinphoneMediaDirectionRecvOnly, FALSE, LinphoneConferenceSecurityLevelNone, {LinphoneParticipantRoleSpeaker, LinphoneParticipantRoleListener}, FALSE, FALSE, FALSE, @@ -6156,24 +6156,28 @@ static void create_simple_conference_in_sfu_payload_mode(void) { } static void create_conference_with_chat(void) { - create_conference_with_chat_base(LinphoneConferenceSecurityLevelNone, FALSE, FALSE, TRUE, -1, TRUE, FALSE, FALSE); + create_conference_with_chat_base(LinphoneConferenceSecurityLevelNone, FALSE, FALSE, TRUE, 1, TRUE, FALSE, FALSE, + ms_time(NULL)); } static void create_point_to_point_encrypted_conference_with_chat(void) { create_conference_with_chat_base(LinphoneConferenceSecurityLevelPointToPoint, FALSE, FALSE, TRUE, -1, TRUE, FALSE, - FALSE); + FALSE, ms_time(NULL)); } static void create_conference_with_chat_and_participant_rejoining(void) { - create_conference_with_chat_base(LinphoneConferenceSecurityLevelNone, FALSE, FALSE, TRUE, -1, TRUE, TRUE, FALSE); + create_conference_with_chat_base(LinphoneConferenceSecurityLevelNone, FALSE, FALSE, TRUE, -1, TRUE, TRUE, FALSE, + (ms_time(NULL) - 45)); } static void create_conference_with_chat_and_cores_restart(void) { - create_conference_with_chat_base(LinphoneConferenceSecurityLevelNone, TRUE, TRUE, TRUE, 1, FALSE, FALSE, FALSE); + create_conference_with_chat_base(LinphoneConferenceSecurityLevelNone, TRUE, TRUE, TRUE, 1, FALSE, FALSE, FALSE, + (ms_time(NULL) - 45)); } static void create_conference_with_chat_network_drops_and_participant_rejoining(void) { - create_conference_with_chat_base(LinphoneConferenceSecurityLevelNone, FALSE, FALSE, FALSE, -1, TRUE, TRUE, TRUE); + create_conference_with_chat_base(LinphoneConferenceSecurityLevelNone, FALSE, FALSE, FALSE, -1, TRUE, TRUE, TRUE, + (ms_time(NULL) - 45)); } #ifndef HAVE_EKT_SERVER_PLUGIN @@ -6819,9 +6823,18 @@ static void create_conference_with_chat_with_server_restarted_before_conference_ } } +static void conference_joined_multiple_times(void) { + conference_joined_multiple_times(LinphoneConferenceSecurityLevelPointToPoint, FALSE, 1); +} + +static void conference_with_chat_joined_multiple_times(void) { + conference_joined_multiple_times(LinphoneConferenceSecurityLevelNone, TRUE, 1); +} + } // namespace LinphoneTest static test_t local_conference_scheduled_conference_basic_tests[] = { + TEST_NO_TAG("Conference joined multiple times", LinphoneTest::conference_joined_multiple_times), TEST_NO_TAG("Call to inexisting conference address", LinphoneTest::call_to_inexisting_conference_address), TEST_NO_TAG("Conference with media lost", LinphoneTest::conference_with_media_lost), TEST_NO_TAG("Conference with participants are late except for one", @@ -6935,6 +6948,7 @@ static test_t local_conference_scheduled_conference_with_screen_sharing_tests[] LinphoneTest::create_simple_conference_with_screen_sharing_no_video_send_component)}; static test_t local_conference_scheduled_conference_with_chat_tests[] = { + TEST_NO_TAG("Conference with chat joined multiple times", LinphoneTest::conference_with_chat_joined_multiple_times), TEST_NO_TAG("Create conference with chat", LinphoneTest::create_conference_with_chat), TEST_NO_TAG("Create point-to-point encrypted conference with chat", LinphoneTest::create_point_to_point_encrypted_conference_with_chat),