Commit 1edfd5a4 authored by jehan's avatar jehan
Browse files

Fix behavior in case of device unregistration for a user member of a group chat.

parent e6411533
......@@ -100,10 +100,12 @@ void ServerGroupChatRoomPrivate::setState (ChatRoom::State state) {
}else{
bool atLeastOneDeviceJoining = false;
bool atLeastOneDevicePresent = false;
bool atLeastOneDeviceLeaving = false;
for (const auto &device : participant->getPrivate()->getDevices()) {
switch (device->getState()) {
case ParticipantDevice::State::ScheduledForLeaving:
case ParticipantDevice::State::Leaving:
atLeastOneDeviceLeaving = true;
break;
case ParticipantDevice::State::ScheduledForJoining:
case ParticipantDevice::State::Joining:
......@@ -116,7 +118,10 @@ void ServerGroupChatRoomPrivate::setState (ChatRoom::State state) {
break;
}
}
if (atLeastOneDevicePresent || atLeastOneDeviceJoining){
//Basically the only case where this participant is not authorized is in case it was removed from the room but not all
//its devices were "BYEed" yet. This is what the line below is testing. Might be better to add a new state in the participant Class,
// but it's not the case yet.
if (atLeastOneDevicePresent || atLeastOneDeviceJoining || atLeastOneDeviceLeaving == false ){
authorizedParticipants.push_back(participant);
}
}
......@@ -227,9 +232,14 @@ void ServerGroupChatRoomPrivate::requestDeletion(){
* to the C++ object.
* The destruction is defered to next main loop iteration, in order to make the self-destruction outside of the call stack that leaded to it.
*/
q->getCore()->doLater([q](){
LinphoneChatRoom * cChatRoom = L_GET_C_BACK_PTR(q);
if (cChatRoom) linphone_chat_room_unref(cChatRoom);
//just in case ServerGroupChatRoom is destroyed before lambda is executed
std::weak_ptr<ChatRoom> cppChatRoom(q->getSharedFromThis());
q->getCore()->doLater([cppChatRoom](){
auto obj = cppChatRoom.lock();
if (obj) {
LinphoneChatRoom * cChatRoom = L_GET_C_BACK_PTR(obj);
if (cChatRoom) linphone_chat_room_unref(cChatRoom);
}
});
}
......@@ -403,6 +413,7 @@ void ServerGroupChatRoomPrivate::removeParticipant (const shared_ptr<const Parti
for (const auto &p : authorizedParticipants) {
if (participant->getAddress() == p->getAddress()) {
lInfo() << q <<" 'participant ' "<< p->getAddress() <<" no more authorized'";
authorizedParticipants.remove(p);
break;
}
......@@ -756,6 +767,8 @@ void ServerGroupChatRoomPrivate::addParticipantDevice (const shared_ptr<Particip
}else{
setParticipantDeviceState(device, ParticipantDevice::State::ScheduledForJoining);
}
} else {
lWarning()<< q << ": Participant device " << participant << " cannot be added because not authorized";
}
}
......@@ -987,43 +1000,28 @@ bool ServerGroupChatRoomPrivate::allDevicesLeft(const std::shared_ptr<Participan
void ServerGroupChatRoomPrivate::onParticipantDeviceLeft (const std::shared_ptr<ParticipantDevice> &device) {
L_Q();
L_Q_T(LocalConference, qConference);
lInfo() << q << ": Participant device '" << device->getAddress().asString() << "' left";
if (! (capabilities & ServerGroupChatRoom::Capabilities::OneToOne) ){
shared_ptr<Participant> participant = const_pointer_cast<Participant>(device->getParticipant()->getSharedFromThis());
if (allDevicesLeft(participant)) {
/* Handle the case where a participant is removed forcibly because all its devices have been retired. */
if (findAuthorizedParticipant(participant->getAddress()) != nullptr) {
lInfo() << q << ": Removing participant '" << participant->getAddress().asString() << "' since it has no device left";
q->removeParticipant(participant);
}
/* When all devices have left, we can get rid of our reginfo subscription. */
if (allDevicesLeft(participant) && findAuthorizedParticipant(participant->getAddress()) == nullptr) {
lInfo() << q << ": Participant '" << participant->getAddress().asString() << "'removed and last device left, unsubscribing";
unSubscribeRegistrationForParticipant(participant->getAddress());
/* And remove the existence of this participant in the chatroom*/
q->LocalConference::removeParticipant(participant);
}
if (qConference->getPrivate()->participants.size() == 0) {
lInfo() << q << ": No participant left, deleting the chat room";
requestDeletion();
}
}else{
/* For 1 to 1 chatrooms, if all devices of both participants are left we'll delete the chatroom*/
bool allLeft = true;
for (const auto &participant : q->getParticipants()){
if (!allDevicesLeft(participant)){
allLeft = false;
break;
}
}
if (allLeft){
lInfo() << q << ": No participant left, deleting the chat room";
requestDeletion();
}
/* if all devices of participants are left we'll delete the chatroom*/
bool allLeft = true;
for (const auto &participant : q->LocalConference::getParticipants()){
if (!allDevicesLeft(participant)){
allLeft = false;
break;
}
}
if (allLeft){
lInfo() << q << ": No participant left, deleting the chat room";
requestDeletion();
}
}
// -----------------------------------------------------------------------------
......
......@@ -303,7 +303,7 @@ endif()
# on mobile platforms, we compile the tester as a library so that we can link with it directly from native applications
if(ANDROID OR IOS)
add_library(linphonetester SHARED ${HEADER_FILES} ${SOURCE_FILES_C} ${SOURCE_FILES_CXX})
target_include_directories(linphonetester PRIVATE ${LINPHONE_INCLUDE_DIRS})
target_include_directories(linphonetester PRIVATE ${LINPHONE_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS})
target_link_libraries(linphonetester ${LINPHONE_LIBS_FOR_TOOLS} ${OTHER_LIBS_FOR_TESTER})
#TODO: replace by if(APPLE) when we want to make apple framework on linphone-desktop too
if(IOS)
......
......@@ -5572,6 +5572,121 @@ end:
linphone_core_manager_destroy(pauline1);
}
static void group_chat_room_device_unregistered (void) {
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
LinphoneCoreManager *laure = linphone_core_manager_create("laure_tcp_rc");
bctbx_list_t *coresManagerList = NULL;
bctbx_list_t *participantsAddresses = NULL;
coresManagerList = bctbx_list_append(coresManagerList, marie);
coresManagerList = bctbx_list_append(coresManagerList, pauline);
coresManagerList = bctbx_list_append(coresManagerList, laure);
bctbx_list_t *coresList = init_core_for_conference(coresManagerList);
start_core_for_conference(coresManagerList);
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc)));
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(laure->lc)));
stats initialMarieStats = marie->stat;
stats initialPaulineStats = pauline->stat;
stats initialLaureStats = laure->stat;
// Marie creates a new group chat room
const char *initialSubject = "Colleagues";
LinphoneChatRoom *marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, FALSE);
participantsAddresses = NULL;
const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
// Check that the chat room is correctly created on Pauline's side and that the participants are added
LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline, &initialPaulineStats, confAddr, initialSubject, 2, FALSE);
// Check that the chat room is correctly created on Laure's side and that the participants are added
LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure, &initialLaureStats, confAddr, initialSubject, 2, FALSE);
LinphoneProxyConfig *proxyConfig = linphone_core_get_default_proxy_config(laure->lc);
linphone_proxy_config_edit(proxyConfig);
linphone_proxy_config_enable_register(proxyConfig, FALSE);
linphone_proxy_config_done(proxyConfig);
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneRegistrationCleared, initialMarieStats.number_of_LinphoneRegistrationCleared + 1, 3000));
//Current expected behavior is to have participant devices removed
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_participant_devices_removed, initialMarieStats.number_of_participant_devices_removed + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_participant_devices_removed, initialPaulineStats.number_of_participant_devices_removed + 1, 3000));
BC_ASSERT_FALSE(wait_for_list(coresList, &marie->stat.number_of_participants_removed, initialMarieStats.number_of_participants_removed + 1, 5000));
BC_ASSERT_FALSE(wait_for_list(coresList, &pauline->stat.number_of_participants_removed, initialPaulineStats.number_of_participants_removed + 1, 5000));
//to avoid automatique re-subscription of chatroom while disabling network
linphone_core_enter_background(marie->lc);
linphone_core_enter_background(pauline->lc);
linphone_core_enter_background(laure->lc);
wait_for_list(coresList,NULL,1,3000);
//to force re-re-connection to restarted flexisip
linphone_core_set_network_reachable(marie->lc, FALSE);
linphone_core_set_network_reachable(pauline->lc, FALSE);
linphone_core_set_network_reachable(laure->lc, FALSE);
//break here and restart Flexisip
marie->stat.number_of_participant_devices_added = 0;
pauline->stat.number_of_participant_devices_added=0;
proxyConfig = linphone_core_get_default_proxy_config(laure->lc);
linphone_proxy_config_edit(proxyConfig);
linphone_proxy_config_enable_register(proxyConfig, TRUE);
linphone_proxy_config_done(proxyConfig);
linphone_core_enter_foreground(marie->lc);
linphone_core_set_network_reachable(marie->lc, TRUE);
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneRegistrationOk, initialMarieStats.number_of_LinphoneRegistrationOk + 1, 10000));
linphone_core_enter_foreground(pauline->lc);
linphone_core_set_network_reachable(pauline->lc, TRUE);
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneRegistrationOk, initialPaulineStats.number_of_LinphoneRegistrationOk + 1, 10000));
linphone_core_enter_foreground(laure->lc);
linphone_core_set_network_reachable(laure->lc, TRUE);
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneRegistrationOk, initialLaureStats.number_of_LinphoneRegistrationOk + 1, 10000));
//in case of flexisip restart
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_participant_devices_added, initialMarieStats.number_of_participant_devices_added + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_participant_devices_added, initialPaulineStats.number_of_participant_devices_added + 1, 3000));
// Laure adds a new device without group chat enabled
initialMarieStats = marie->stat;
initialPaulineStats = pauline->stat;
initialLaureStats = laure->stat;
LinphoneCoreManager *laure2 = linphone_core_manager_new("laure_tcp_rc");
coresManagerList = bctbx_list_append(coresManagerList, laure2);
proxyConfig = linphone_core_get_default_proxy_config(laure->lc);
linphone_proxy_config_edit(proxyConfig);
linphone_proxy_config_enable_register(proxyConfig, FALSE);
linphone_proxy_config_done(proxyConfig);
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneRegistrationCleared, initialLaureStats.number_of_LinphoneRegistrationCleared + 1, 3000));
//Current expected behavior is to have participant devices removed
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_participant_devices_removed, initialMarieStats.number_of_participant_devices_removed + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_participant_devices_removed, initialPaulineStats.number_of_participant_devices_removed + 1, 3000));
BC_ASSERT_FALSE(wait_for_list(coresList, &marie->stat.number_of_participants_removed, initialMarieStats.number_of_participants_removed + 1, 5000));
BC_ASSERT_FALSE(wait_for_list(coresList, &pauline->stat.number_of_participants_removed, initialPaulineStats.number_of_participants_removed + 1, 5000));
// Clean db from chat room
linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
linphone_core_manager_delete_chat_room(laure, laureCr, coresList);
linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
bctbx_list_free(coresList);
bctbx_list_free(coresManagerList);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(laure);
linphone_core_manager_destroy(laure2);
}
test_t group_chat_tests[] = {
TEST_NO_TAG("Chat room params", group_chat_room_params),
TEST_NO_TAG("Chat room with forced local identity", group_chat_room_creation_with_given_identity),
......@@ -5636,7 +5751,9 @@ test_t group_chat_tests[] = {
TEST_ONE_TAG("Check if participant device are removed", group_chat_room_join_one_to_one_chat_room_with_a_new_device_not_notified, "LeaksMemory" /*due to core restart*/),
TEST_ONE_TAG("Subscribe successfull after set chat database path", subscribe_test_after_set_chat_database_path, "LeaksMemory" /*due to core restart*/),
TEST_ONE_TAG("Send forward message", one_to_one_chat_room_send_forward_message, "LeaksMemory" /*due to core restart*/),
TEST_ONE_TAG("Linphone core stop/start and chatroom ref", core_stop_start_with_chat_room_ref, "LeaksMemory" /*due to core restart*/)
TEST_ONE_TAG("Linphone core stop/start and chatroom ref", core_stop_start_with_chat_room_ref, "LeaksMemory" /*due to core restart*/),
TEST_ONE_TAG("Subscribe successfull after set chat database path", subscribe_test_after_set_chat_database_path, "LeaksMemory" /*due to core restart*/),
TEST_ONE_TAG("Make sure device unregistration does not triger user to be removed from a group", group_chat_room_device_unregistered, "LeaksMemory" /*due network up/down*/)
};
test_suite_t group_chat_test_suite = {
......
127.0.0.1 sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org sipv4.example.org conf.example.org subscribe.example.org lime.wildcard1.linphone.org http-proxy.example.org stun.example.org external.example.org
127.0.0.1 sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org sipv4.example.org conf.example.org subscribe.example.org lime.wildcard1.linphone.org http-proxy.example.org stun.example.org external.example.org sip1.example.org
::1 lime.wildcard1.linphone.org sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org external.example.org
::1 lime.wildcard1.linphone.org sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org external.example.org sip1.example.org
188.165.46.90 tunnel.wildcard2.linphone.org
......
......@@ -579,6 +579,7 @@ void linphone_core_manager_reinit(LinphoneCoreManager *mgr) {
if (mgr->lc) {
if (lp_config_get_string(linphone_core_get_config(mgr->lc), "misc", "uuid", NULL))
uuid = bctbx_strdup(lp_config_get_string(linphone_core_get_config(mgr->lc), "misc", "uuid", NULL));
linphone_core_set_network_reachable(mgr->lc, FALSE); // to avoid unregister
linphone_core_unref(mgr->lc);
}
linphone_core_manager_configure(mgr);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment