Commit 3e7baa8a authored by Paul Cartier's avatar Paul Cartier
Browse files

Asynchronous core stop

parent f1c08b5e
......@@ -147,6 +147,7 @@ static void set_media_network_reachable(LinphoneCore* lc,bool_t isReachable);
static void linphone_core_run_hooks(LinphoneCore *lc);
static void linphone_core_zrtp_cache_close(LinphoneCore *lc);
void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName);
static void _linphone_core_stop_async_end(LinphoneCore *lc);
#include "enum.h"
#include "contact_providers_priv.h"
......@@ -3625,6 +3626,12 @@ void linphone_core_iterate(LinphoneCore *lc){
if (liblinphone_serialize_logs == TRUE) {
ortp_logv_flush();
}
if (lc->state == LinphoneGlobalShutdown && lc->async_stop) {
if (L_GET_PRIVATE_FROM_C_OBJECT(lc)->asyncStopDone()) {
_linphone_core_stop_async_end(lc);
}
}
}
LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url){
......@@ -6329,12 +6336,129 @@ LinphoneXmlRpcSession * linphone_core_create_xml_rpc_session(LinphoneCore *lc, c
return linphone_xml_rpc_session_new(lc, url);
}
/**
* First part of the async Core stop:
* Called by linphone_core_stop_async() to begin the async stop process and change the state to "Shutdown"
*/
static void _linphone_core_stop_async_start(LinphoneCore *lc) {
linphone_task_list_free(&lc->hooks);
lc->video_conf.show_local = FALSE;
lc->async_stop = TRUE;
L_GET_PRIVATE_FROM_C_OBJECT(lc)->shutdown();
#ifdef VIDEO_ENABLED
if (lc->previewstream!=NULL){
video_preview_stop(lc->previewstream);
lc->previewstream=NULL;
}
#endif
lc->msevq=NULL;
linphone_core_stop_ringing(lc);
linphone_core_set_state(lc, LinphoneGlobalShutdown, "Shutdown");
}
/**
* Second part of the async Core stop:
* After we made sure all asynchronous tasks are finished, this function is called to clean the objects
* and change the state to "Off"
*/
static void _linphone_core_stop_async_end(LinphoneCore *lc) {
L_GET_PRIVATE_FROM_C_OBJECT(lc)->stop();
lc->chat_rooms = bctbx_list_free_with_data(lc->chat_rooms, (bctbx_list_free_func)linphone_chat_room_unref);
getPlatformHelpers(lc)->onLinphoneCoreStop();
/* save all config */
friends_config_uninit(lc);
sip_config_uninit(lc);
net_config_uninit(lc);
rtp_config_uninit(lc);
sound_config_uninit(lc);
video_config_uninit(lc);
codecs_config_uninit(lc);
sip_setup_unregister_all();
if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config);
bctbx_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_unref);
lc->call_logs=bctbx_list_free(lc->call_logs);
if(lc->zrtp_secrets_cache != NULL) {
ms_free(lc->zrtp_secrets_cache);
lc->zrtp_secrets_cache = NULL;
}
if(lc->user_certificates_path != NULL) {
ms_free(lc->user_certificates_path);
lc->user_certificates_path = NULL;
}
if(lc->play_file!=NULL){
ms_free(lc->play_file);
lc->play_file = NULL;
}
if(lc->rec_file!=NULL){
ms_free(lc->rec_file);
lc->rec_file = NULL;
}
if (lc->logs_db_file) {
ms_free(lc->logs_db_file);
lc->logs_db_file = NULL;
}
if (lc->friends_db_file) {
ms_free(lc->friends_db_file);
lc->friends_db_file = NULL;
}
if (lc->tls_key){
ms_free(lc->tls_key);
lc->tls_key = NULL;
}
if (lc->tls_cert){
ms_free(lc->tls_cert);
lc->tls_cert = NULL;
}
if (lc->ringtoneplayer) {
linphone_ringtoneplayer_destroy(lc->ringtoneplayer);
lc->ringtoneplayer = NULL;
}
if (lc->im_encryption_engine) {
linphone_im_encryption_engine_unref(lc->im_encryption_engine);
lc->im_encryption_engine = NULL;
}
if (lc->default_ac_service) {
linphone_account_creator_service_unref(lc->default_ac_service);
lc->default_ac_service = NULL;
}
linphone_core_free_payload_types(lc);
if (lc->supported_formats) ms_free((void *)lc->supported_formats);
lc->supported_formats = NULL;
linphone_core_call_log_storage_close(lc);
linphone_core_friends_storage_close(lc);
linphone_core_zrtp_cache_close(lc);
ms_bandwidth_controller_destroy(lc->bw_controller);
lc->bw_controller = NULL;
ms_factory_destroy(lc->factory);
lc->factory = NULL;
if (lc->platform_helper) delete getPlatformHelpers(lc);
lc->platform_helper = NULL;
linphone_core_set_state(lc, LinphoneGlobalOff, "Off");
}
static void _linphone_core_stop(LinphoneCore *lc) {
bctbx_list_t *elem = NULL;
int i=0;
bool_t wait_until_unsubscribe = FALSE;
linphone_task_list_free(&lc->hooks);
lc->video_conf.show_local = FALSE;
lc->async_stop = FALSE;
linphone_core_set_state(lc, LinphoneGlobalShutdown, "Shutdown");
......@@ -6448,6 +6572,10 @@ void linphone_core_stop(LinphoneCore *lc) {
_linphone_core_stop(lc);
}
void linphone_core_stop_async(LinphoneCore *lc) {
_linphone_core_stop_async_start(lc);
}
void _linphone_core_uninit(LinphoneCore *lc)
{
lc->is_unreffing = TRUE;
......
......@@ -838,7 +838,8 @@ namespace LinphonePrivate {
bctbx_list_t *callsCache; \
bool_t dns_set_by_app; \
int auto_download_incoming_files_max_size; \
bool_t sender_name_hidden_in_forward_message;
bool_t sender_name_hidden_in_forward_message; \
bool_t async_stop;
#define LINPHONE_CORE_STRUCT_FIELDS \
LINPHONE_CORE_STRUCT_BASE_FIELDS \
......
......@@ -1067,6 +1067,17 @@ LINPHONE_PUBLIC LinphoneStatus linphone_core_start(LinphoneCore *lc);
*/
LINPHONE_PUBLIC void linphone_core_stop (LinphoneCore *core);
/**
* Stop asynchronously a #LinphoneCore object after it has been instantiated and started.
* State changes to Shutdown then linphone_core_iterate() must be called to allow the Core to end asynchronous tasks (terminate call, etc.).
* When all tasks are finished, State will change to Off.
* Must be called only if #LinphoneGlobalState is On.
* When #LinphoneGlobalState is Off #LinphoneCore can be started again using linphone_core_start().
* @ingroup initializing
* @param[in] core The #LinphoneCore object to be stopped
*/
LINPHONE_PUBLIC void linphone_core_stop_async (LinphoneCore *core);
/**
* Increment the reference counter of a #LinphoneCore object.
* @param lc The #LinphoneCore which the ref counter is to be incremented.
......
......@@ -51,6 +51,9 @@ public:
void registerListener (CoreListener *listener);
void unregisterListener (CoreListener *listener);
void uninit ();
void shutdown();
void stop();
bool asyncStopDone();
void notifyGlobalStateChanged (LinphoneGlobalState state);
void notifyNetworkReachable (bool sipNetworkReachable, bool mediaNetworkReachable);
......
......@@ -108,6 +108,53 @@ void CorePrivate::unregisterListener (CoreListener *listener) {
listeners.remove(listener);
}
bool CorePrivate::asyncStopDone() {
L_Q();
if (!calls.empty()) {
calls.front()->terminate();
return false;
}
bctbx_list_t *elem = NULL;
for (elem = q->getCCore()->friends_lists; elem != NULL; elem = bctbx_list_next(elem)) {
LinphoneFriendList *list = (LinphoneFriendList *) elem->data;
linphone_friend_list_enable_subscriptions(list,FALSE);
if (list->event) {
return false;
}
}
return true;
}
void CorePrivate::shutdown() {
if(!calls.empty()) {
calls.front()->terminate();
}
}
void CorePrivate::stop() {
L_Q();
chatRoomsById.clear();
noCreatedClientGroupChatRooms.clear();
listeners.clear();
if (q->limeX3dhEnabled()) {
q->enableLimeX3dh(false);
}
#ifdef HAVE_ADVANCED_IM
remoteListEventHandler = nullptr;
localListEventHandler = nullptr;
#endif
AddressPrivate::clearSipAddressesCache();
if (mainDb != nullptr) {
mainDb->disconnect();
}
}
void CorePrivate::uninit () {
L_Q();
while (!calls.empty()) {
......
......@@ -5095,6 +5095,25 @@ end:
linphone_core_manager_destroy(marie);
}
static void async_core_stop_after_call(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc");
BC_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000));
BC_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk, 1, 2000));
BC_ASSERT_TRUE(call(marie,pauline));
linphone_core_stop_async(marie->lc);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneGlobalShutdown, 1, int, "%d");
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneGlobalOff, 1));
BC_ASSERT_TRUE(wait_for(pauline->lc, NULL, &pauline->stat.number_of_LinphoneCallEnd, 1));
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallEnd, 1, int, "%d");
linphone_core_manager_destroy_after_stop_async(marie);
linphone_core_manager_destroy(pauline);
}
test_t call_tests[] = {
TEST_NO_TAG("Early declined call", early_declined_call),
TEST_NO_TAG("Call declined", call_declined),
......@@ -5198,6 +5217,7 @@ test_t call_tests[] = {
TEST_NO_TAG("Call declined, other ringing device receive CANCEL with reason", cancel_other_device_after_decline),
TEST_NO_TAG("Simple call with GRUU", simple_call_with_gruu),
TEST_NO_TAG("Simple call with GRUU only one device ring", simple_call_with_gruu_only_one_device_ring),
TEST_ONE_TAG("Async core stop", async_core_stop_after_call, "LeaksMemory")
};
test_suite_t call_test_suite = {"Single Call", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
......
......@@ -374,11 +374,13 @@ LinphoneCoreManager* linphone_core_manager_new3(const char* rc_file, bool_t chec
LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, bool_t check_for_proxies);
LinphoneCoreManager* linphone_core_manager_new(const char* rc_file);
void linphone_core_manager_stop(LinphoneCoreManager *mgr);
void linphone_core_manager_uninit_after_stop_async(LinphoneCoreManager *mgr);
void linphone_core_manager_reinit(LinphoneCoreManager *mgr);
void linphone_core_manager_restart(LinphoneCoreManager *mgr, bool_t check_for_proxies);
void linphone_core_manager_uninit(LinphoneCoreManager *mgr);
void linphone_core_manager_wait_for_stun_resolution(LinphoneCoreManager *mgr);
void linphone_core_manager_destroy(LinphoneCoreManager* mgr);
void linphone_core_manager_destroy_after_stop_async(LinphoneCoreManager* mgr);
void linphone_core_manager_delete_chat_room (LinphoneCoreManager *mgr, LinphoneChatRoom *cr, bctbx_list_t *coresList);
bctbx_list_t * init_core_for_conference(bctbx_list_t *coreManagerList);
void start_core_for_conference(bctbx_list_t *coreManagerList);
......
......@@ -575,6 +575,22 @@ void linphone_core_manager_stop(LinphoneCoreManager *mgr){
}
}
void linphone_core_manager_uninit_after_stop_async(LinphoneCoreManager *mgr) {
if (mgr->lc) {
const char *record_file = linphone_core_get_record_file(mgr->lc);
if (!liblinphone_tester_keep_record_files && record_file && ortp_file_exist(record_file)==0) {
if ((bc_get_number_of_failures() - mgr->number_of_bcunit_error_at_creation)>0) {
ms_error("Test has failed, keeping recorded file [%s]", record_file);
}
else {
unlink(record_file);
}
}
linphone_core_unref(mgr->lc);
mgr->lc = NULL;
}
}
void linphone_core_manager_reinit(LinphoneCoreManager *mgr) {
char *uuid = NULL;
if (mgr->lc) {
......@@ -646,6 +662,17 @@ void linphone_core_manager_destroy(LinphoneCoreManager* mgr) {
ms_free(mgr);
}
void linphone_core_manager_destroy_after_stop_async(LinphoneCoreManager* mgr) {
if (mgr->lc && !linphone_core_is_network_reachable(mgr->lc)) {
int previousNbRegistrationOk = mgr->stat.number_of_LinphoneRegistrationOk;
linphone_core_set_network_reachable(mgr->lc, TRUE);
wait_for_until(mgr->lc, NULL, &mgr->stat.number_of_LinphoneRegistrationOk, previousNbRegistrationOk + 1, 2000);
}
linphone_core_manager_uninit_after_stop_async(mgr);
linphone_core_manager_uninit(mgr);
ms_free(mgr);
}
void linphone_core_manager_delete_chat_room (LinphoneCoreManager *mgr, LinphoneChatRoom *cr, bctbx_list_t *coresList) {
stats mgrStats = mgr->stat;
if (cr) {
......
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