Commit 71f0c480 authored by Sylvain Berfini's avatar Sylvain Berfini 🎩
Browse files

Started init/start/uninit process refactor to add a stop() method to be able...

Started init/start/uninit process refactor to add a stop() method to be able to destroy a Core in a more deterministic way than in the destructor
parent a3bc9e44
......@@ -870,6 +870,7 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) {
if (!friendList) {
friendList = linphone_core_create_friend_list(lc);
linphone_core_add_friend_list(lc, friendList);
linphone_friend_list_unref(friendList);
}
if (linphone_friend_list_add_friend(friendList, lf) != LinphoneFriendListOK) return;
if (bctbx_list_find(lc->subscribers, lf)) {
......
......@@ -2032,6 +2032,9 @@ static void linphone_core_free_payload_types(LinphoneCore *lc){
bctbx_list_free_with_data(lc->default_audio_codecs, (void (*)(void*))payload_type_destroy);
bctbx_list_free_with_data(lc->default_video_codecs, (void (*)(void*))payload_type_destroy);
bctbx_list_free_with_data(lc->default_text_codecs, (void (*)(void*))payload_type_destroy);
lc->default_audio_codecs = NULL;
lc->default_video_codecs = NULL;
lc->default_text_codecs = NULL;
}
void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message){
......@@ -2356,12 +2359,23 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
lc->sal->setCallbacks(&linphone_sal_callbacks);
#ifdef __ANDROID__
if (system_context)
lc->platform_helper = LinphonePrivate::createAndroidPlatformHelpers(lc->cppPtr, system_context);
if (system_context) {
JNIEnv *env = ms_get_jni_env();
if (lc->system_context) {
env->DeleteGlobalRef((jobject)lc->system_context);
}
lc->system_context = (jobject)env->NewGlobalRef((jobject)system_context);
}
if (lc->system_context) {
lc->platform_helper = LinphonePrivate::createAndroidPlatformHelpers(lc->cppPtr, lc->system_context);
}
else
ms_fatal("You must provide the Android's app context when creating the core!");
#elif TARGET_OS_IPHONE
lc->platform_helper = LinphonePrivate::createIosPlatformHelpers(lc->cppPtr, system_context);
if (system_context) {
lc->system_context = system_context;
}
lc->platform_helper = LinphonePrivate::createIosPlatformHelpers(lc->cppPtr, lc->system_context);
#endif
if (lc->platform_helper == NULL)
lc->platform_helper = new LinphonePrivate::GenericPlatformHelpers(lc->cppPtr);
......@@ -2382,7 +2396,9 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
linphone_core_cbs_set_subscribe_received(internal_cbs, linphone_core_internal_subscribe_received);
linphone_core_cbs_set_subscription_state_changed(internal_cbs, linphone_core_internal_subscription_state_changed);
linphone_core_cbs_set_publish_state_changed(internal_cbs, linphone_core_internal_publish_state_changed);
_linphone_core_add_callbacks(lc, internal_cbs, TRUE);
if (lc->vtable_refs == NULL) { // Do not add a new listener upon restart
_linphone_core_add_callbacks(lc, internal_cbs, TRUE);
}
belle_sip_object_unref(internal_cbs);
if (cbs != NULL) {
......@@ -2443,13 +2459,31 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
linphone_presence_model_set_basic_status(lc->presence_model, LinphonePresenceBasicStatusOpen);
_linphone_core_read_config(lc);
linphone_core_set_state(lc, LinphoneGlobalReady, "Ready");
if (automatically_start) {
linphone_core_start(lc);
}
}
void linphone_core_start (LinphoneCore *lc) {
linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up");
if (lc->state == LinphoneGlobalOn) {
bctbx_warning("Core is already started, skipping...");
return;
} else if (lc->state == LinphoneGlobalShutdown) {
bctbx_error("Can't start a Core that is stopping, wait for Off state");
return;
} else if (lc->state == LinphoneGlobalOff) {
bctbx_warning("Core was stopped, before starting it again we need to init it");
linphone_core_init(lc, NULL, lc->config, lc->data, NULL, FALSE);
// Decrement refs to avoid leaking
lp_config_unref(lc->config);
linphone_core_deactivate_log_serialization_if_needed();
bctbx_uninit_logger();
}
linphone_core_set_state(lc, LinphoneGlobalStartup, "Starting up");
L_GET_PRIVATE_FROM_C_OBJECT(lc)->init();
......@@ -6056,6 +6090,7 @@ void net_config_uninit(LinphoneCore *lc)
linphone_nat_policy_unref(lc->nat_policy);
lc->nat_policy = NULL;
}
lc->net_conf = {0};
}
void sip_config_uninit(LinphoneCore *lc)
......@@ -6108,6 +6143,7 @@ void sip_config_uninit(LinphoneCore *lc)
if (lc->vcard_context) {
linphone_vcard_context_destroy(lc->vcard_context);
lc->vcard_context = NULL;
}
lc->sal->resetTransports();
......@@ -6135,14 +6171,22 @@ void sip_config_uninit(LinphoneCore *lc)
lc->sal=NULL;
if (lc->sip_conf.guessed_contact)
if (lc->sip_conf.guessed_contact) {
ms_free(lc->sip_conf.guessed_contact);
if (config->contact)
lc->sip_conf.guessed_contact = NULL;
}
if (config->contact) {
ms_free(config->contact);
if (lc->default_rls_addr)
config->contact = NULL;
}
if (lc->default_rls_addr) {
linphone_address_unref(lc->default_rls_addr);
lc->default_rls_addr = NULL;
}
linphone_im_notif_policy_unref(lc->im_notif_policy);
lc->im_notif_policy = NULL;
lc->sip_conf = {0};
}
void rtp_config_uninit(LinphoneCore *lc)
......@@ -6171,6 +6215,7 @@ void rtp_config_uninit(LinphoneCore *lc)
ms_free(lc->rtp_conf.audio_multicast_addr);
ms_free(lc->rtp_conf.video_multicast_addr);
ms_free(config->srtp_suites);
lc->rtp_conf = {0};
}
static void sound_config_uninit(LinphoneCore *lc)
......@@ -6185,6 +6230,7 @@ static void sound_config_uninit(LinphoneCore *lc)
if (config->local_ring) ms_free(config->local_ring);
if (config->remote_ring) ms_free(config->remote_ring);
lc->tones=bctbx_list_free_with_data(lc->tones, (void (*)(void*))linphone_tone_description_destroy);
lc->sound_conf = {0};
}
static void video_config_uninit(LinphoneCore *lc)
......@@ -6197,6 +6243,7 @@ static void video_config_uninit(LinphoneCore *lc)
ms_free((void *)lc->video_conf.cams);
if (lc->video_conf.vdef) linphone_video_definition_unref(lc->video_conf.vdef);
if (lc->video_conf.preview_vdef) linphone_video_definition_unref(lc->video_conf.preview_vdef);
lc->video_conf = {0};
}
void _linphone_core_codec_config_write(LinphoneCore *lc){
......@@ -6240,6 +6287,7 @@ static void codecs_config_uninit(LinphoneCore *lc)
bctbx_list_free(lc->codecs_conf.audio_codecs);
bctbx_list_free(lc->codecs_conf.video_codecs);
bctbx_list_free(lc->codecs_conf.text_codecs);
lc->codecs_conf = {0};
}
void friends_config_uninit(LinphoneCore* lc)
......@@ -6284,16 +6332,20 @@ LinphoneXmlRpcSession * linphone_core_create_xml_rpc_session(LinphoneCore *lc, c
return linphone_xml_rpc_session_new(lc, url);
}
void _linphone_core_uninit(LinphoneCore *lc)
{
static void _linphone_core_stop(LinphoneCore *lc, bool_t notify_global_state) {
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;
//no longer call LinphoneGlobalShutdown because it cause LinphoneCore revival in case of managed languages like Java
lc->state = LinphoneGlobalShutdown;
if (notify_global_state) {
// Now that we have a proper uninit method called by application we can use again the callbacks
linphone_core_set_state(lc, LinphoneGlobalShutdown, "Shutdown");
} else {
lc->state = LinphoneGlobalShutdown;
}
L_GET_PRIVATE_FROM_C_OBJECT(lc)->uninit();
for (elem = lc->friends_lists; elem != NULL; elem = bctbx_list_next(elem)) {
......@@ -6334,60 +6386,99 @@ void _linphone_core_uninit(LinphoneCore *lc)
sip_setup_unregister_all();
if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config);
lp_config_destroy(lc->config);
lc->config = NULL; /* Mark the config as NULL to block further calls */
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);
//no longer call LinphoneGlobalOff because it cause LinphoneCore revival in case of managed languages like Java
lc->state = LinphoneGlobalOff;
linphone_core_deactivate_log_serialization_if_needed();
bctbx_list_free_with_data(lc->vtable_refs,(void (*)(void *))v_table_reference_destroy);
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;
if (notify_global_state) {
// Now that we have a proper uninit method called by application we can use again the callbacks
linphone_core_set_state(lc, LinphoneGlobalOff, "Off");
} else {
lc->state = LinphoneGlobalOff;
}
}
void linphone_core_stop(LinphoneCore *lc) {
_linphone_core_stop(lc, TRUE);
}
void _linphone_core_uninit(LinphoneCore *lc)
{
if (lc->state != LinphoneGlobalOff) {
_linphone_core_stop(lc, FALSE);
}
lp_config_unref(lc->config);
lc->config = NULL;
#ifdef __ANDROID__
if (lc->system_context) {
JNIEnv *env = ms_get_jni_env();
env->DeleteGlobalRef((jobject)lc->system_context);
}
#endif
lc->system_context = NULL;
linphone_core_deactivate_log_serialization_if_needed();
bctbx_list_free_with_data(lc->vtable_refs,(void (*)(void *))v_table_reference_destroy);
bctbx_uninit_logger();
}
......@@ -6582,13 +6673,10 @@ const char* linphone_configuring_state_to_string(LinphoneConfiguringState cs){
switch(cs){
case LinphoneConfiguringSuccessful:
return "LinphoneConfiguringSuccessful";
break;
case LinphoneConfiguringFailed:
return "LinphoneConfiguringFailed";
break;
case LinphoneConfiguringSkipped:
return "LinphoneConfiguringSkipped";
break;
}
return NULL;
}
......@@ -6597,17 +6685,16 @@ const char *linphone_global_state_to_string(LinphoneGlobalState gs){
switch(gs){
case LinphoneGlobalOff:
return "LinphoneGlobalOff";
break;
case LinphoneGlobalOn:
return "LinphoneGlobalOn";
break;
case LinphoneGlobalStartup:
return "LinphoneGlobalStartup";
break;
case LinphoneGlobalShutdown:
return "LinphoneGlobalShutdown";
case LinphoneGlobalConfiguring:
return "LinphoneGlobalConfiguring";
case LinphoneGlobalReady:
return "LinphoneGlobalReady";
break;
}
return NULL;
......
......@@ -841,7 +841,7 @@ namespace LinphonePrivate {
bctbx_list_t *chat_rooms; \
bctbx_list_t *callsCache; \
bool_t dns_set_by_app; \
int auto_download_incoming_files_max_size; \
int auto_download_incoming_files_max_size;
#define LINPHONE_CORE_STRUCT_FIELDS \
LINPHONE_CORE_STRUCT_BASE_FIELDS \
......@@ -849,6 +849,7 @@ namespace LinphonePrivate {
bctbx_mutex_t zrtp_cache_db_mutex; \
sqlite3 *logs_db; \
sqlite3 *friends_db; \
bool_t debug_storage;
bool_t debug_storage; \
void *system_context;
#endif /* _PRIVATE_STRUCTS_H_ */
......@@ -1004,12 +1004,23 @@ LINPHONE_DEPRECATED LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const Linpho
LINPHONE_DEPRECATED LINPHONE_PUBLIC LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, LpConfig *config, void *userdata);
/**
* Start a #LinphoneCore object after it has been instantiated.
* Start a #LinphoneCore object after it has been instantiated and not automatically started.
* Also re-initialize a #LinphoneCore object that has been stopped using linphone_core_stop().
* Must be called only if #LinphoneGlobalState is either Ready of Off. State will changed to Startup, Configuring and then On.
* @ingroup initializing
* @param[in] core The #LinphoneCore object to be started
*/
LINPHONE_PUBLIC void linphone_core_start (LinphoneCore *core);
/**
* Stop a #LinphoneCore object after it has been instantiated and started.
* If stopped, it can be started again using linphone_core_start().
* Must be called only if #LinphoneGlobalState is either On. State will changed to Shutdown and then Off.
* @ingroup initializing
* @param[in] core The #LinphoneCore object to be stopped
*/
LINPHONE_PUBLIC void linphone_core_stop (LinphoneCore *core);
/**
* Increment the reference counter of a #LinphoneCore object.
* @param lc The #LinphoneCore which the ref counter is to be incremented.
......
......@@ -109,6 +109,8 @@ LINPHONE_DEPRECATED LINPHONE_PUBLIC LinphoneCore *linphone_factory_create_core_2
* The #LinphoneCore object is the primary handle for doing all phone actions. It should be unique within your
* application.
* The #LinphoneCore object is not started automatically, you need to call linphone_core_start() to that effect.
* The returned #LinphoneCore will be in #LinphoneGlobalState Ready.
* Core ressources can be released using linphone_core_stop() which is strongly encouraged on garbage collected languages.
* @param[in] factory The #LinphoneFactory singleton.
* @param[in] config_path A path to a config file. If it does not exists it will be created. The config file is used to
* store all settings, proxies... so that all these settings become persistent over the life of the #LinphoneCore object.
......@@ -175,6 +177,8 @@ LINPHONE_DEPRECATED LINPHONE_PUBLIC LinphoneCore *linphone_factory_create_core_w
* The #LinphoneCore object is the primary handle for doing all phone actions. It should be unique within your
* application.
* The #LinphoneCore object is not started automatically, you need to call linphone_core_start() to that effect.
* The returned #LinphoneCore will be in #LinphoneGlobalState Ready.
* Core ressources can be released using linphone_core_stop() which is strongly encouraged on garbage collected languages.
* @param[in] factory The #LinphoneFactory singleton.
* @param[in] config A #LinphoneConfig object holding the configuration for the #LinphoneCore to be instantiated.
* @param[in] system_context A pointer to a system object required by the core to operate. Currently it is required to
......
......@@ -505,11 +505,18 @@ typedef enum _LinphoneFriendListSyncStatus {
* @ingroup initializing
**/
typedef enum _LinphoneGlobalState {
/** State in which we're in after linphone_core_stop(). Do not call any method while in this state except for linphone_core_start() */
LinphoneGlobalOff,
/** Transient state for when we call linphone_core_start() */
LinphoneGlobalStartup,
/** Indicates #LinphoneCore has been started and is up and running */
LinphoneGlobalOn,
/** Transient state for when we call linphone_core_stop() */
LinphoneGlobalShutdown,
LinphoneGlobalConfiguring
/** Transient state between Startup and On if there is a remote provisionning URI configured */
LinphoneGlobalConfiguring,
/** #LinphoneCore state after being created by linphone_factory_create_core(), generally followed by a call to linphone_core_start() */
LinphoneGlobalReady
} LinphoneGlobalState;
/**
......
......@@ -42,6 +42,7 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(
)
static void _linphone_core_constructor (LinphoneCore *lc) {
lc->state = LinphoneGlobalOff;
}
static void _linphone_core_destructor (LinphoneCore *lc) {
......
......@@ -98,6 +98,10 @@ void CorePrivate::uninit () {
chatRooms.clear();
chatRoomsById.clear();
noCreatedClientGroupChatRooms.clear();
listeners.clear();
if (q->limeX3dhEnabled()) {
q->enableLimeX3dh(false);
}
remoteListEventHandler = nullptr;
localListEventHandler = nullptr;
......
......@@ -85,6 +85,51 @@ static void core_init_test(void) {
/* until we have good certificates on our test server... */
linphone_core_verify_server_certificates(lc,FALSE);
if (BC_ASSERT_PTR_NOT_NULL(lc)) {
BC_ASSERT_EQUAL(linphone_core_get_global_state(lc), LinphoneGlobalOn, int, "%i");
linphone_core_unref(lc);
}
}
static void core_init_stop_test(void) {
LinphoneCore* lc;
lc = linphone_factory_create_core_2(linphone_factory_get(),NULL,NULL,liblinphone_tester_get_empty_rc(), NULL, system_context);
/* until we have good certificates on our test server... */
linphone_core_verify_server_certificates(lc,FALSE);
if (BC_ASSERT_PTR_NOT_NULL(lc)) {
BC_ASSERT_EQUAL(linphone_core_get_global_state(lc), LinphoneGlobalOn, int, "%i");
linphone_core_stop(lc);
BC_ASSERT_EQUAL(linphone_core_get_global_state(lc), LinphoneGlobalOff, int, "%i");
}
if (BC_ASSERT_PTR_NOT_NULL(lc)) {
linphone_core_unref(lc);
}
}
static void core_init_stop_start_test(void) {
LinphoneCore* lc;
lc = linphone_factory_create_core_2(linphone_factory_get(),NULL,NULL,liblinphone_tester_get_empty_rc(), NULL, system_context);
/* until we have good certificates on our test server... */
linphone_core_verify_server_certificates(lc, FALSE);
const char *uuid = lp_config_get_string(linphone_core_get_config(lc), "misc", "uuid", NULL);
BC_ASSERT_STRING_NOT_EQUAL(uuid, "");
if (BC_ASSERT_PTR_NOT_NULL(lc)) {
BC_ASSERT_EQUAL(linphone_core_get_global_state(lc), LinphoneGlobalOn, int, "%i");
linphone_core_stop(lc);
BC_ASSERT_EQUAL(linphone_core_get_global_state(lc), LinphoneGlobalOff, int, "%i");
}
if (BC_ASSERT_PTR_NOT_NULL(lc)) {
linphone_core_start(lc);
BC_ASSERT_EQUAL(linphone_core_get_global_state(lc), LinphoneGlobalOn, int, "%i");
}
const char *uuid2 = lp_config_get_string(linphone_core_get_config(lc), "misc", "uuid", NULL);
BC_ASSERT_STRING_NOT_EQUAL(uuid2, "");
BC_ASSERT_STRING_EQUAL(uuid, uuid2);
if (BC_ASSERT_PTR_NOT_NULL(lc)) {
linphone_core_unref(lc);
}
......@@ -1486,6 +1531,8 @@ test_t setup_tests[] = {
TEST_NO_TAG("Linphone proxy config address equal (internal api)", linphone_proxy_config_address_equal_test),
TEST_NO_TAG("Linphone proxy config server address change (internal api)", linphone_proxy_config_is_server_config_changed_test),
TEST_NO_TAG("Linphone core init/uninit", core_init_test),
TEST_NO_TAG("Linphone core init/stop/uninit", core_init_stop_test),
TEST_NO_TAG("Linphone core init/stop/start/uninit", core_init_stop_start_test),
TEST_NO_TAG("Linphone random transport port",core_sip_transport_test),
TEST_NO_TAG("Linphone interpret url", linphone_interpret_url_test),
TEST_NO_TAG("LPConfig from buffer", linphone_lpconfig_from_buffer),
......
......@@ -522,6 +522,7 @@ void linphone_core_manager_stop(LinphoneCoreManager *mgr){
unlink(record_file);
}
}
linphone_core_stop(mgr->lc);
linphone_core_unref(mgr->lc);
mgr->lc = NULL;
}
......@@ -543,7 +544,13 @@ void linphone_core_manager_reinit(LinphoneCoreManager *mgr) {
}
void linphone_core_manager_restart(LinphoneCoreManager *mgr, bool_t check_for_proxies) {
linphone_core_manager_reinit(mgr);
//linphone_core_manager_reinit(mgr);
if (mgr->lc) {
linphone_core_stop(mgr->lc);
} else {
linphone_core_manager_configure(mgr);
}
reset_counters(&mgr->stat);
linphone_core_manager_start(mgr, check_for_proxies);
}
......
......@@ -520,7 +520,7 @@ public class AndroidPlatformHelper {
mContext.unregisterReceiver(mNetworkReceiver);
}
} else {
if (mConnectivityManager != null) {
if (mNetworkManagerAbove21 != null && mConnectivityManager != null) {
Log.i("[Platform Helper] Unregistering network callbacks");
mNetworkManagerAbove21.unregisterNetworkCallbacks(mConnectivityManager);
}
......
......@@ -251,6 +251,12 @@ class JavaTranslator(object):
methodDict['classImplName'] = className + 'Impl'
methodDict['isLinphoneFactory'] = (className == 'Factory')
methodDict['jniPath'] = self.jni_path
methodDict['isLinphoneCore'] = (className == 'Core')
methodDict['isNotLinphoneCoreStart'] = (_method.name.to_c() != 'linphone_core_start')
hasCoreAccessor = class_.name.to_camel_case() in CORE_ACCESSOR_LIST
methodDict['hasCoreAccessor'] = hasCoreAccessor
if hasCoreAccessor:
methodDict['c_core_accessor'] = 'linphone_' + class_.name.to_snake_case() + '_get_core'
methodDict['return'] = _method.returnType.translate(self.langTranslator, jni=True, isReturn=True, namespace=namespace)
methodDict['hasListReturn'] = methodDict['return'] == 'jobjectArray'
......
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