diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 90aea4c4c..131d7656c 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -747,6 +747,7 @@ static void set_tls_properties(Sal *ctx){ belle_tls_crypto_config_set_verify_exceptions(crypto_config, verify_exceptions); if (ctx->root_ca != NULL) belle_tls_crypto_config_set_root_ca(crypto_config, ctx->root_ca); belle_sip_tls_listening_point_set_crypto_config(tlp, crypto_config); + belle_sip_object_unref(crypto_config); } } diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index c8689a848..6a8107d93 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -195,6 +195,18 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque static belle_sip_listener_callbacks_t op_subscribe_callbacks={ 0 }; +/*Invoke when sal_op_release is called by upper layer*/ +static void sal_op_release_cb(struct SalOpBase* op_base) { + SalOp *op =(SalOp*)op_base; + if(op->refresher) { + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + set_or_update_dialog(op,NULL); /*only if we have refresher. else dialog terminated event will remove association*/ + } + +} + void sal_op_subscribe_fill_cbs(SalOp*op) { if (op_subscribe_callbacks.process_io_error==NULL){ op_subscribe_callbacks.process_io_error=subscribe_process_io_error; @@ -206,6 +218,7 @@ void sal_op_subscribe_fill_cbs(SalOp*op) { } op->callbacks=&op_subscribe_callbacks; op->type=SalOpSubscribe; + op->base.release_cb=sal_op_release_cb; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 33d118e1d..b58be0f2b 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -35,6 +35,8 @@ void sal_op_release(SalOp *op){ if (op->state!=SalOpStateTerminating) op->state=SalOpStateTerminated; sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn't not mean freeing op. Make sure back pointer will not be used later*/ + if (op->base.release_cb) + op->base.release_cb(&op->base); if (op->refresher) { belle_sip_refresher_stop(op->refresher); } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index bfed1fadb..6e9f0e6d2 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -52,24 +52,13 @@ static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_e static void presence_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { SalOp* op= (SalOp*)ctx; - if (op->dialog) { - if (belle_sip_dialog_is_server(op->dialog)){ + if (op->dialog && belle_sip_dialog_is_server(op->dialog)) { ms_message("Incoming subscribtion from [%s] terminated",sal_op_get_from(op)); if (!op->op_released){ op->base.root->callbacks.subscribe_presence_closed(op, sal_op_get_from(op)); } set_or_update_dialog(op, NULL); - }else{ - if (belle_sip_dialog_terminated_event_is_expired(event)){ - ms_warning("Outgoing presence subscription expired."); - if (op->refresher){ - /*send a new SUBSCRIBE, that will attempt to establish a new dialog*/ - sal_subscribe_presence(op,NULL,NULL,-1); - } - } - } - - } + }/* else client dialog is managed by refresher*/ } static void presence_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase){ @@ -144,13 +133,6 @@ static void presence_response_event(void *op_base, const belle_sip_response_even } break; } - case BELLE_SIP_DIALOG_TERMINATED: - if (op->refresher) { - belle_sip_refresher_stop(op->refresher); - belle_sip_object_unref(op->refresher); - op->refresher=NULL; - } - break; default: { ms_error("presence op [%p] receive answer [%i] not implemented",op,code); } @@ -297,6 +279,17 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques static belle_sip_listener_callbacks_t op_presence_callbacks={0}; +/*Invoke when sal_op_release is called by upper layer*/ +static void sal_op_release_cb(struct SalOpBase* op_base) { + SalOp *op =(SalOp*)op_base; + if(op->refresher) { + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + set_or_update_dialog(op,NULL); /*only if we have refresher. else dialog terminated event will remove association*/ + } + +} void sal_op_presence_fill_cbs(SalOp*op) { if (op_presence_callbacks.process_request_event==NULL){ op_presence_callbacks.process_io_error=presence_process_io_error; @@ -308,6 +301,7 @@ void sal_op_presence_fill_cbs(SalOp*op) { } op->callbacks=&op_presence_callbacks; op->type=SalOpPresence; + op->base.release_cb=sal_op_release_cb; } @@ -380,6 +374,7 @@ int sal_notify_presence(SalOp *op, SalPresenceModel *presence){ int sal_notify_presence_close(SalOp *op){ belle_sip_request_t* notify=NULL; + int status; if (sal_op_check_dialog_state(op)) { return -1; } @@ -389,7 +384,9 @@ int sal_notify_presence_close(SalOp *op){ sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),NULL); /*FIXME, what about expires ??*/ belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); - return sal_op_send_request(op,notify); + status = sal_op_send_request(op,notify); + set_or_update_dialog(op,NULL); /*because we may be chalanged for the notify, so we must release dialog right now*/ + return status; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a927500c0..1e14854a9 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1135,6 +1135,7 @@ static void convert_presence_to_xml_requested(SalOp *op, SalPresenceModel *prese if(linphone_presence_model_get_presentity((LinphonePresenceModel*)presence) == NULL) { LinphoneAddress * presentity = linphone_address_new(contact); linphone_presence_model_set_presentity((LinphonePresenceModel*)presence, presentity); + linphone_address_unref(presentity); } *content = linphone_presence_model_to_xml((LinphonePresenceModel*)presence); } diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index 20216b05e..1ab02b5a5 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -599,7 +599,9 @@ LinphoneFriend * linphone_friend_list_find_friend_by_out_subscribe(const Linphon void linphone_friend_list_close_subscriptions(LinphoneFriendList *list) { /* FIXME we should wait until subscription to complete. */ - if (list->friends) + if (list->event) { + linphone_event_terminate(list->event); + } else if (list->friends) ms_list_for_each(list->friends, (void (*)(void *))linphone_friend_close_subscriptions); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5ae3a00f7..92668030f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6493,6 +6493,8 @@ LpConfig * linphone_core_create_lp_config(LinphoneCore *lc, const char *filename static void linphone_core_uninit(LinphoneCore *lc) { MSList *elem = NULL; + int i=0; + bool_t wait_until_unsubscribe = FALSE; linphone_task_list_free(&lc->hooks); lc->video_conf.show_local = FALSE; @@ -6506,6 +6508,13 @@ static void linphone_core_uninit(LinphoneCore *lc) for (elem = lc->friends_lists; elem != NULL; elem = ms_list_next(elem)) { LinphoneFriendList *list = (LinphoneFriendList *)elem->data; linphone_friend_list_close_subscriptions(list); + if (list->event) + wait_until_unsubscribe = TRUE; + } + /*give a chance to unsubscribe, might be optimized*/ + for (i=0; wait_until_unsubscribe && i<20; i++) { + linphone_core_iterate(lc); + ms_usleep(50000); } lc->chatrooms = ms_list_free_with_data(lc->chatrooms, (MSIterateFunc)linphone_chat_room_release); diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 49e1263ba..5488a1358 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -121,7 +121,7 @@ typedef struct _LinphoneFriend LinphoneFriend; * @return a new empty #LinphoneFriend * @deprecated use #linphone_core_create_friend instead */ -LINPHONE_PUBLIC MS2_DEPRECATED LinphoneFriend * linphone_friend_new(void); /*fix me me replace MS2_DEPRECATED by LINPHONE_DEPRECATED*/ +LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneFriend * linphone_friend_new(void); /** * Contructor same as linphone_friend_new() + linphone_friend_set_address() @@ -129,7 +129,7 @@ LINPHONE_PUBLIC MS2_DEPRECATED LinphoneFriend * linphone_friend_new(void); /*fix * @return a new #LinphoneFriend with \link linphone_friend_get_address() address initialized \endlink * @deprecated use #linphone_core_create_friend_with_address instead */ -LINPHONE_PUBLIC MS2_DEPRECATED LinphoneFriend *linphone_friend_new_with_address(const char *addr); /*fix me me replace MS2_DEPRECATED by LINPHONE_DEPRECATED*/ +LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneFriend *linphone_friend_new_with_address(const char *addr); /** * Contructor same as linphone_friend_new() + linphone_friend_set_address() diff --git a/include/sal/sal.h b/include/sal/sal.h index 666af4fad..c5b04b159 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -330,7 +330,9 @@ bool_t sal_media_description_has_srtp(const SalMediaDescription *md); bool_t sal_media_description_has_dtls(const SalMediaDescription *md); int sal_media_description_get_nb_active_streams(const SalMediaDescription *md); - +struct SalOpBase; +typedef void (*SalOpReleaseCb)(struct SalOpBase *op); + /*this structure must be at the first byte of the SalOp structure defined by implementors*/ typedef struct SalOpBase{ Sal *root; @@ -355,6 +357,7 @@ typedef struct SalOpBase{ SalCustomHeader *sent_custom_headers; SalCustomHeader *recv_custom_headers; char* entity_tag; /*as defined by rfc3903 (I.E publih)*/ + SalOpReleaseCb release_cb; } SalOpBase; diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index d57978926..7828aacdf 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -360,10 +360,10 @@ static void publish_without_expires(void){ test_t event_tests[] = { TEST_ONE_TAG("Subscribe declined", subscribe_test_declined, "LeaksMemory"), - TEST_ONE_TAG("Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber, "LeaksMemory"), + TEST_ONE_TAG("Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber, "presence"), TEST_ONE_TAG("Subscribe with custom headers", subscribe_test_with_custom_header, "LeaksMemory"), - TEST_ONE_TAG("Subscribe refreshed", subscribe_test_refreshed, "LeaksMemory"), - TEST_ONE_TAG("Subscribe manually refreshed", subscribe_test_manually_refreshed, "LeaksMemory"), + TEST_ONE_TAG("Subscribe refreshed", subscribe_test_refreshed, "presence"), + TEST_ONE_TAG("Subscribe manually refreshed", subscribe_test_manually_refreshed, "presence"), TEST_ONE_TAG("Subscribe terminated by notifier", subscribe_test_terminated_by_notifier, "LeaksMemory"), TEST_ONE_TAG("Publish", publish_test, "LeaksMemory"), TEST_ONE_TAG("Publish without expires", publish_without_expires, "LeaksMemory"), diff --git a/tester/presence_tester.c b/tester/presence_tester.c index fae9aef60..c2aa82b5b 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -709,7 +709,6 @@ static void test_presence_list_base(bool_t enable_compression) { const char *marie_identity; const char *pauline_identity; MSList* lcs = NULL; - int dummy = 0; laure_identity = get_identity(laure); marie_identity = get_identity(marie); @@ -817,13 +816,23 @@ static void test_presence_list_base(bool_t enable_compression) { enable_publish(marie, FALSE); enable_publish(pauline, FALSE); - wait_for_list(lcs, &dummy, 1, 2000); /* Wait a little bit for the presence notifications. TODO: Wait for the correct number of PresenceReceived events. */ + + reset_counters(&pauline->stat); + reset_counters(&laure->stat); + reset_counters(&marie->stat); + + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphonePresenceActivityOffline, 1, 2000)); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(pauline->lc), marie_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); + + BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphonePresenceActivityOffline, 2, 2000)); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), pauline_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), marie_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); + + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphonePresenceActivityOffline, 1, 2000)); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(marie->lc), laure_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); @@ -1023,7 +1032,7 @@ static void simple_subscribe_with_friend_from_rc(void) { test_t presence_tests[] = { - TEST_ONE_TAG("Simple Subscribe", simple_subscribe,"LeaksMemory"), + TEST_ONE_TAG("Simple Subscribe", simple_subscribe,"presence"), TEST_ONE_TAG("Simple Subscribe with friend from rc", simple_subscribe_with_friend_from_rc,"LeaksMemory"), TEST_ONE_TAG("Simple Publish", simple_publish, "LeaksMemory"), TEST_ONE_TAG("Simple Publish with expires", publish_with_expires, "LeaksMemory"), @@ -1033,7 +1042,7 @@ test_t presence_tests[] = { TEST_NO_TAG("App managed presence failure", subscribe_failure_handle_by_app), TEST_NO_TAG("Presence SUBSCRIBE forked", subscribe_presence_forked), TEST_NO_TAG("Presence SUBSCRIBE expired", subscribe_presence_expired), - TEST_ONE_TAG("Subscriber no longer reachable using server",subscriber_no_longer_reachable, "LeaksMemory"), + TEST_ONE_TAG("Subscriber no longer reachable using server",subscriber_no_longer_reachable, "presence"), TEST_ONE_TAG("Subscribe with late publish", test_subscribe_notify_publish, "LeaksMemory"), TEST_ONE_TAG("Forked subscribe with late publish", test_forked_subscribe_notify_publish, "LeaksMemory"), TEST_ONE_TAG("Presence list", test_presence_list, "LeaksMemory"),