From b35df101ee162831573fd9b11515e34ed71638db Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 9 Mar 2018 17:42:22 +0100 Subject: [PATCH 01/32] Started multi routes but currently crashes... --- coreapi/linphonecore.c | 15 +++++++++----- coreapi/private_structs.h | 2 +- coreapi/proxy.c | 36 +++++++++++++++++++++------------ include/linphone/proxy_config.h | 8 ++++++++ 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2027b4101..56024b2c5 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3421,11 +3421,16 @@ LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall * system. */ static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneAddress *dest){ - bctbx_list_t *ret=NULL; - const char *local_route=linphone_proxy_config_get_route(proxy); - const LinphoneAddress *srv_route=linphone_proxy_config_get_service_route(proxy); - if (local_route){ - ret=bctbx_list_append(ret,sal_address_new(local_route)); + bctbx_list_t *ret = NULL; + const bctbx_list_t *proxy_routes = linphone_proxy_config_get_routes(proxy); + bctbx_list_t *proxy_routes_iterator = (bctbx_list_t *)proxy_routes; + const LinphoneAddress *srv_route = linphone_proxy_config_get_service_route(proxy); + while (proxy_routes_iterator) { + const char *local_route = (const char *)bctbx_list_get_data(proxy_routes_iterator); + if (local_route) { + ret = bctbx_list_append(ret, sal_address_new(local_route)); + } + proxy_routes_iterator = bctbx_list_next(proxy_routes_iterator); } if (srv_route){ ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_OBJECT(srv_route)->getInternalAddress())); diff --git a/coreapi/private_structs.h b/coreapi/private_structs.h index 13e0bcce5..3bcfc4d78 100644 --- a/coreapi/private_structs.h +++ b/coreapi/private_structs.h @@ -90,7 +90,7 @@ struct _LinphoneProxyConfig LinphoneAddress* identity_address; LinphoneAddress *contact_address; LinphoneAddress *contact_address_without_params; - char *reg_route; + bctbx_list_t *reg_routes; char *quality_reporting_collector; char *realm; char *contact_params; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 127d9bb93..dad8307e5 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -113,7 +113,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf const char *dial_prefix = lc ? lp_config_get_default_string(lc->config,"proxy","dial_prefix",NULL) : NULL; const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL; const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL; - const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL; + const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL; //TODO return list instead of string const char *realm = lc ? lp_config_get_default_string(lc->config, "proxy", "realm", NULL) : NULL; const char *quality_reporting_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "quality_reporting_collector", NULL) : NULL; const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL; @@ -130,7 +130,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf cfg->identity_address = identity ? linphone_address_new(identity) : NULL; cfg->reg_identity = cfg->identity_address ? linphone_address_as_string(cfg->identity_address) : NULL; cfg->reg_proxy = proxy ? ms_strdup(proxy) : NULL; - cfg->reg_route = route ? ms_strdup(route) : NULL; + cfg->reg_routes = route ? bctbx_list_append(cfg->reg_routes, ms_strdup(route)) : NULL; //TODO get list directly cfg->realm = realm ? ms_strdup(realm) : NULL; cfg->quality_reporting_enabled = lc ? !!lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0; cfg->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL; @@ -183,13 +183,18 @@ bool_t linphone_proxy_config_compute_publish_params_hash(LinphoneProxyConfig * c char hash[33]; char saved; unsigned long long previous_hash[2]; + bctbx_list_t *routes_iterator = cfg->reg_routes; previous_hash[0] = cfg->previous_publish_config_hash[0]; previous_hash[1] = cfg->previous_publish_config_hash[1]; source = ms_strcat_printf(source, "%i",cfg->privacy); source=append_linphone_address(cfg->identity_address, source); source=append_string(cfg->reg_proxy,source); - source=append_string(cfg->reg_route,source); + while (routes_iterator) { + const char *route = (const char *)bctbx_list_get_data(routes_iterator); + source=append_string(route,source); + routes_iterator = bctbx_list_next(routes_iterator); + } source=append_string(cfg->realm,source); source = ms_strcat_printf(source, "%i",cfg->publish_expires); source = ms_strcat_printf(source, "%i",cfg->publish); @@ -235,7 +240,7 @@ void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg){ if (cfg->reg_proxy!=NULL) ms_free(cfg->reg_proxy); if (cfg->reg_identity!=NULL) ms_free(cfg->reg_identity); if (cfg->identity_address!=NULL) linphone_address_unref(cfg->identity_address); - if (cfg->reg_route!=NULL) ms_free(cfg->reg_route); + if (cfg->reg_routes!=NULL) bctbx_list_free_with_data(cfg->reg_routes, ms_free); if (cfg->quality_reporting_collector!=NULL) ms_free(cfg->quality_reporting_collector); if (cfg->ssctx!=NULL) sip_setup_context_free(cfg->ssctx); if (cfg->realm!=NULL) ms_free(cfg->realm); @@ -348,9 +353,9 @@ const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){ LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route) { - if (cfg->reg_route!=NULL){ - ms_free(cfg->reg_route); - cfg->reg_route=NULL; + if (cfg->reg_routes!=NULL){ + bctbx_list_free_with_data(cfg->reg_routes, ms_free); + cfg->reg_routes=NULL; } if (route!=NULL && route[0] !='\0'){ SalAddress *addr; @@ -362,7 +367,7 @@ LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const c addr=sal_address_new(tmp); if (addr!=NULL){ sal_address_destroy(addr); - cfg->reg_route=tmp; + cfg->reg_routes = bctbx_list_append(cfg->reg_routes, tmp); return 0; }else{ ms_free(tmp); @@ -934,8 +939,13 @@ void _linphone_proxy_config_unpublish(LinphoneProxyConfig *obj) { } } -const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg){ - return cfg->reg_route; +const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg) { + if (cfg->reg_routes) return (const char *)bctbx_list_get_data(cfg->reg_routes); + return NULL; +} + +const bctbx_list_t* linphone_proxy_config_get_routes(const LinphoneProxyConfig *cfg) { + return cfg->reg_routes; } const LinphoneAddress *linphone_proxy_config_get_identity_address(const LinphoneProxyConfig *cfg){ @@ -1116,8 +1126,8 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC if (cfg->reg_proxy!=NULL){ lp_config_set_string(config,key,"reg_proxy",cfg->reg_proxy); } - if (cfg->reg_route!=NULL){ - lp_config_set_string(config,key,"reg_route",cfg->reg_route); + if (cfg->reg_routes != NULL) { + lp_config_set_string_list(config, key, "reg_route", cfg->reg_routes); } if (cfg->reg_identity!=NULL){ lp_config_set_string(config,key,"reg_identity",cfg->reg_identity); @@ -1187,7 +1197,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc CONFIGURE_STRING_VALUE(cfg,config,key,identity,"reg_identity") CONFIGURE_STRING_VALUE(cfg,config,key,server_addr,"reg_proxy") - CONFIGURE_STRING_VALUE(cfg,config,key,route,"reg_route") + cfg->reg_routes = linphone_config_get_string_list(config, key, "reg_route", NULL); CONFIGURE_STRING_VALUE(cfg,config,key,realm,"realm") diff --git a/include/linphone/proxy_config.h b/include/linphone/proxy_config.h index ec9368a34..13ef5d294 100644 --- a/include/linphone/proxy_config.h +++ b/include/linphone/proxy_config.h @@ -257,9 +257,17 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, c /** * @return the route set for this proxy configuration. + * @deprecated Use linphone_proxy_config_get_routes() instead. **/ LINPHONE_PUBLIC const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg); +/** + * Gets the list of the routes set for this proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @return \bctbx_list{const char *} the list of routes. + */ +LINPHONE_PUBLIC const bctbx_list_t* linphone_proxy_config_get_routes(const LinphoneProxyConfig *cfg); + /** * @return the SIP identity that belongs to this proxy configuration. **/ From 9b0c21cc233f85b79364acdd9762536f50b2be92 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 13 Mar 2018 15:03:20 +0100 Subject: [PATCH 02/32] Fixed multi routes crash --- coreapi/proxy.c | 37 ++++++++++++++++++++++++++++++--- include/linphone/proxy_config.h | 10 +++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index dad8307e5..067b95790 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -353,9 +353,9 @@ const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){ LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route) { - if (cfg->reg_routes!=NULL){ + if (cfg->reg_routes != NULL) { bctbx_list_free_with_data(cfg->reg_routes, ms_free); - cfg->reg_routes=NULL; + cfg->reg_routes = NULL; } if (route!=NULL && route[0] !='\0'){ SalAddress *addr; @@ -378,6 +378,37 @@ LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const c } } +LinphoneStatus linphone_proxy_config_set_routes(LinphoneProxyConfig *cfg, const bctbx_list_t *routes) { + if (cfg->reg_routes != NULL) { + bctbx_list_free_with_data(cfg->reg_routes, ms_free); + cfg->reg_routes = NULL; + } + bctbx_list_t *iterator = (bctbx_list_t *)routes; + while (iterator != NULL) { + char *route = (char *)bctbx_list_get_data(iterator); + if (route != NULL && route[0] !='\0') { + SalAddress *addr; + char *tmp; + /*try to prepend 'sip:' */ + if (strstr(route,"sip:") == NULL && strstr(route,"sips:") == NULL) { + tmp = ms_strdup_printf("sip:%s",route); + } else { + tmp = ms_strdup(route); + } + addr = sal_address_new(tmp); + if (addr != NULL) { + sal_address_destroy(addr); + cfg->reg_routes = bctbx_list_append(cfg->reg_routes, tmp); + } else { + ms_free(tmp); + return -1; + } + } + iterator = bctbx_list_next(iterator); + } + return 0; +} + bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *cfg){ if (cfg->reg_proxy==NULL) return FALSE; @@ -1197,7 +1228,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc CONFIGURE_STRING_VALUE(cfg,config,key,identity,"reg_identity") CONFIGURE_STRING_VALUE(cfg,config,key,server_addr,"reg_proxy") - cfg->reg_routes = linphone_config_get_string_list(config, key, "reg_route", NULL); + linphone_proxy_config_set_routes(cfg, linphone_config_get_string_list(config, key, "reg_route", NULL)); CONFIGURE_STRING_VALUE(cfg,config,key,realm,"realm") diff --git a/include/linphone/proxy_config.h b/include/linphone/proxy_config.h index 13ef5d294..edaa9d8c8 100644 --- a/include/linphone/proxy_config.h +++ b/include/linphone/proxy_config.h @@ -99,6 +99,16 @@ LINPHONE_PUBLIC LinphoneStatus linphone_proxy_config_set_identity_address(Linpho **/ LINPHONE_PUBLIC LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route); +/** + * Sets a list of SIP route. + * When a route is set, all outgoing calls will go to the route's destination if this proxy + * is the default one (see linphone_core_set_default_proxy() ). + * @param[in] cfg the #LinphoneProxyConfig + * @param[in] routes A \bctbx_list{const char *} of routes + * @return -1 if routes are invalid, 0 otherwise. +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_proxy_config_set_routes(LinphoneProxyConfig *cfg, const bctbx_list_t *routes); + /** * Sets the registration expiration time in seconds. **/ From c80f9f65c0f59bb9de4d9d037fdd0f3a088c922c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 13 Mar 2018 17:16:11 +0100 Subject: [PATCH 03/32] Added test for single route --- tester/proxy_config_tester.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tester/proxy_config_tester.c b/tester/proxy_config_tester.c index a2bf63066..a07c0217f 100644 --- a/tester/proxy_config_tester.c +++ b/tester/proxy_config_tester.c @@ -243,12 +243,36 @@ static void load_dynamic_proxy_config(void) { } +static void single_route(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneProxyConfig *marie_cfg = linphone_core_get_default_proxy_config(marie->lc); + BC_ASSERT_PTR_NOT_NULL(marie_cfg); + + const bctbx_list_t *routes = linphone_proxy_config_get_routes(marie_cfg); + BC_ASSERT_PTR_NOT_NULL(routes); + BC_ASSERT_EQUAL(bctbx_list_size(routes), 1, int, "%d"); + const char *route = (const char *)bctbx_list_get_data(routes); + BC_ASSERT_STRING_EQUAL(linphone_proxy_config_get_route(marie_cfg), "sip:sip.example.org;transport=tcp;lr"); + BC_ASSERT_STRING_EQUAL(route, "sip:sip.example.org;transport=tcp;lr"); + + linphone_proxy_config_set_route(marie_cfg, "sip.linphone.org"); + routes = linphone_proxy_config_get_routes(marie_cfg); + BC_ASSERT_PTR_NOT_NULL(routes); + BC_ASSERT_EQUAL(bctbx_list_size(routes), 1, int, "%d"); + route = (const char *)bctbx_list_get_data(routes); + BC_ASSERT_STRING_EQUAL(linphone_proxy_config_get_route(marie_cfg), "sip:sip.linphone.org"); + BC_ASSERT_STRING_EQUAL(route, "sip:sip.linphone.org"); + + linphone_core_manager_destroy(marie); +} + test_t proxy_config_tests[] = { TEST_NO_TAG("Phone normalization without proxy", phone_normalization_without_proxy), TEST_NO_TAG("Phone normalization with proxy", phone_normalization_with_proxy), TEST_NO_TAG("Phone normalization with dial escape plus", phone_normalization_with_dial_escape_plus), TEST_NO_TAG("SIP URI normalization", sip_uri_normalization), - TEST_NO_TAG("Load new default value for proxy config", load_dynamic_proxy_config) + TEST_NO_TAG("Load new default value for proxy config", load_dynamic_proxy_config), + TEST_NO_TAG("Single route", single_route) }; test_suite_t proxy_config_test_suite = {"Proxy config", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, From 09025ed3c894d2b3dd3f601dceccdbe32d1305e4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 14 Mar 2018 18:18:39 +0100 Subject: [PATCH 04/32] Add chat room callbacks to handle subscription to registration state of participants + add new group chat tester. --- coreapi/private_functions.h | 4 +- include/linphone/api/c-callbacks.h | 16 ++++- include/linphone/api/c-chat-room-cbs.h | 40 +++++++++-- include/linphone/api/c-chat-room.h | 11 ++- src/c-wrapper/api/c-chat-room-cbs.cpp | 28 ++++++-- src/c-wrapper/api/c-chat-room.cpp | 22 +++++- src/chat/chat-room/server-group-chat-room-p.h | 15 ++++- .../chat-room/server-group-chat-room-stub.cpp | 2 + tester/group_chat_tester.c | 67 ++++++++++++++++++- 9 files changed, 185 insertions(+), 20 deletions(-) diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h index 9ab4e447f..df615255b 100644 --- a/coreapi/private_functions.h +++ b/coreapi/private_functions.h @@ -291,8 +291,10 @@ void _linphone_chat_room_notify_undecryptable_message_received(LinphoneChatRoom void _linphone_chat_room_notify_chat_message_received(LinphoneChatRoom *cr, const LinphoneEventLog *event_log); void _linphone_chat_room_notify_chat_message_sent(LinphoneChatRoom *cr, const LinphoneEventLog *event_log); void _linphone_chat_room_notify_conference_address_generation(LinphoneChatRoom *cr); -void _linphone_chat_room_notify_participant_device_fetched(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr); +void _linphone_chat_room_notify_participant_device_fetch_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr); void _linphone_chat_room_notify_participants_capabilities_checked(LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsAddr); +void _linphone_chat_room_notify_participant_registration_subscription_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr); +void _linphone_chat_room_notify_participant_registration_unsubscription_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr); void _linphone_chat_room_notify_chat_message_should_be_stored(LinphoneChatRoom *cr, LinphoneChatMessage *msg); void _linphone_chat_room_clear_callbacks (LinphoneChatRoom *cr); diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index 228758a61..f8b796a00 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -239,7 +239,7 @@ typedef void (*LinphoneChatRoomCbsConferenceAddressGenerationCb) (LinphoneChatRo * @param[in] cr #LinphoneChatRoom object * @param[in] participantAddr #LinphoneAddress object */ -typedef void (*LinphoneChatRoomCbsParticipantDeviceFetchedCb) (LinphoneChatRoom *cr, const LinphoneAddress *participantAddr); +typedef void (*LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb) (LinphoneChatRoom *cr, const LinphoneAddress *participantAddr); /** * Callback used when a group chat room server is checking participants capabilities. @@ -249,6 +249,20 @@ typedef void (*LinphoneChatRoomCbsParticipantDeviceFetchedCb) (LinphoneChatRoom */ typedef void (*LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb) (LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsAddr); +/** + * Callback used when a group chat room server is subscribing to registration state of a participant. + * @param[in] cr #LinphoneChatRoom object + * @param[in] participantAddr #LinphoneAddress object + */ +typedef void (*LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb) (LinphoneChatRoom *cr, const LinphoneAddress *participantAddr); + +/** + * Callback used when a group chat room server is unsubscribing to registration state of a participant. + * @param[in] cr #LinphoneChatRoom object + * @param[in] participantAddr #LinphoneAddress object + */ +typedef void (*LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb) (LinphoneChatRoom *cr, const LinphoneAddress *participantAddr); + /** * Callback used to tell the core whether or not to store the incoming message in db or not using linphone_chat_message_set_to_be_stored(). * @param[in] cr #LinphoneChatRoom object diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h index 0e02b615c..6cbf7bd91 100644 --- a/include/linphone/api/c-chat-room-cbs.h +++ b/include/linphone/api/c-chat-room-cbs.h @@ -244,18 +244,18 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsConferenceAddressGenerationCb linphone_chat_r LINPHONE_PUBLIC void linphone_chat_room_cbs_set_conference_address_generation (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsConferenceAddressGenerationCb cb); /** - * Get the participant device getting callback. + * Get the participant device fetching callback. * @param[in] cbs LinphoneChatRoomCbs object - * @return The participant device getting callback + * @return The participant device fetching callback */ -LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantDeviceFetchedCb linphone_chat_room_cbs_get_participant_device_fetched (const LinphoneChatRoomCbs *cbs); +LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb linphone_chat_room_cbs_get_participant_device_fetch_requested (const LinphoneChatRoomCbs *cbs); /** - * Set the participant device getting callback. + * Set the participant device fetching callback. * @param[in] cbs LinphoneChatRoomCbs object - * @param[in] cb The participant device getting callback to be used + * @param[in] cb The participant device fetching callback to be used */ -LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_device_fetched (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceFetchedCb cb); +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_device_fetch_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb cb); /** * Get the participants capabilities callback. @@ -271,6 +271,34 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb linphone_ch */ LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participants_capabilities_checked (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb cb); +/** + * Get the participant registration subscription callback. + * @param[in] cbs LinphoneChatRoomCbs object + * @return The participant registration subscription callback + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb linphone_chat_room_cbs_get_participant_registration_subscription_requested (const LinphoneChatRoomCbs *cbs); + +/** + * Set the participant registration subscription callback. + * @param[in] cbs LinphoneChatRoomCbs object + * @param[in] cb The participant registration subscription callback to be used + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_registration_subscription_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb cb); + +/** + * Get the participant registration unsubscription callback. + * @param[in] cbs LinphoneChatRoomCbs object + * @return The participant registration unsubscription callback + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb linphone_chat_room_cbs_get_participant_registration_unsubscription_requested (const LinphoneChatRoomCbs *cbs); + +/** + * Set the participant registration unsubscription callback. + * @param[in] cbs LinphoneChatRoomCbs object + * @param[in] cb The participant registration unsubscription callback to be used + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_registration_unsubscription_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb cb); + /** * Get the message should be stored callback. * @param[in] cbs LinphoneChatRoomCbs object diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 0cd0761db..63aa290cb 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -454,13 +454,22 @@ LINPHONE_PUBLIC void linphone_chat_room_set_conference_address (LinphoneChatRoom /** * Set the participant device. This function needs to be called from the - * LinphoneChatRoomCbsParticipantDeviceFetchedCb callback and only there. + * LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb callback and only there. * @param[in] cr A LinphoneChatRoom object * @param[in] partAddr The participant address * @param[in] partDevices \bctbx_list{LinphoneAddress} list of the participant devices to be used by the group chat room */ LINPHONE_PUBLIC void linphone_chat_room_set_participant_devices (LinphoneChatRoom *cr, const LinphoneAddress *partAddr, const bctbx_list_t *partDevices); +/** + * Add a participant device. + * This is to used if a new device registers itself after the chat room creation. + * @param[in] cr A #LinphoneChatRoom object + * @param[in] participantAddress The address of the participant for which a new device is to be added + * @param[in] deviceAddress The address of the new device to be added + */ +LINPHONE_PUBLIC void linphone_chat_room_add_participant_device (LinphoneChatRoom *cr, const LinphoneAddress *participantAddress, const LinphoneAddress *deviceAddress); + /** * Set the participant device. This function needs to be called from the * LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb callback and only there. diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index 518c5b8bd..1d3d4d8d6 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -39,8 +39,10 @@ struct _LinphoneChatRoomCbs { LinphoneChatRoomCbsChatMessageReceivedCb chatMessageReceivedCb; LinphoneChatRoomCbsChatMessageSentCb chatMessageSentCb; LinphoneChatRoomCbsConferenceAddressGenerationCb conferenceAddressGenerationCb; - LinphoneChatRoomCbsParticipantDeviceFetchedCb participantDeviceFetchedCb; + LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb participantDeviceFetchRequestedCb; LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb participantsCapabilitiesChecked; + LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb participantRegistrationSubscriptionRequestedCb; + LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb participantRegistrationUnsubscriptionRequestedCb; LinphoneChatRoomCbsShouldChatMessageBeStoredCb shouldMessageBeStoredCb; }; @@ -182,12 +184,12 @@ void linphone_chat_room_cbs_set_conference_address_generation (LinphoneChatRoomC cbs->conferenceAddressGenerationCb = cb; } -LinphoneChatRoomCbsParticipantDeviceFetchedCb linphone_chat_room_cbs_get_participant_device_fetched (const LinphoneChatRoomCbs *cbs) { - return cbs->participantDeviceFetchedCb; +LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb linphone_chat_room_cbs_get_participant_device_fetch_requested (const LinphoneChatRoomCbs *cbs) { + return cbs->participantDeviceFetchRequestedCb; } -void linphone_chat_room_cbs_set_participant_device_fetched (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceFetchedCb cb) { - cbs->participantDeviceFetchedCb = cb; +void linphone_chat_room_cbs_set_participant_device_fetch_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb cb) { + cbs->participantDeviceFetchRequestedCb = cb; } LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb linphone_chat_room_cbs_get_participants_capabilities_checked (const LinphoneChatRoomCbs *cbs) { @@ -198,6 +200,22 @@ void linphone_chat_room_cbs_set_participants_capabilities_checked (LinphoneChatR cbs->participantsCapabilitiesChecked = cb; } +LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb linphone_chat_room_cbs_get_participant_registration_subscription_requested (const LinphoneChatRoomCbs *cbs) { + return cbs->participantRegistrationSubscriptionRequestedCb; +} + +void linphone_chat_room_cbs_set_participant_registration_subscription_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb cb) { + cbs->participantRegistrationSubscriptionRequestedCb = cb; +} + +LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb linphone_chat_room_cbs_get_participant_registration_unsubscription_requested (const LinphoneChatRoomCbs *cbs) { + return cbs->participantRegistrationUnsubscriptionRequestedCb; +} + +void linphone_chat_room_cbs_set_participant_registration_unsubscription_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb cb) { + cbs->participantRegistrationUnsubscriptionRequestedCb = cb; +} + LinphoneChatRoomCbsShouldChatMessageBeStoredCb linphone_chat_room_cbs_get_chat_message_should_be_stored( LinphoneChatRoomCbs *cbs) { return cbs->shouldMessageBeStoredCb; } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 817a82bbd..e549964e0 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -382,6 +382,16 @@ void linphone_chat_room_set_participant_devices (LinphoneChatRoom *cr, const Lin bctbx_free(addrStr); } +void linphone_chat_room_add_participant_device (LinphoneChatRoom *cr, const LinphoneAddress *participantAddress, const LinphoneAddress *deviceAddress) { + char *participantAddressStr = linphone_address_as_string(participantAddress); + char *deviceAddressStr = linphone_address_as_string(deviceAddress); + LinphonePrivate::ServerGroupChatRoomPrivate *sgcr = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(cr)); + if (sgcr) + sgcr->addParticipantDevice(LinphonePrivate::IdentityAddress(participantAddressStr), LinphonePrivate::IdentityAddress(deviceAddressStr)); + bctbx_free(participantAddressStr); + bctbx_free(deviceAddressStr); +} + void linphone_chat_room_add_compatible_participants (LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsCompatible) { list lPartsComp = L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(participantsCompatible, Address); LinphonePrivate::ServerGroupChatRoomPrivate *sgcr = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(cr)); @@ -486,14 +496,22 @@ void _linphone_chat_room_notify_conference_address_generation(LinphoneChatRoom * NOTIFY_IF_EXIST(ConferenceAddressGeneration, conference_address_generation, cr) } -void _linphone_chat_room_notify_participant_device_fetched(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr) { - NOTIFY_IF_EXIST(ParticipantDeviceFetched, participant_device_fetched, cr, participantAddr) +void _linphone_chat_room_notify_participant_device_fetch_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr) { + NOTIFY_IF_EXIST(ParticipantDeviceFetchRequested, participant_device_fetch_requested, cr, participantAddr) } void _linphone_chat_room_notify_participants_capabilities_checked(LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsAddr) { NOTIFY_IF_EXIST(ParticipantsCapabilitiesChecked, participants_capabilities_checked, cr, deviceAddr, participantsAddr) } +void _linphone_chat_room_notify_participant_registration_subscription_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr) { + NOTIFY_IF_EXIST(ParticipantRegistrationSubscriptionRequested, participant_registration_subscription_requested, cr, participantAddr) +} + +void _linphone_chat_room_notify_participant_registration_unsubscription_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr) { + NOTIFY_IF_EXIST(ParticipantRegistrationUnsubscriptionRequested, participant_registration_unsubscription_requested, cr, participantAddr) +} + void _linphone_chat_room_notify_chat_message_should_be_stored(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { NOTIFY_IF_EXIST(ShouldChatMessageBeStored, chat_message_should_be_stored, cr, msg) } diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index 1f124cab3..f31326ad0 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -60,6 +60,7 @@ public: void setConferenceAddress (const IdentityAddress &conferenceAddress); void setParticipantDevices (const IdentityAddress &addr, const std::list &devices); + void addParticipantDevice (const IdentityAddress &participantAddress, const IdentityAddress &deviceAddress); void addCompatibleParticipants (const IdentityAddress &deviceAddr, const std::list &compatibleParticipants); void checkCompatibleParticipants (const IdentityAddress &deviceAddr, const std::list &addressesToCheck); @@ -67,17 +68,29 @@ public: private: struct Message { - Message (const std::string &from, const std::string &contentType, const std::string &text) : fromAddr(from) { + Message (const std::string &from, const std::string &contentType, const std::string &text, const SalCustomHeader *salCustomHeaders) + : fromAddr(from) + { content.setContentType(contentType); if (!text.empty()) content.setBodyFromUtf8(text); + if (salCustomHeaders) + customHeaders = sal_custom_header_clone(salCustomHeaders); + } + + ~Message () { + if (customHeaders) + sal_custom_header_free(customHeaders); } IdentityAddress fromAddr; Content content; std::chrono::system_clock::time_point timestamp = std::chrono::system_clock::now(); + SalCustomHeader *customHeaders = nullptr; }; + static void copyMessageHeaders (const std::shared_ptr &fromMessage, const std::shared_ptr &toMessage); + void designateAdmin (); void dispatchMessage (const std::shared_ptr &message, const std::string &uri); void finalizeCreation (); diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index ad0ce75f6..d8204fc5b 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -80,6 +80,8 @@ void ServerGroupChatRoomPrivate::setConferenceAddress (const IdentityAddress &) void ServerGroupChatRoomPrivate::setParticipantDevices (const IdentityAddress &addr, const list &devices) {} +void ServerGroupChatRoomPrivate::addParticipantDevice (const IdentityAddress &participantAddress, const IdentityAddress &deviceAddress) {} + void ServerGroupChatRoomPrivate::addCompatibleParticipants (const IdentityAddress &deviceAddr, const list &participantCompatible) {} // ----------------------------------------------------------------------------- diff --git a/tester/group_chat_tester.c b/tester/group_chat_tester.c index 22cb42d4b..fcccb89ee 100644 --- a/tester/group_chat_tester.c +++ b/tester/group_chat_tester.c @@ -2874,7 +2874,7 @@ static void group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2 linphone_core_manager_destroy(pauline2); } - +#if 0 static void group_chat_room_join_one_to_one_chat_room_with_a_new_device (void) { LinphoneCoreManager *marie1 = linphone_core_manager_create("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc"); @@ -2963,6 +2963,7 @@ static void group_chat_room_join_one_to_one_chat_room_with_a_new_device (void) { linphone_core_manager_destroy(marie1); linphone_core_manager_destroy(pauline); } +#endif static void group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left (void) { LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc"); @@ -3179,6 +3180,65 @@ static void find_one_to_one_chat_room (void) { linphone_core_manager_destroy(chloe); } +static void group_chat_room_new_device_after_creation (void) { + LinphoneCoreManager *marie1 = linphone_core_manager_create("marie_rc"); + LinphoneCoreManager *pauline1 = linphone_core_manager_create("pauline_rc"); + LinphoneCoreManager *pauline2 = 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, marie1); + coresManagerList = bctbx_list_append(coresManagerList, pauline1); + coresManagerList = bctbx_list_append(coresManagerList, pauline2); + 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(pauline1->lc))); + participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(laure->lc))); + stats initialMarie1Stats = marie1->stat; + stats initialPauline1Stats = pauline1->stat; + stats initialPauline2Stats = pauline2->stat; + stats initialLaureStats = laure->stat; + + // Marie creates a new group chat room + const char *initialSubject = "Colleagues"; + LinphoneChatRoom *marie1Cr = create_chat_room_client_side(coresList, marie1, &initialMarie1Stats, participantsAddresses, initialSubject, -1); + participantsAddresses = NULL; + const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marie1Cr); + + // Check that the chat room is correctly created on Pauline1 and Pauline2's sides and that the participants are added + LinphoneChatRoom *pauline1Cr = check_creation_chat_room_client_side(coresList, pauline1, &initialPauline1Stats, confAddr, initialSubject, 2, FALSE); + LinphoneChatRoom *pauline2Cr = check_creation_chat_room_client_side(coresList, pauline2, &initialPauline2Stats, 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); + + // Marie adds a new device + LinphoneCoreManager *marie2 = linphone_core_manager_create("marie_rc"); + stats initialMarie2Stats = marie2->stat; + bctbx_list_t *tmpCoresManagerList = bctbx_list_append(NULL, marie2); + bctbx_list_t *tmpCoresList = init_core_for_conference(tmpCoresManagerList); + coresList = bctbx_list_concat(coresList, tmpCoresList); + start_core_for_conference(tmpCoresManagerList); + bctbx_list_free(tmpCoresManagerList); + LinphoneChatRoom *marie2Cr = check_creation_chat_room_client_side(coresList, marie2, &initialMarie2Stats, confAddr, initialSubject, 2, TRUE); + + // Clean db from chat room + linphone_core_manager_delete_chat_room(marie1, marie1Cr, coresList); + linphone_core_delete_chat_room(marie2->lc, marie2Cr); + linphone_core_manager_delete_chat_room(pauline1, pauline1Cr, coresList); + linphone_core_delete_chat_room(pauline2->lc, pauline2Cr); + linphone_core_manager_delete_chat_room(laure, laureCr, coresList); + + bctbx_list_free(coresList); + bctbx_list_free(coresManagerList); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline1); + linphone_core_manager_destroy(pauline2); + linphone_core_manager_destroy(laure); +} + test_t group_chat_tests[] = { TEST_NO_TAG("Group chat room creation server", group_chat_room_creation_server), TEST_ONE_TAG("Add participant", group_chat_room_add_participant, "LeaksMemory"), @@ -3218,11 +3278,12 @@ test_t group_chat_tests[] = { TEST_NO_TAG("Unique one-to-one chatroom", group_chat_room_unique_one_to_one_chat_room), TEST_NO_TAG("Unique one-to-one chatroom recreated from message", group_chat_room_unique_one_to_one_chat_room_recreated_from_message), TEST_ONE_TAG("Unique one-to-one chatroom recreated from message with app restart", group_chat_room_unique_one_to_one_chat_room_recreated_from_message_with_app_restart, "LeaksMemory"), - TEST_NO_TAG("Join one-to-one chat room with a new device", group_chat_room_join_one_to_one_chat_room_with_a_new_device), + //TEST_NO_TAG("Join one-to-one chat room with a new device", group_chat_room_join_one_to_one_chat_room_with_a_new_device), TEST_NO_TAG("New unique one-to-one chatroom after both participants left", group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left), TEST_NO_TAG("Unique one-to-one chatroom re-created from the party that deleted it, with inactive devices", group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2), TEST_NO_TAG("IMDN for group chat room", imdn_for_group_chat_room), - TEST_NO_TAG("Find one to one chat room", find_one_to_one_chat_room) + TEST_NO_TAG("Find one to one chat room", find_one_to_one_chat_room), + TEST_NO_TAG("New device after group chat room creation", group_chat_room_new_device_after_creation) }; test_suite_t group_chat_test_suite = { From 7c27d3c9bc2fa468e61683055eb7867d216d5b3a Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 15 Mar 2018 08:58:07 +0100 Subject: [PATCH 05/32] fix invalid read in Sal destruction --- src/sal/sal.cpp | 1 - tester/flexisip_tester.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sal/sal.cpp b/src/sal/sal.cpp index 41054ddc8..3346ab05e 100644 --- a/src/sal/sal.cpp +++ b/src/sal/sal.cpp @@ -118,7 +118,6 @@ void Sal::process_request_event_cb (void *ud, const belle_sip_request_event_t *e op->fill_cbs(); }else if (strcmp("REFER",method)==0) { op=new SalReferOp(sal); - op->fill_cbs(); }else if (strcmp("OPTIONS",method)==0) { resp=belle_sip_response_create_from_request(req,200); belle_sip_provider_send_response(sal->prov,resp); diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 11e80bab4..ef21a90ea 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -1388,7 +1388,7 @@ static void on_refer_received(SalOp *op, const SalAddress *refer_to) { Sal *sal = sal_op_get_sal(op); LinphoneCoreManager *receiver = (LinphoneCoreManager*)sal_get_user_pointer(sal); receiver->stat.number_of_LinphoneCallRefered++; - sal_release_op(op); + } void resend_refer_other_devices(void) { From 734453206d4dcce5d0024e47ee7be50a5a113e46 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 15 Mar 2018 10:36:01 +0100 Subject: [PATCH 06/32] Fix crash if user pointer of op is null in call failure callback. --- coreapi/callbacks.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 6302d92f6..da809bc05 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -256,7 +256,9 @@ static void call_terminated(SalOp *op, const char *from) { } static void call_failure(SalOp *op) { - std::shared_ptr session = reinterpret_cast(op->get_user_pointer())->getSharedFromThis(); + shared_ptr session; + if (op->get_user_pointer()) + session = reinterpret_cast(op->get_user_pointer())->getSharedFromThis(); if (!session) { ms_warning("Failure reported on already terminated CallSession"); return; From 5c2669970fc341e6c97cc3f6e2eb7ca766de2bd7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 15 Mar 2018 10:49:51 +0100 Subject: [PATCH 07/32] Restore "Join one-to-one chat room with a new device" group chat tester. --- tester/group_chat_tester.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/tester/group_chat_tester.c b/tester/group_chat_tester.c index fcccb89ee..bc9bb7159 100644 --- a/tester/group_chat_tester.c +++ b/tester/group_chat_tester.c @@ -2874,7 +2874,6 @@ static void group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2 linphone_core_manager_destroy(pauline2); } -#if 0 static void group_chat_room_join_one_to_one_chat_room_with_a_new_device (void) { LinphoneCoreManager *marie1 = linphone_core_manager_create("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc"); @@ -2925,16 +2924,11 @@ static void group_chat_room_join_one_to_one_chat_room_with_a_new_device (void) { coresManagerList = bctbx_list_concat(coresManagerList, newCoresManagerList); coresList = bctbx_list_concat(coresList, newCoresList); - // Marie2 creates a new one-to-one chat room with Pauline + // Marie2 gets the one-to-one chat room with Pauline stats initialMarie2Stats = marie2->stat; - participantsAddresses = bctbx_list_append(NULL, linphone_address_new(linphone_core_get_identity(pauline->lc))); - LinphoneChatRoom *marie2Cr = create_chat_room_client_side(coresList, marie2, &initialMarie2Stats, participantsAddresses, initialSubject, -1); + LinphoneChatRoom *marie2Cr = check_creation_chat_room_client_side(coresList, marie2, &initialMarie2Stats, confAddr, initialSubject, 1, FALSE); BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(marie2Cr) & LinphoneChatRoomCapabilitiesOneToOne); - // Check that the created address is the same as before - const LinphoneAddress *newConfAddr = linphone_chat_room_get_conference_address(marie2Cr); - BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, newConfAddr)); - // Marie2 sends a new message textMessage = "Fine and you?"; message = _send_message(marie2Cr, textMessage); @@ -2963,7 +2957,6 @@ static void group_chat_room_join_one_to_one_chat_room_with_a_new_device (void) { linphone_core_manager_destroy(marie1); linphone_core_manager_destroy(pauline); } -#endif static void group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left (void) { LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc"); @@ -3278,7 +3271,7 @@ test_t group_chat_tests[] = { TEST_NO_TAG("Unique one-to-one chatroom", group_chat_room_unique_one_to_one_chat_room), TEST_NO_TAG("Unique one-to-one chatroom recreated from message", group_chat_room_unique_one_to_one_chat_room_recreated_from_message), TEST_ONE_TAG("Unique one-to-one chatroom recreated from message with app restart", group_chat_room_unique_one_to_one_chat_room_recreated_from_message_with_app_restart, "LeaksMemory"), - //TEST_NO_TAG("Join one-to-one chat room with a new device", group_chat_room_join_one_to_one_chat_room_with_a_new_device), + TEST_NO_TAG("Join one-to-one chat room with a new device", group_chat_room_join_one_to_one_chat_room_with_a_new_device), TEST_NO_TAG("New unique one-to-one chatroom after both participants left", group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left), TEST_NO_TAG("Unique one-to-one chatroom re-created from the party that deleted it, with inactive devices", group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2), TEST_NO_TAG("IMDN for group chat room", imdn_for_group_chat_room), From a244da20ff900f63073e3d4c5afe425960dcbca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Turnel?= Date: Thu, 15 Mar 2018 13:58:33 +0100 Subject: [PATCH 08/32] Add a TMMBR callback --- coreapi/private_functions.h | 1 + include/linphone/api/c-call-cbs.h | 14 ++++ include/linphone/api/c-callbacks.h | 8 +++ src/c-wrapper/api/c-call-cbs.cpp | 9 +++ src/c-wrapper/api/c-call.cpp | 4 ++ src/call/call-p.h | 1 + src/call/call.cpp | 5 ++ .../session/call-session-listener.h | 1 + src/conference/session/media-session.cpp | 19 ++++- tester/call_video_tester.c | 69 ++++++++++++++++++- tester/liblinphone_tester.h | 1 + 11 files changed, 128 insertions(+), 4 deletions(-) diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h index df615255b..e6a27fbe0 100644 --- a/coreapi/private_functions.h +++ b/coreapi/private_functions.h @@ -47,6 +47,7 @@ void linphone_call_notify_transfer_state_changed(LinphoneCall *call, LinphoneCal void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallStats *stats); void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg); void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received); +void linphone_call_notify_tmmbr_received(LinphoneCall *call, int stream_index, int tmmbr); LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op); diff --git a/include/linphone/api/c-call-cbs.h b/include/linphone/api/c-call-cbs.h index ed5c3718c..207321ddf 100644 --- a/include/linphone/api/c-call-cbs.h +++ b/include/linphone/api/c-call-cbs.h @@ -159,6 +159,20 @@ LINPHONE_PUBLIC LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_process */ LINPHONE_PUBLIC void linphone_call_cbs_set_ack_processing (LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb); +/** + * Get the TMMBR received callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current TMMBR received callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsTmmbrReceivedCb linphone_call_cbs_get_tmmbr_received(LinphoneCallCbs *cbs); + +/** + * Set the TMMBR received callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The TMMBR received callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_tmmbr_received(LinphoneCallCbs *cbs, LinphoneCallCbsTmmbrReceivedCb cb); + /** * @} */ diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index f8b796a00..339963691 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -87,6 +87,14 @@ typedef void (*LinphoneCallCbsTransferStateChangedCb)(LinphoneCall *call, Linpho */ typedef void (*LinphoneCallCbsAckProcessingCb)(LinphoneCall *call, LinphoneHeaders *ack, bool_t is_received); +/** + * Callback for notifying a received TMMBR. + * @param call LinphoneCall for which the TMMBR has changed + * @param stream_index the index of the current stream + * @param tmmbr the value of the received TMMBR + */ +typedef void (*LinphoneCallCbsTmmbrReceivedCb)(LinphoneCall *call, int stream_index, int tmmbr); + /** * @} **/ diff --git a/src/c-wrapper/api/c-call-cbs.cpp b/src/c-wrapper/api/c-call-cbs.cpp index 17b521e40..903dfa26a 100644 --- a/src/c-wrapper/api/c-call-cbs.cpp +++ b/src/c-wrapper/api/c-call-cbs.cpp @@ -33,6 +33,7 @@ struct _LinphoneCallCbs { LinphoneCallCbsStatsUpdatedCb statsUpdatedCb; LinphoneCallCbsTransferStateChangedCb transferStateChangedCb; LinphoneCallCbsAckProcessingCb ackProcessing; + LinphoneCallCbsTmmbrReceivedCb tmmbrReceivedCb; }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallCbs); @@ -124,3 +125,11 @@ LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing (LinphoneCal void linphone_call_cbs_set_ack_processing (LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb){ cbs->ackProcessing = cb; } + +LinphoneCallCbsTmmbrReceivedCb linphone_call_cbs_get_tmmbr_received (LinphoneCallCbs *cbs) { + return cbs->tmmbrReceivedCb; +} + +void linphone_call_cbs_set_tmmbr_received (LinphoneCallCbs *cbs, LinphoneCallCbsTmmbrReceivedCb cb) { + cbs->tmmbrReceivedCb = cb; +} diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 07159bfc4..0fa450fa5 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -206,6 +206,10 @@ void linphone_call_notify_ack_processing (LinphoneCall *call, LinphoneHeaders *m NOTIFY_IF_EXIST(AckProcessing, ack_processing, call, msg, is_received) } +void linphone_call_notify_tmmbr_received (LinphoneCall *call, int stream_index, int tmmbr) { + NOTIFY_IF_EXIST(TmmbrReceived, tmmbr_received, call, stream_index, tmmbr) +} + // ============================================================================= // Public functions. diff --git a/src/call/call-p.h b/src/call/call-p.h index 7b2754ff6..0477198df 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -110,6 +110,7 @@ private: bool areSoundResourcesAvailable (const std::shared_ptr &session) override; bool isPlayingRingbackTone (const std::shared_ptr &session) override; void onRealTimeTextCharacterReceived (const std::shared_ptr &session, RealtimeTextReceivedCharacter *character) override; + void onTmmbrReceived(const std::shared_ptr &session, int streamIndex, int tmmbr) override; mutable LinphonePlayer *player = nullptr; diff --git a/src/call/call.cpp b/src/call/call.cpp index f60387011..6d51ce781 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -491,6 +491,11 @@ void CallPrivate::onRealTimeTextCharacterReceived (const shared_ptr getChatRoom()->getPrivate()->realtimeTextReceived(data->character, q->getSharedFromThis()); } +void CallPrivate::onTmmbrReceived (const shared_ptr &session, int streamIndex, int tmmbr) { + L_Q(); + linphone_call_notify_tmmbr_received(L_GET_C_BACK_PTR(q), streamIndex, tmmbr); +} + // ============================================================================= Call::Call (CallPrivate &p, shared_ptr core) : Object(p), CoreAccessor(core) { diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index a334614ea..edc634f22 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -54,6 +54,7 @@ public: virtual void onIncomingCallSessionTimeoutCheck (const std::shared_ptr &session, int elapsed, bool oneSecondElapsed) {} virtual void onInfoReceived (const std::shared_ptr &session, const LinphoneInfoMessage *im) {} virtual void onNoMediaTimeoutCheck (const std::shared_ptr &session, bool oneSecondElapsed) {} + virtual void onTmmbrReceived (const std::shared_ptr &session, int streamIndex, int tmmbr) {} virtual void onEncryptionChanged (const std::shared_ptr &session, bool activated, const std::string &authToken) {} diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index d79b6a34a..955bcbb4e 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -2238,6 +2238,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { } void MediaSessionPrivate::handleStreamEvents (int streamIndex) { + L_Q(); MediaStream *ms = (streamIndex == mainAudioStreamIndex) ? &audioStream->ms : (streamIndex == mainVideoStreamIndex ? &videoStream->ms : &textStream->ms); if (ms) { @@ -2272,14 +2273,28 @@ void MediaSessionPrivate::handleStreamEvents (int streamIndex) { stats = videoStats; else stats = textStats; + + OrtpEventType evt = ortp_event_get_type(ev); + OrtpEventData *evd = ortp_event_get_data(ev); + + /*This MUST be done before any call to "linphone_call_stats_fill" since it has ownership over evd->packet*/ + if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { + do { + if (evd->packet && rtcp_is_RTPFB(evd->packet)) { + if (rtcp_RTPFB_get_type(evd->packet) == RTCP_RTPFB_TMMBR) { + listener->onTmmbrReceived(q->getSharedFromThis(), streamIndex, (int)rtcp_RTPFB_tmmbr_get_max_bitrate(evd->packet)); + } + } + } while (rtcp_next_packet(evd->packet)); + rtcp_rewind(evd->packet); + } + /* And yes the MediaStream must be taken at each iteration, because it may have changed due to the handling of events * in this loop*/ ms = getMediaStream(streamIndex); if (ms) linphone_call_stats_fill(stats, ms, ev); notifyStatsUpdated(streamIndex); - OrtpEventType evt = ortp_event_get_type(ev); - OrtpEventData *evd = ortp_event_get_data(ev); if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED) { if (streamIndex == mainAudioStreamIndex) audioStreamEncryptionChanged(!!evd->info.zrtp_stream_encrypted); diff --git a/tester/call_video_tester.c b/tester/call_video_tester.c index cf55ad1f1..d74fbd2f8 100644 --- a/tester/call_video_tester.c +++ b/tester/call_video_tester.c @@ -2008,6 +2008,70 @@ static void video_call_with_thin_congestion(void){ linphone_core_manager_destroy(pauline); } +static void on_tmmbr_received(LinphoneCall *call, int stream_index, int tmmbr) { + if (stream_index == _linphone_call_get_main_video_stream_index(call)) { + stats* stat = get_stats(linphone_call_get_core(call)); + stat->tmmbr_received_from_cb = tmmbr; + } +} + +static void call_created(LinphoneCore *lc, LinphoneCall *call) { + LinphoneCallCbs *cbs = linphone_factory_create_call_cbs(linphone_factory_get()); + linphone_call_cbs_set_tmmbr_received(cbs, on_tmmbr_received); + linphone_call_add_callbacks(call, cbs); + linphone_call_cbs_unref(cbs); +} + +/* + * This test simulates a higher bandwith available from marie than expected. + * The stream from pauline to marie is not under test. + * It checks that after a few seconds marie received a TMMBR with the approximate value corresponding to the new bandwidth. + * +**/ +static void video_call_with_high_bandwidth_available(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); + LinphoneVideoPolicy pol = {0}; + OrtpNetworkSimulatorParams simparams = { 0 }; + LinphoneCoreCbs *core_cbs = linphone_factory_create_core_cbs(linphone_factory_get()); + + linphone_core_set_video_device(marie->lc, "Mire: Mire (synthetic moving picture)"); + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, TRUE); + linphone_core_enable_video_capture(pauline->lc, TRUE); + linphone_core_enable_video_display(pauline->lc, TRUE); + + pol.automatically_accept = TRUE; + pol.automatically_initiate = TRUE; + linphone_core_set_video_policy(marie->lc, &pol); + linphone_core_set_video_policy(pauline->lc, &pol); + + linphone_core_set_preferred_video_size_by_name(marie->lc, "vga"); + simparams.mode = OrtpNetworkSimulatorOutbound; + simparams.enabled = TRUE; + simparams.max_bandwidth = 1000000; + simparams.max_buffer_size = (int)simparams.max_bandwidth; + simparams.latency = 60; + + linphone_core_set_network_simulator_params(marie->lc, &simparams); + + linphone_core_cbs_set_call_created(core_cbs, call_created); + linphone_core_add_callbacks(marie->lc, core_cbs); + + if (BC_ASSERT_TRUE(call(marie, pauline))){ + /*wait a little in order to have traffic*/ + BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, NULL, 5, 50000)); + + BC_ASSERT_GREATER((float)marie->stat.last_tmmbr_value_received, 870000.f, float, "%f"); + BC_ASSERT_LOWER((float)marie->stat.last_tmmbr_value_received, 1150000.f, float, "%f"); + + end_call(marie, pauline); + } + linphone_core_cbs_unref(core_cbs); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + test_t call_video_tests[] = { #ifdef VIDEO_ENABLED TEST_NO_TAG("Call paused resumed with video", call_paused_resumed_with_video), @@ -2073,10 +2137,11 @@ test_t call_video_tests[] = { TEST_NO_TAG("Classic video entry phone setup", classic_video_entry_phone_setup), TEST_NO_TAG("Incoming REINVITE with invalid SDP in ACK", incoming_reinvite_with_invalid_ack_sdp), TEST_NO_TAG("Outgoing REINVITE with invalid SDP in ACK", outgoing_reinvite_with_invalid_ack_sdp), -#endif TEST_NO_TAG("Video call with no audio and no video codec", video_call_with_no_audio_and_no_video_codec), TEST_NO_TAG("Call with early media and no SDP in 200 Ok with video", call_with_early_media_and_no_sdp_in_200_with_video), - TEST_NO_TAG("Video call with thin congestion", video_call_with_thin_congestion) + TEST_NO_TAG("Video call with thin congestion", video_call_with_thin_congestion), + TEST_NO_TAG("Video call with high bandwidth available", video_call_with_high_bandwidth_available) +#endif }; test_suite_t call_video_test_suite = {"Video Call", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 7e07493d0..9824c2084 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -283,6 +283,7 @@ typedef struct _stats { int number_of_rtcp_generic_nack; int number_of_tmmbr_received; int last_tmmbr_value_received; + int tmmbr_received_from_cb; int number_of_participants_added; int number_of_participant_admin_statuses_changed; From 1207501da26b2e2861ff091c72f761c86b988eb9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 15 Mar 2018 14:00:57 +0100 Subject: [PATCH 09/32] Started to restore external body url feature in chat message --- src/c-wrapper/api/c-chat-message.cpp | 2 +- src/chat/chat-message/chat-message-p.h | 2 ++ src/chat/chat-message/chat-message.cpp | 8 ++++++++ src/chat/chat-room/chat-room.cpp | 9 +++++++-- .../modifier/file-transfer-chat-message-modifier.cpp | 4 ++++ src/chat/modifier/file-transfer-chat-message-modifier.h | 1 + 6 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 333d6a94e..902055f9a 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -108,7 +108,7 @@ const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessag } void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) { - + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setExternalBodyUrl(L_C_TO_STRING(url)); } time_t linphone_chat_message_get_time(const LinphoneChatMessage *msg) { diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 764de0d96..42cbb58e6 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -105,6 +105,7 @@ public: std::string getSalCustomHeaderValue (const std::string &name); void loadFileTransferUrlFromBodyToContent (); + std::string createFakeFileTransferFromUrl(const std::string &url); void setChatRoom (const std::shared_ptr &chatRoom); @@ -127,6 +128,7 @@ public: void setAppdata (const std::string &appData); const std::string &getExternalBodyUrl () const; + void setExternalBodyUrl (const std::string &url); bool hasTextContent () const; const Content* getTextContent () const; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 487a052af..ead18f02c 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -263,6 +263,10 @@ const string &ChatMessagePrivate::getExternalBodyUrl () const { return Utils::getEmptyConstRefObject(); } +void ChatMessagePrivate::setExternalBodyUrl (const string &url) { + //TODO +} + const ContentType &ChatMessagePrivate::getContentType () { loadContentsFromDatabase(); if (direction == ChatMessage::Direction::Incoming) { @@ -390,6 +394,10 @@ void ChatMessagePrivate::loadFileTransferUrlFromBodyToContent() { fileTransferChatMessageModifier.decode(q->getSharedFromThis(), errorCode); } +std::string ChatMessagePrivate::createFakeFileTransferFromUrl(const std::string &url) { + return fileTransferChatMessageModifier.createFakeFileTransferFromUrl(url); +} + void ChatMessagePrivate::setChatRoom (const shared_ptr &cr) { chatRoom = cr; chatRoomId = cr->getChatRoomId(); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 9404bba69..8f69fda03 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -193,8 +193,13 @@ LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessag ); Content content; - content.setContentType(message->content_type); - content.setBodyFromUtf8(message->text ? message->text : ""); + if (message->url && strcmp(message->content_type, ContentType::ExternalBody.asString().c_str()) == 0) { + content.setContentType(ContentType::FileTransfer); + content.setBody(msg->getPrivate()->createFakeFileTransferFromUrl(message->url)); + } else { + content.setContentType(message->content_type); + content.setBodyFromUtf8(message->text ? message->text : ""); + } msg->setInternalContent(content); msg->getPrivate()->setTime(message->time); diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index 1da43ae8d..8dd98988d 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -968,4 +968,8 @@ void FileTransferChatMessageModifier::releaseHttpRequest () { } } +string FileTransferChatMessageModifier::createFakeFileTransferFromUrl(const string &url) { + return ""; //TODO +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.h b/src/chat/modifier/file-transfer-chat-message-modifier.h index 99a7cbf2e..d6d9af736 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.h +++ b/src/chat/modifier/file-transfer-chat-message-modifier.h @@ -63,6 +63,7 @@ public: int downloadFile(const std::shared_ptr &message, FileTransferContent *fileTransferContent); void cancelFileTransfer(); bool isFileTransferInProgressAndValid(); + std::string createFakeFileTransferFromUrl(const std::string &url); private: int uploadFile(); From 166b0a5d62e391e5eddf17a58d1f3acc4facd012 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 15 Mar 2018 14:09:42 +0100 Subject: [PATCH 10/32] Send message with external body url if exists --- src/chat/chat-message/chat-message-p.h | 1 + src/chat/chat-message/chat-message.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 42cbb58e6..b665e0d1f 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -163,6 +163,7 @@ private: time_t time = ::ms_time(0); // TODO: Change me in all files. std::string imdnId; std::string rttMessage; + std::string externalBodyUrl; bool isSecured = false; mutable bool isReadOnly = false; Content internalContent; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index ead18f02c..86b126cfa 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -256,6 +256,9 @@ void ChatMessagePrivate::setAppdata (const string &data) { } const string &ChatMessagePrivate::getExternalBodyUrl () const { + if (!externalBodyUrl.empty()) { + return externalBodyUrl; + } if (hasFileTransferContent()) { FileTransferContent *content = (FileTransferContent*) getFileTransferContent(); return content->getFileUrl(); @@ -264,7 +267,7 @@ const string &ChatMessagePrivate::getExternalBodyUrl () const { } void ChatMessagePrivate::setExternalBodyUrl (const string &url) { - //TODO + externalBodyUrl = url; } const ContentType &ChatMessagePrivate::getContentType () { @@ -719,14 +722,18 @@ void ChatMessagePrivate::send () { if (internalContent.isEmpty()) { if (contents.size() > 0) { internalContent = *(contents.front()); - } else { + } else if (!externalBodyUrl.empty()) { // When using external body url, there is no content lError() << "Trying to send a message without any content !"; return; } } auto msgOp = dynamic_cast(op); - if (internalContent.getContentType().isValid()) { + if (!externalBodyUrl.empty()) { + char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", externalBodyUrl); + msgOp->send_message(content_type, NULL); + ms_free(content_type); + } else if (internalContent.getContentType().isValid()) { msgOp->send_message(internalContent.getContentType().asString().c_str(), internalContent.getBodyAsUtf8String().c_str()); } else { msgOp->send_message(ContentType::PlainText.asString().c_str(), internalContent.getBodyAsUtf8String().c_str()); From 3fd55c4a2bb81be4449d297bfebdbdbce4a01f1d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 15 Mar 2018 14:31:57 +0100 Subject: [PATCH 11/32] Fixes + tests for external body URL --- src/c-wrapper/api/c-chat-room.cpp | 7 +++- src/chat/chat-message/chat-message.cpp | 4 +-- src/chat/chat-room/chat-room.cpp | 2 ++ tester/message_tester.c | 48 ++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index e549964e0..91dbad4c0 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -113,7 +113,12 @@ const LinphoneAddress *linphone_chat_room_get_local_address (LinphoneChatRoom *c } LinphoneChatMessage *linphone_chat_room_create_message (LinphoneChatRoom *cr, const char *message) { - shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createChatMessage(L_C_TO_STRING(message)); + shared_ptr cppPtr; + if (message && strlen(message) > 0) { + cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createChatMessage(L_C_TO_STRING(message)); + } else { + cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createChatMessage(); + } LinphoneChatMessage *object = L_INIT(ChatMessage); L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr); return object; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 86b126cfa..7e12324ee 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -722,7 +722,7 @@ void ChatMessagePrivate::send () { if (internalContent.isEmpty()) { if (contents.size() > 0) { internalContent = *(contents.front()); - } else if (!externalBodyUrl.empty()) { // When using external body url, there is no content + } else if (externalBodyUrl.empty()) { // When using external body url, there is no content lError() << "Trying to send a message without any content !"; return; } @@ -730,7 +730,7 @@ void ChatMessagePrivate::send () { auto msgOp = dynamic_cast(op); if (!externalBodyUrl.empty()) { - char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", externalBodyUrl); + char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", externalBodyUrl.c_str()); msgOp->send_message(content_type, NULL); ms_free(content_type); } else if (internalContent.getContentType().isValid()) { diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 8f69fda03..cbd6ef4c3 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -26,6 +26,7 @@ #include "chat/chat-room/chat-room-p.h" #include "core/core-p.h" #include "sip-tools/sip-headers.h" +#include "logger/logger.h" // ============================================================================= @@ -194,6 +195,7 @@ LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessag Content content; if (message->url && strcmp(message->content_type, ContentType::ExternalBody.asString().c_str()) == 0) { + lInfo() << "Received a message with an external body URL " << message->url; content.setContentType(ContentType::FileTransfer); content.setBody(msg->getPrivate()->createFakeFileTransferFromUrl(message->url)); } else { diff --git a/tester/message_tester.c b/tester/message_tester.c index 0d639eac0..cfca82130 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -730,6 +730,52 @@ static void file_transfer_2_messages_simultaneously(void) { } } +static void file_transfer_external_body_url(bool_t use_file_body_handler_in_download) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneChatRoom* chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity); + LinphoneChatMessage* msg = linphone_chat_room_create_message(chat_room, NULL); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + char *receive_filepath = bc_tester_file("receive_file.dump"); + + linphone_chat_message_set_external_body_url(msg, "https://www.linphone.org/img/linphone-open-source-voip-projectX2.png"); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_room_send_chat_message(chat_room, msg); + linphone_chat_message_unref(msg); + + BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageReceivedWithFile, 1, 60000)); + + if (pauline->stat.last_received_chat_message) { + LinphoneChatMessage *recv_msg = pauline->stat.last_received_chat_message; + cbs = linphone_chat_message_get_callbacks(recv_msg); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication); + if (use_file_body_handler_in_download) { + /* Remove any previously downloaded file */ + remove(receive_filepath); + linphone_chat_message_set_file_transfer_filepath(recv_msg, receive_filepath); + } + linphone_chat_message_download_file(recv_msg); + + /* wait for a long time in case the DNS SRV resolution takes times - it should be immediate though */ + BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneFileTransferDownloadSuccessful, 1, 55000)); + } + + remove(receive_filepath); + bc_free(receive_filepath); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void file_transfer_using_external_body_url(void) { + file_transfer_external_body_url(FALSE); +} + +static void file_transfer_using_external_body_url_2(void) { + file_transfer_external_body_url(TRUE); +} + static void text_message_denied(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); @@ -2439,6 +2485,8 @@ test_t message_tests[] = { TEST_NO_TAG("Transfer message upload cancelled", transfer_message_upload_cancelled), TEST_NO_TAG("Transfer message download cancelled", transfer_message_download_cancelled), TEST_NO_TAG("Transfer 2 messages simultaneously", file_transfer_2_messages_simultaneously), + TEST_NO_TAG("Transfer using external body URL", file_transfer_using_external_body_url), + TEST_NO_TAG("Transfer using external body URL 2", file_transfer_using_external_body_url_2), TEST_NO_TAG("Text message denied", text_message_denied), TEST_NO_TAG("IsComposing notification", is_composing_notification), TEST_NO_TAG("IMDN notifications", imdn_notifications), From a36a3c55cfdd3957d331c14daae5be69a10238f7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 15 Mar 2018 14:43:53 +0100 Subject: [PATCH 12/32] Finished fake file transfer xml from external body url --- .../modifier/file-transfer-chat-message-modifier.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index 8dd98988d..f0eeef84e 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -969,7 +969,16 @@ void FileTransferChatMessageModifier::releaseHttpRequest () { } string FileTransferChatMessageModifier::createFakeFileTransferFromUrl(const string &url) { - return ""; //TODO + string fileName = url.substr(url.find_last_of("/") + 1); + stringstream fakeXml; + fakeXml << "\r\n"; + fakeXml << "\r\n"; + fakeXml << "" << fileName << "\r\n"; + fakeXml << "application/binary\r\n"; + fakeXml << "\r\n"; + fakeXml << "\r\n"; + fakeXml << ""; + return fakeXml.str(); } LINPHONE_END_NAMESPACE From 5fb17f6598c7a7de5e82434d257775aa96ff5106 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 15 Mar 2018 15:06:35 +0100 Subject: [PATCH 13/32] Split first line of fake xml in two --- src/chat/modifier/file-transfer-chat-message-modifier.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index f0eeef84e..b320de965 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -971,7 +971,8 @@ void FileTransferChatMessageModifier::releaseHttpRequest () { string FileTransferChatMessageModifier::createFakeFileTransferFromUrl(const string &url) { string fileName = url.substr(url.find_last_of("/") + 1); stringstream fakeXml; - fakeXml << "\r\n"; + fakeXml << "\r\n" + fakeXml << "\r\n"; fakeXml << "\r\n"; fakeXml << "" << fileName << "\r\n"; fakeXml << "application/binary\r\n"; From 23287aae21b9fdd56bb99e2c2438211cdbbe9f5c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 15 Mar 2018 15:25:43 +0100 Subject: [PATCH 14/32] Forgot ; --- src/chat/modifier/file-transfer-chat-message-modifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index b320de965..d9d0767b2 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -971,7 +971,7 @@ void FileTransferChatMessageModifier::releaseHttpRequest () { string FileTransferChatMessageModifier::createFakeFileTransferFromUrl(const string &url) { string fileName = url.substr(url.find_last_of("/") + 1); stringstream fakeXml; - fakeXml << "\r\n" + fakeXml << "\r\n"; fakeXml << "\r\n"; fakeXml << "\r\n"; fakeXml << "" << fileName << "\r\n"; From f58ba4083e00cd8c1b15135f3deb6788144f085c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 15 Mar 2018 15:46:45 +0100 Subject: [PATCH 15/32] Moved appData from FileContent to any Content --- src/chat/chat-message/chat-message.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 7e12324ee..4781424be 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -236,23 +236,23 @@ void ChatMessagePrivate::setFileTransferFilepath (const string &path) { const string &ChatMessagePrivate::getAppdata () const { for (const Content *c : getContents()) { - if (c->isFile()) { - FileContent *fileContent = (FileContent *)c; - return fileContent->getAppData("legacy"); + if (!c->getAppData("legacy").empty()) { + return c->getAppData("legacy"); } } return Utils::getEmptyConstRefObject(); } void ChatMessagePrivate::setAppdata (const string &data) { - for (const Content *c : getContents()) { - if (c->isFile()) { - FileContent *fileContent = (FileContent *)c; - fileContent->setAppData("legacy", data); - break; - } + bool contentFound = false; + for (Content *c : getContents()) { + c->setAppData("legacy", data); + contentFound = true; + break; + } + if (contentFound) { + updateInDb(); } - updateInDb(); } const string &ChatMessagePrivate::getExternalBodyUrl () const { From 032f6cd91a276879a3c97959b446f61d80f85554 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 15 Mar 2018 15:57:59 +0100 Subject: [PATCH 16/32] When creating a message with no text, create an empty Content so we can use it to store an appData --- src/c-wrapper/api/c-chat-room.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 91dbad4c0..e549964e0 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -113,12 +113,7 @@ const LinphoneAddress *linphone_chat_room_get_local_address (LinphoneChatRoom *c } LinphoneChatMessage *linphone_chat_room_create_message (LinphoneChatRoom *cr, const char *message) { - shared_ptr cppPtr; - if (message && strlen(message) > 0) { - cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createChatMessage(L_C_TO_STRING(message)); - } else { - cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createChatMessage(); - } + shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createChatMessage(L_C_TO_STRING(message)); LinphoneChatMessage *object = L_INIT(ChatMessage); L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr); return object; From bcf1baaff13ddd7299fe08dc49152a15109a8196 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 16 Mar 2018 11:04:08 +0100 Subject: [PATCH 17/32] Wait for file transfer to be downloaded before sending Displayed IMDN --- src/chat/chat-message/chat-message.cpp | 8 +++++- src/chat/chat-room/chat-room.cpp | 7 +++-- tester/message_tester.c | 36 +++++++++++++++++++------- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 4781424be..579f44343 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -147,7 +147,13 @@ void ChatMessagePrivate::setState (ChatMessage::State newState, bool force) { if (cbs && linphone_chat_message_cbs_get_msg_state_changed(cbs)) linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, (LinphoneChatMessageState)state); - updateInDb(); + if (state == ChatMessage::State::FileTransferDone && !hasFileTransferContent()) { + // We wait until the file has been downloaded to send the displayed IMDN + q->sendDisplayNotification(); + setState(ChatMessage::State::Displayed); + } else { + updateInDb(); + } } belle_http_request_t *ChatMessagePrivate::getHttpRequest () const { diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index cbd6ef4c3..1eb64ce00 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -445,8 +445,11 @@ void ChatRoom::markAsRead () { CorePrivate *dCore = getCore()->getPrivate(); for (auto &chatMessage : dCore->mainDb->getUnreadChatMessages(d->chatRoomId)) { - chatMessage->sendDisplayNotification(); - chatMessage->getPrivate()->setState(ChatMessage::State::Displayed, true); + // Do not send display notification for file transfer until it has been downloaded (it won't have a file transfer content anymore) + if (!chatMessage->getPrivate()->hasFileTransferContent()) { + chatMessage->sendDisplayNotification(); + chatMessage->getPrivate()->setState(ChatMessage::State::Displayed, true); // True will ensure the setState won't update the database so it will be done below by the markChatMessagesAsRead + } } dCore->mainDb->markChatMessagesAsRead(d->chatRoomId); diff --git a/tester/message_tester.c b/tester/message_tester.c index cfca82130..396f4b9c4 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -503,9 +503,13 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau } else { BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1, 60000)); if (marie->stat.last_received_chat_message) { + LinphoneChatRoom *marie_room = linphone_core_get_chat_room(marie->lc, pauline->identity); + linphone_chat_room_mark_as_read(marie_room); + // We shoudln't get displayed IMDN until file has been downloaded + BC_ASSERT_FALSE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDisplayed,1, 5000)); + LinphoneChatMessage *recv_msg; if (download_from_history) { - LinphoneChatRoom *marie_room = linphone_core_get_chat_room(marie->lc, pauline->identity); msg_list = linphone_chat_room_get_history(marie_room,1); BC_ASSERT_PTR_NOT_NULL(msg_list); if (!msg_list) goto end; @@ -529,12 +533,13 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau belle_http_provider_set_recv_error(linphone_core_get_http_provider(marie->lc), -1); BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneMessageNotDelivered,1, 10000)); belle_http_provider_set_recv_error(linphone_core_get_http_provider(marie->lc), 0); + BC_ASSERT_FALSE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDisplayed,1, 5000)); } else { /* wait for a long time in case the DNS SRV resolution takes times - it should be immediate though */ if (BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1,55000))) { compare_files(send_filepath, receive_filepath); - } + BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDisplayed,1, 5000)); } } BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,2, int, "%d"); //sent twice because of file transfer @@ -549,41 +554,48 @@ end: } void transfer_message_base(bool_t upload_error, bool_t download_error, bool_t use_file_body_handler_in_upload, - bool_t use_file_body_handler_in_download, bool_t download_from_history) { + bool_t use_file_body_handler_in_download, bool_t download_from_history, bool_t enable_imdn) { if (transport_supported(LinphoneTransportTls)) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + if (enable_imdn) { + lp_config_set_int(linphone_core_get_config(pauline->lc), "sip", "deliver_imdn", 1); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "deliver_imdn", 1); + linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc)); + linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc)); + } transfer_message_base2(marie,pauline,upload_error,download_error, use_file_body_handler_in_upload, use_file_body_handler_in_download, download_from_history); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(marie); } } static void transfer_message(void) { - transfer_message_base(FALSE, FALSE, FALSE, FALSE, FALSE); + transfer_message_base(FALSE, FALSE, FALSE, FALSE, FALSE, TRUE); } static void transfer_message_2(void) { - transfer_message_base(FALSE, FALSE, TRUE, FALSE, FALSE); + transfer_message_base(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE); } static void transfer_message_3(void) { - transfer_message_base(FALSE, FALSE, FALSE, TRUE, FALSE); + transfer_message_base(FALSE, FALSE, FALSE, TRUE, FALSE, TRUE); } static void transfer_message_4(void) { - transfer_message_base(FALSE, FALSE, TRUE, TRUE, FALSE); + transfer_message_base(FALSE, FALSE, TRUE, TRUE, FALSE, TRUE); } static void transfer_message_from_history(void) { - transfer_message_base(FALSE, FALSE, TRUE, TRUE, TRUE); + transfer_message_base(FALSE, FALSE, TRUE, TRUE, TRUE, TRUE); } static void transfer_message_with_upload_io_error(void) { - transfer_message_base(TRUE, FALSE, FALSE, FALSE, FALSE); + transfer_message_base(TRUE, FALSE, FALSE, FALSE, FALSE, TRUE); } static void transfer_message_with_download_io_error(void) { - transfer_message_base(FALSE, TRUE, FALSE, FALSE, FALSE); + transfer_message_base(FALSE, TRUE, FALSE, FALSE, FALSE, TRUE); } static void transfer_message_upload_cancelled(void) { @@ -2176,6 +2188,10 @@ void file_transfer_with_http_proxy(void) { if (transport_supported(LinphoneTransportTls)) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + lp_config_set_int(linphone_core_get_config(pauline->lc), "sip", "deliver_imdn", 1); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "deliver_imdn", 1); + linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc)); + linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc)); linphone_core_set_http_proxy_host(marie->lc, "sip.linphone.org"); transfer_message_base2(marie,pauline,FALSE,FALSE,FALSE,FALSE,FALSE); linphone_core_manager_destroy(pauline); From 5ec972c98dad2b92d0e3665f8d4b7422b60f3cb6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 16 Mar 2018 14:32:41 +0100 Subject: [PATCH 18/32] Improve Content-Type and Content-Disposition handling. --- src/CMakeLists.txt | 2 + src/chat/chat-message/chat-message.cpp | 2 +- src/chat/chat-room/chat-room.cpp | 4 +- src/chat/chat-room/client-group-chat-room.cpp | 6 +- src/chat/chat-room/server-group-chat-room-p.h | 2 +- src/conference/local-conference.cpp | 3 +- src/content/content-disposition.cpp | 86 +++++++++++++++++++ src/content/content-disposition.h | 59 +++++++++++++ src/content/content-p.h | 3 +- src/content/content.cpp | 9 +- src/content/content.h | 6 +- src/sal/call-op.cpp | 13 ++- tester/multipart-tester.cpp | 4 +- 13 files changed, 175 insertions(+), 24 deletions(-) create mode 100644 src/content/content-disposition.cpp create mode 100644 src/content/content-disposition.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fbca16af0..ca182139f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,6 +92,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/session/media-session.h conference/session/port-config.h containers/lru-cache.h + content/content-disposition.h content/content-manager.h content/content-p.h content/content-type.h @@ -215,6 +216,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES conference/remote-conference.cpp conference/session/call-session.cpp conference/session/media-session.cpp + content/content-disposition.cpp content/content-manager.cpp content/content-type.cpp content/content.cpp diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 579f44343..eb2d1f029 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -427,7 +427,7 @@ void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { shared_ptr msg = q->getChatRoom()->createChatMessage(); Content *content = new Content(); - content->setContentType("message/imdn+xml"); + content->setContentType(ContentType::Imdn); content->setBody(Imdn::createXml(imdnId, time, imdnType, reason)); msg->addContent(*content); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 1eb64ce00..28106b50d 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -194,12 +194,12 @@ LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessag ); Content content; - if (message->url && strcmp(message->content_type, ContentType::ExternalBody.asString().c_str()) == 0) { + if (message->url && (ContentType(message->content_type) == ContentType::ExternalBody)) { lInfo() << "Received a message with an external body URL " << message->url; content.setContentType(ContentType::FileTransfer); content.setBody(msg->getPrivate()->createFakeFileTransferFromUrl(message->url)); } else { - content.setContentType(message->content_type); + content.setContentType(ContentType(message->content_type)); content.setBodyFromUtf8(message->text ? message->text : ""); } msg->setInternalContent(content); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 496be28ac..29c872d30 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -27,6 +27,8 @@ #include "conference/participant-p.h" #include "conference/remote-conference-p.h" #include "conference/session/call-session-p.h" +#include "content/content-disposition.h" +#include "content/content-type.h" #include "core/core-p.h" #include "logger/logger.h" #include "sal/refer-op.h" @@ -308,8 +310,8 @@ void ClientGroupChatRoom::addParticipants ( Content content; content.setBody(getResourceLists(addressesList)); - content.setContentType("application/resource-lists+xml"); - content.setContentDisposition("recipient-list"); + content.setContentType(ContentType::ResourceLists); + content.setContentDisposition(ContentDisposition::RecipientList); // TODO: Activate compression //if (linphone_core_content_encoding_supported(getCore()->getCCore(), "deflate")) // content.setContentEncoding("deflate"); diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index f31326ad0..911f31f67 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -68,7 +68,7 @@ public: private: struct Message { - Message (const std::string &from, const std::string &contentType, const std::string &text, const SalCustomHeader *salCustomHeaders) + Message (const std::string &from, const ContentType &contentType, const std::string &text, const SalCustomHeader *salCustomHeaders) : fromAddr(from) { content.setContentType(contentType); diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index fe06f6464..847400131 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -18,6 +18,7 @@ */ #include "content/content.h" +#include "content/content-disposition.h" #include "content/content-type.h" #include "handlers/local-conference-event-handler.h" #include "local-conference-p.h" @@ -70,7 +71,7 @@ void LocalConference::removeParticipant (const shared_ptr &pa list LocalConference::parseResourceLists (const Content &content) { if ((content.getContentType() == ContentType::ResourceLists) - && (content.getContentDisposition() == "recipient-list") + && (content.getContentDisposition() == ContentDisposition::RecipientList) ) { istringstream data(content.getBodyAsString()); unique_ptr rl(Xsd::ResourceLists::parseResourceLists( diff --git a/src/content/content-disposition.cpp b/src/content/content-disposition.cpp new file mode 100644 index 000000000..f8dc53ce4 --- /dev/null +++ b/src/content/content-disposition.cpp @@ -0,0 +1,86 @@ +/* + * content-disposition.cpp + * Copyright (C) 2010-2018 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/utils/utils.h" + +#include "content-disposition.h" +#include "object/clonable-object-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ----------------------------------------------------------------------------- + +class ContentDispositionPrivate : public ClonableObjectPrivate { +public: + string disposition; +}; + +// ----------------------------------------------------------------------------- + +const ContentDisposition ContentDisposition::RecipientList("recipient-list"); + +// ----------------------------------------------------------------------------- + +ContentDisposition::ContentDisposition (const string &disposition) : ClonableObject(*new ContentDispositionPrivate) { + L_D(); + d->disposition = disposition; +} + +ContentDisposition::ContentDisposition (const ContentDisposition &other) + : ContentDisposition(other.getPrivate()->disposition) {} + +ContentDisposition &ContentDisposition::operator= (const ContentDisposition &other) { + L_D(); + if (this != &other) { + d->disposition = other.getPrivate()->disposition; + } + return *this; +} + +bool ContentDisposition::operator== (const ContentDisposition &other) const { + L_D(); + return d->disposition == other.getPrivate()->disposition; +} + +bool ContentDisposition::operator!= (const ContentDisposition &other) const { + return !(*this == other); +} + +bool ContentDisposition::isEmpty () const { + L_D(); + return d->disposition.empty(); +} + +bool ContentDisposition::isValid () const { + L_D(); + return !d->disposition.empty(); +} + +string ContentDisposition::asString () const { + L_D(); + if (isValid()) + return d->disposition; + return ""; +} + +LINPHONE_END_NAMESPACE diff --git a/src/content/content-disposition.h b/src/content/content-disposition.h new file mode 100644 index 000000000..c9668d379 --- /dev/null +++ b/src/content/content-disposition.h @@ -0,0 +1,59 @@ +/* + * content-disposition.h + * Copyright (C) 2010-2018 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _L_CONTENT_DISPOSITION_H_ +#define _L_CONTENT_DISPOSITION_H_ + +#include "object/clonable-object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ContentDispositionPrivate; + +class LINPHONE_PUBLIC ContentDisposition : public ClonableObject { +public: + explicit ContentDisposition (const std::string &contentDisposition = ""); + ContentDisposition (const ContentDisposition &other); + + ContentDisposition &operator= (const ContentDisposition &other); + + bool operator== (const ContentDisposition &other) const; + bool operator!= (const ContentDisposition &other) const; + + // Delete these operators to prevent putting complicated content-disposition strings + // in the code. Instead define static const ContentDisposition objects below. + bool operator== (const std::string &other) const = delete; + bool operator!= (const std::string &other) const = delete; + + bool isEmpty () const; + bool isValid () const; + + std::string asString () const; + + static const ContentDisposition RecipientList; + +private: + L_DECLARE_PRIVATE(ContentDisposition); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _L_CONTENT_DISPOSITION_H_ diff --git a/src/content/content-p.h b/src/content/content-p.h index d0b8738c6..167712313 100644 --- a/src/content/content-p.h +++ b/src/content/content-p.h @@ -20,6 +20,7 @@ #ifndef _L_CONTENT_P_H_ #define _L_CONTENT_P_H_ +#include "content-disposition.h" #include "content-type.h" #include "content.h" #include "object/clonable-object-p.h" @@ -32,7 +33,7 @@ class ContentPrivate : public ClonableObjectPrivate { private: std::vector body; ContentType contentType; - std::string contentDisposition; + ContentDisposition contentDisposition; std::string contentEncoding; std::list> headers; diff --git a/src/content/content.cpp b/src/content/content.cpp index c538141cf..aa30503d4 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -110,17 +110,12 @@ void Content::setContentType (const ContentType &contentType) { d->contentType = contentType; } -void Content::setContentType (const string &contentType) { - L_D(); - d->contentType = ContentType(contentType); -} - -const string &Content::getContentDisposition () const { +const ContentDisposition &Content::getContentDisposition () const { L_D(); return d->contentDisposition; } -void Content::setContentDisposition (const string &contentDisposition) { +void Content::setContentDisposition (const ContentDisposition &contentDisposition) { L_D(); d->contentDisposition = contentDisposition; } diff --git a/src/content/content.h b/src/content/content.h index d3be11f51..c570670c5 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -32,6 +32,7 @@ L_DECL_C_STRUCT(LinphoneContent); LINPHONE_BEGIN_NAMESPACE +class ContentDisposition; class ContentType; class ContentPrivate; @@ -49,10 +50,9 @@ public: const ContentType &getContentType () const; void setContentType (const ContentType &contentType); - void setContentType (const std::string &contentType); - const std::string &getContentDisposition () const; - void setContentDisposition (const std::string &contentDisposition); + const ContentDisposition &getContentDisposition () const; + void setContentDisposition (const ContentDisposition &contentDisposition); const std::string &getContentEncoding () const; void setContentEncoding (const std::string &contentEncoding); diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index 5a8583479..a73c021ea 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -24,6 +24,7 @@ #include #include +#include "content/content-disposition.h" #include "content/content-type.h" using namespace std; @@ -102,7 +103,7 @@ belle_sip_header_allow_t *SalCallOp::create_allow(bool_t enable_update) { int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) { ContentType contentType = body.getContentType(); - string contentDisposition = body.getContentDisposition(); + auto contentDisposition = body.getContentDisposition(); string contentEncoding = body.getContentEncoding(); size_t bodySize = body.getBody().size(); @@ -115,8 +116,10 @@ int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) { belle_sip_header_content_type_t *content_type = belle_sip_header_content_type_create(contentType.getType().c_str(), contentType.getSubType().c_str()); belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_type)); } - if (!contentDisposition.empty()) { - belle_sip_header_content_disposition_t *contentDispositionHeader = belle_sip_header_content_disposition_create(contentDisposition.c_str()); + if (contentDisposition.isValid()) { + belle_sip_header_content_disposition_t *contentDispositionHeader = belle_sip_header_content_disposition_create( + contentDisposition.asString().c_str() + ); belle_sip_message_add_header(msg, BELLE_SIP_HEADER(contentDispositionHeader)); } if (!contentEncoding.empty()) @@ -243,7 +246,9 @@ Content SalCallOp::extract_body(belle_sip_message_t *message) { if (type_str && subtype_str) body.setContentType(ContentType(type_str, subtype_str)); if (contentDisposition) - body.setContentDisposition(belle_sip_header_content_disposition_get_content_disposition(contentDisposition)); + body.setContentDisposition( + ContentDisposition(belle_sip_header_content_disposition_get_content_disposition(contentDisposition)) + ); if (length > 0 && body_str) body.setBody(body_str, length); return body; } diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index ad5d731f3..3fdd9073a 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -50,7 +50,7 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool if (first_file_transfer) { char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv"); FileContent *content = new FileContent(); - content->setContentType("video/mkv"); + content->setContentType(ContentType("video/mkv")); content->setFilePath(send_filepath); content->setFileName("sintel_trailer_opus_h264.mkv"); marieMessage->addContent(*content); @@ -65,7 +65,7 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool if (second_file_transfer) { char *send_filepath = bc_tester_res("vcards/vcards.vcf"); FileContent *content = new FileContent(); - content->setContentType("file/vcf"); + content->setContentType(ContentType("file/vcf")); content->setFilePath(send_filepath); content->setFileName("vcards.vcf"); marieMessage->addContent(*content); From 01394ff75ce51cd424ef8aaae2d74d13dc75c1ed Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 16 Mar 2018 14:55:55 +0100 Subject: [PATCH 19/32] Use unique_ptr for StunClient and IceAgent objects. --- src/conference/session/media-session-p.h | 6 +++--- src/conference/session/media-session.cpp | 7 ++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 6ee6ac50a..7b014e138 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -74,7 +74,7 @@ public: void setParams (MediaSessionParams *msp); void setRemoteParams (MediaSessionParams *msp); - IceSession *getIceSession () const { return iceAgent->getIceSession(); } + IceSession *getIceSession () const { return iceAgent ? iceAgent->getIceSession() : nullptr; } SalMediaDescription *getLocalDesc () const { return localDesc; } @@ -284,8 +284,8 @@ private: int mainTextStreamIndex = LINPHONE_CALL_STATS_TEXT; LinphoneNatPolicy *natPolicy = nullptr; - StunClient *stunClient = nullptr; - IceAgent *iceAgent = nullptr; + std::unique_ptr stunClient; + std::unique_ptr iceAgent; // The address family to prefer for RTP path, guessed from signaling path. int af; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 955bcbb4e..32ae463c6 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -1177,7 +1177,7 @@ string MediaSessionPrivate::getPublicIpForStream (int streamIndex) { void MediaSessionPrivate::runStunTestsIfNeeded () { L_Q(); if (linphone_nat_policy_stun_enabled(natPolicy) && !(linphone_nat_policy_ice_enabled(natPolicy) || linphone_nat_policy_turn_enabled(natPolicy))) { - stunClient = new StunClient(q->getCore()); + stunClient = makeUnique(q->getCore()); int ret = stunClient->run(mediaPorts[mainAudioStreamIndex].rtpPort, mediaPorts[mainVideoStreamIndex].rtpPort, mediaPorts[mainTextStreamIndex].rtpPort); if (ret >= 0) pingTime = ret; @@ -3939,7 +3939,7 @@ MediaSession::MediaSession (const shared_ptr &core, shared_ptrsetPortConfig(d->mainTextStreamIndex, make_pair(minPort, maxPort)); memset(d->sessions, 0, sizeof(d->sessions)); - d->iceAgent = new IceAgent(*this); + d->iceAgent = makeUnique(*this); lInfo() << "New MediaSession [" << this << "] initialized (LinphoneCore version: " << linphone_core_get_version() << ")"; } @@ -3957,9 +3957,6 @@ MediaSession::~MediaSession () { linphone_call_stats_unref(d->textStats); if (d->natPolicy) linphone_nat_policy_unref(d->natPolicy); - if (d->stunClient) - delete d->stunClient; - delete d->iceAgent; if (d->localDesc) sal_media_description_unref(d->localDesc); if (d->biggestDesc) From 0cf7325c4b53921d1b6a61ac486149beea77516d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 16 Mar 2018 15:58:48 +0100 Subject: [PATCH 20/32] Fix memory leak with proxy config routes. --- coreapi/proxy.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 067b95790..bad2e9aa4 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1228,7 +1228,10 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc CONFIGURE_STRING_VALUE(cfg,config,key,identity,"reg_identity") CONFIGURE_STRING_VALUE(cfg,config,key,server_addr,"reg_proxy") - linphone_proxy_config_set_routes(cfg, linphone_config_get_string_list(config, key, "reg_route", NULL)); + bctbx_list_t *routes = linphone_config_get_string_list(config, key, "reg_route", NULL); + linphone_proxy_config_set_routes(cfg, routes); + if (routes) + bctbx_list_free_with_data(routes, (bctbx_list_free_func)bctbx_free); CONFIGURE_STRING_VALUE(cfg,config,key,realm,"realm") From 3a0bcc675a2ad5ef205297cfb3a79a943cb339c6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 16 Mar 2018 16:55:51 +0100 Subject: [PATCH 21/32] Some more improvements to Content-Type and Content-Disposition handling. --- include/linphone/utils/utils.h | 2 ++ src/content/content-disposition.cpp | 31 ++++++++++++++++++++++++----- src/content/content-disposition.h | 4 ++++ src/content/content-type.cpp | 8 ++++---- src/utils/utils.cpp | 6 ++++++ 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index 7200ec935..e13c89889 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -107,6 +107,8 @@ namespace Utils { return str ? str : ""; } + LINPHONE_PUBLIC std::string trim (const std::string &str); + template LINPHONE_PUBLIC const T &getEmptyConstRefObject () { static const T object; diff --git a/src/content/content-disposition.cpp b/src/content/content-disposition.cpp index f8dc53ce4..ccaf7da15 100644 --- a/src/content/content-disposition.cpp +++ b/src/content/content-disposition.cpp @@ -33,33 +33,40 @@ LINPHONE_BEGIN_NAMESPACE class ContentDispositionPrivate : public ClonableObjectPrivate { public: string disposition; + string parameter; }; // ----------------------------------------------------------------------------- const ContentDisposition ContentDisposition::RecipientList("recipient-list"); +const ContentDisposition ContentDisposition::RecipientListHistory("recipient-list-history; handling=optional"); // ----------------------------------------------------------------------------- ContentDisposition::ContentDisposition (const string &disposition) : ClonableObject(*new ContentDispositionPrivate) { L_D(); - d->disposition = disposition; + size_t posParam = disposition.find(";"); + d->disposition = Utils::trim(disposition.substr(0, posParam)); + if (posParam != string::npos) + setParameter(Utils::trim(disposition.substr(posParam + 1))); } ContentDisposition::ContentDisposition (const ContentDisposition &other) - : ContentDisposition(other.getPrivate()->disposition) {} + : ContentDisposition(other.asString()) {} ContentDisposition &ContentDisposition::operator= (const ContentDisposition &other) { L_D(); if (this != &other) { d->disposition = other.getPrivate()->disposition; + setParameter(other.getParameter()); } return *this; } bool ContentDisposition::operator== (const ContentDisposition &other) const { L_D(); - return d->disposition == other.getPrivate()->disposition; + return d->disposition == other.getPrivate()->disposition + && getParameter() == other.getParameter(); } bool ContentDisposition::operator!= (const ContentDisposition &other) const { @@ -76,10 +83,24 @@ bool ContentDisposition::isValid () const { return !d->disposition.empty(); } +const string &ContentDisposition::getParameter () const { + L_D(); + return d->parameter; +} + +void ContentDisposition::setParameter (const string ¶meter) { + L_D(); + d->parameter = parameter; +} + string ContentDisposition::asString () const { L_D(); - if (isValid()) - return d->disposition; + if (isValid()) { + string asString = d->disposition; + if (!d->parameter.empty()) + asString += ";" + d->parameter; + return asString; + } return ""; } diff --git a/src/content/content-disposition.h b/src/content/content-disposition.h index c9668d379..6f2fcc9ca 100644 --- a/src/content/content-disposition.h +++ b/src/content/content-disposition.h @@ -46,9 +46,13 @@ public: bool isEmpty () const; bool isValid () const; + const std::string &getParameter () const; + void setParameter (const std::string ¶meter); + std::string asString () const; static const ContentDisposition RecipientList; + static const ContentDisposition RecipientListHistory; private: L_DECLARE_PRIVATE(ContentDisposition); diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 97a0ad488..78c356af6 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -56,20 +56,20 @@ ContentType::ContentType (const string &contentType) : ClonableObject(*new Conte L_D(); size_t pos = contentType.find('/'); - size_t posParam = contentType.find("; "); + size_t posParam = contentType.find(";"); size_t end = contentType.length(); if (pos == string::npos) return; - if (setType(contentType.substr(0, pos))) { + if (setType(Utils::trim(contentType.substr(0, pos)))) { if (posParam != string::npos) end = posParam; - if (!setSubType(contentType.substr(pos + 1, end - (pos + 1)))) + if (!setSubType(Utils::trim(contentType.substr(pos + 1, end - (pos + 1))))) d->type.clear(); } if (posParam != string::npos) - setParameter(contentType.substr(posParam + 2)); // We remove the blankspace after the ;. + setParameter(Utils::trim(contentType.substr(posParam + 1))); } ContentType::ContentType (const string &type, const string &subType) : ClonableObject(*new ContentTypePrivate) { diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index c9d1b8442..eb5ba94d2 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -175,6 +175,12 @@ char *Utils::utf8ToChar (uint32_t ic) { return result; } +string Utils::trim (const string &str) { + auto itFront = find_if_not(str.begin(), str.end(), [] (int c) { return isspace(c); }); + auto itBack = find_if_not(str.rbegin(), str.rend(), [] (int c) { return isspace(c); }).base(); + return (itBack <= itFront ? string() : string(itFront, itBack)); +} + // ----------------------------------------------------------------------------- tm Utils::getTimeTAsTm (time_t time) { From 6c7c56271a261af359a587a06916d8309f47003f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 17 Mar 2018 12:05:49 +0100 Subject: [PATCH 22/32] Implement deferred ICE reinvite response when the ICE session isn't yet completed. --- src/conference/session/call-session-p.h | 1 + src/conference/session/call-session.cpp | 7 +++--- src/conference/session/media-session-p.h | 2 +- src/conference/session/media-session.cpp | 26 +++++++++++++++++++- src/nat/ice-agent.cpp | 31 ++++++++++++++++++++++++ src/nat/ice-agent.h | 5 ++++ 6 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index fc62e4e43..d8dbed101 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -134,6 +134,7 @@ protected: bool broken = false; bool deferIncomingNotification = false; bool deferUpdate = false; + bool deferUpdateInternal = false; bool needLocalIpRefresh = false; bool nonOpError = false; /* Set when the LinphoneErrorInfo was set at higher level than sal */ bool notifyRinging = true; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 2aad40f1a..2b6d0da8d 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -467,9 +467,10 @@ void CallSessionPrivate::updated (bool isUpdate) { void CallSessionPrivate::updatedByRemote () { L_Q(); setState(CallSession::State::UpdatedByRemote,"Call updated by remote"); - if (deferUpdate) { - if (state == CallSession::State::UpdatedByRemote) - lInfo() << "CallSession [" << q << "]: UpdatedByRemoted was signaled but defered. LinphoneCore expects the application to call CallSession::acceptUpdate() later"; + if (deferUpdate || deferUpdateInternal) { + if (state == CallSession::State::UpdatedByRemote && !deferUpdateInternal){ + lInfo() << "CallSession [" << q << "]: UpdatedByRemoted was signaled but defered. LinphoneCore expects the application to call linphone_call_accept_update() later"; + } } else { if (state == CallSession::State::UpdatedByRemote) q->acceptUpdate(nullptr); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 7b014e138..7013e7b18 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -254,7 +254,6 @@ private: int sendDtmf (); void stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); - private: static const std::string ecStateStore; static const int ecStateMaxLen; @@ -325,6 +324,7 @@ private: bool automaticallyPaused = false; bool pausedByApp = false; bool recordActive = false; + bool incomingIceReinvitePending = false; std::string onHoldFile; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 32ae463c6..c240343f7 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -382,6 +382,8 @@ void MediaSessionPrivate::updated (bool isUpdate) { CallSessionPrivate::updated(isUpdate); } + + void MediaSessionPrivate::updating (bool isUpdate) { L_Q(); SalMediaDescription *rmd = op->get_remote_media_description(); @@ -702,6 +704,10 @@ shared_ptr MediaSessionPrivate::getMe () const { void MediaSessionPrivate::setState (CallSession::State newState, const string &message) { L_Q(); + SalMediaDescription *rmd; + + lInfo()<<"MediaSessionPrivate::setState"; + /* Take a ref on the session otherwise it might get destroyed during the call to setState */ shared_ptr sessionRef = q->getSharedFromThis(); if ((newState != state) && (newState != CallSession::State::StreamsRunning)) @@ -709,6 +715,21 @@ void MediaSessionPrivate::setState (CallSession::State newState, const string &m CallSessionPrivate::setState(newState, message); if (listener) listener->onCallSessionStateChangedForReporting(q->getSharedFromThis()); + switch(newState){ + case CallSession::State::UpdatedByRemote: + /*Handle specifically the case of an incoming ICE-concluded reINVITE*/ + lInfo()<<"Checking for ICE reINVITE"; + rmd = op->get_remote_media_description(); + if (iceAgent && rmd != nullptr && iceAgent->checkIceReinviteNeedsDeferedResponse(rmd)){ + deferUpdate = true; + deferUpdateInternal = true; + incomingIceReinvitePending = true; + lInfo()<<"CallSession [" << q << "]: ICE reinvite received, but one or more check-lists are not completed. Response will be sent later, when ICE has completed"; + } + break; + default: + break; + } } // ----------------------------------------------------------------------------- @@ -2191,11 +2212,14 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { OrtpEventData *evd = ortp_event_get_data(ev); if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { if (iceAgent->hasCompletedCheckList()) { - /* At least one ICE session has succeeded, so perform a call update */ + /* The ICE session has succeeded, so perform a call update */ if (iceAgent->isControlling() && q->getCurrentParams()->getPrivate()->getUpdateCallWhenIceCompleted()) { MediaSessionParams newParams(*getParams()); newParams.getPrivate()->setInternalCallUpdate(true); q->update(&newParams); + }else if (!iceAgent->isControlling() && incomingIceReinvitePending){ + q->acceptUpdate(nullptr); + incomingIceReinvitePending = false; } startDtlsOnAllStreams(); } diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index 4c98340fd..726312f9f 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -738,4 +738,35 @@ void IceAgent::updateIceStateInCallStatsForStream (LinphoneCallStats *stats, Ice } } +bool IceAgent::checkIceReinviteNeedsDeferedResponse(SalMediaDescription *md){ + int i,j; + IceCheckList *cl; + + if (!iceSession) return false; + + if (ice_session_state(iceSession) != IS_Running ) return false; + + for (i = 0; i < md->nb_streams; i++) { + SalStreamDescription *stream = &md->streams[i]; + cl = ice_session_check_list(iceSession, i); + + if (cl==NULL) continue; + if (stream->ice_mismatch == TRUE) { + return false; + } + if (stream->rtp_port == 0) { + continue; + } + + if (ice_check_list_state(cl) != ICL_Running) continue; + + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) { + const SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[j]; + if (remote_candidate->addr[0] != '\0') return true; + + } + } + return false; +} + LINPHONE_END_NAMESPACE diff --git a/src/nat/ice-agent.h b/src/nat/ice-agent.h index 3af487df1..0e702010b 100644 --- a/src/nat/ice-agent.h +++ b/src/nat/ice-agent.h @@ -66,6 +66,11 @@ public: void updateFromRemoteMediaDescription (const SalMediaDescription *localDesc, const SalMediaDescription *remoteDesc, bool isOffer); void updateIceStateInCallStats (); void updateLocalMediaDescriptionFromIce (SalMediaDescription *desc); + /* + * Checks if an incoming offer with ICE needs a delayed answer, because the ice session hasn't completed yet with + * connecvity checks. + */ + bool checkIceReinviteNeedsDeferedResponse(SalMediaDescription *md); private: void addLocalIceCandidates (int family, const char *addr, IceCheckList *audioCl, IceCheckList *videoCl, IceCheckList *textCl); From 5a985ca79d9bf8018f0c191fdf27ef7c4ebde597 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 14 Sep 2017 13:08:30 +0200 Subject: [PATCH 23/32] update proxy config etag on status PublishOk. It allows PUBLISH to be consistent over network state changes, avoiding orphan tuples to remain server side. --- coreapi/proxy.c | 32 +++++-- tester/presence_server_tester.c | 149 ++++++++++++++++++++++++++++++++ tester/presence_tester.c | 101 +--------------------- 3 files changed, 174 insertions(+), 108 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index bad2e9aa4..e9a3641a4 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -826,6 +826,13 @@ LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *pr return NULL; } +void linphone_proxy_config_set_etag(LinphoneProxyConfig *cfg,const char* sip_etag) { + if (cfg->sip_etag) ms_free(cfg->sip_etag); + if (sip_etag) + cfg->sip_etag = ms_strdup(sip_etag); + else + cfg->sip_etag = NULL; +} /** * Commits modification made to the proxy configuration. **/ @@ -867,11 +874,7 @@ LinphoneStatus linphone_proxy_config_done(LinphoneProxyConfig *cfg) ms_message("Publish params have changed on proxy config [%p]",cfg); if (cfg->presence_publish_event) { if (cfg->publish) { - const char * sip_etag = linphone_event_get_custom_header(cfg->presence_publish_event, "SIP-ETag"); - if (sip_etag) { - if (cfg->sip_etag) ms_free(cfg->sip_etag); - cfg->sip_etag = ms_strdup(sip_etag); - } + linphone_proxy_config_set_etag(cfg, linphone_event_get_custom_header(cfg->presence_publish_event, "SIP-ETag")); } /*publish is terminated*/ linphone_event_terminate(cfg->presence_publish_event); @@ -1542,9 +1545,22 @@ void linphone_proxy_config_set_nat_policy(LinphoneProxyConfig *cfg, LinphoneNatP } void linphone_proxy_config_notify_publish_state_changed(LinphoneProxyConfig *cfg, LinphonePublishState state) { - if ((cfg->presence_publish_event != NULL) && ((state == LinphonePublishCleared) || (state == LinphonePublishError))) { - linphone_event_unref(cfg->presence_publish_event); - cfg->presence_publish_event = NULL; + + if (cfg->presence_publish_event != NULL) { + switch (state) { + case LinphonePublishCleared: + linphone_proxy_config_set_etag(cfg,NULL); + case LinphonePublishError: + linphone_event_unref(cfg->presence_publish_event); + cfg->presence_publish_event = NULL; + break; + case LinphonePublishOk: + linphone_proxy_config_set_etag(cfg,linphone_event_get_custom_header(cfg->presence_publish_event, "SIP-ETag")); + break; + default: + break; + + } } } diff --git a/tester/presence_server_tester.c b/tester/presence_server_tester.c index 5f9f0bf7d..62bb8a364 100644 --- a/tester/presence_server_tester.c +++ b/tester/presence_server_tester.c @@ -1571,8 +1571,157 @@ static void extended_notify_sub_unsub_sub2(void) { bctbx_list_free(lcs); } +static void simple_publish_with_expire(int expires) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneProxyConfig* proxy; + LinphonePresenceModel* presence; + LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); + + linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed); + _linphone_core_add_callbacks(marie->lc, cbs, TRUE); + linphone_core_cbs_unref(cbs); + + proxy = linphone_core_get_default_proxy_config(marie->lc); + linphone_proxy_config_edit(proxy); + if (expires > 0) { + linphone_proxy_config_set_publish_expires(proxy,expires); + } + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_done(proxy); + + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1)); + + presence = linphone_presence_model_new(); + linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed); + linphone_core_set_presence_model(marie->lc,presence); + linphone_presence_model_unref(presence); + + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2)); + + linphone_proxy_config_edit(proxy); + linphone_proxy_config_done(proxy); + /*make sure no publish is sent*/ + BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3,2000)); + + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,FALSE); + linphone_proxy_config_done(proxy); + + + /*fixme PUBLISH state machine is too simple, clear state should only be propagated at API level when 200ok is received*/ + /*BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));*/ + wait_for_until(marie->lc,marie->lc,NULL,0,2000); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishCleared,1)); + + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_done(proxy); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3)); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,3)); + + linphone_proxy_config_edit(proxy); + linphone_proxy_config_set_publish_expires(proxy, linphone_proxy_config_get_publish_expires(proxy)+1); + linphone_proxy_config_done(proxy); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,4)); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,4)); + + linphone_core_manager_stop(marie); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,3,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/ + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,4,int,"%i"); + linphone_core_manager_destroy(marie); +} + +static void simple_publish(void) { + simple_publish_with_expire(-1); +} + +static void publish_with_expires(void) { + simple_publish_with_expire(2); +} + +static void publish_with_dual_identity(void) { + LinphoneCoreManager* pauline = linphone_core_manager_new("multi_account_rc"); + const bctbx_list_t* proxies; + LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); + + linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed); + _linphone_core_add_callbacks(pauline->lc, cbs, TRUE); + linphone_core_cbs_unref(cbs); + + for (proxies = linphone_core_get_proxy_config_list(pauline->lc); proxies!=NULL; proxies = proxies->next) { + LinphoneProxyConfig *proxy = (LinphoneProxyConfig *) proxies->data; + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_done(proxy); + } + + BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishProgress,4)); + BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishOk,4)); + + linphone_core_manager_stop(pauline); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishCleared,4,int,"%i"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishOk,4,int,"%i"); + linphone_core_manager_destroy(pauline); + +} +static void publish_with_network_state_changes(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneFriend* marie_as_friend = linphone_core_create_friend_with_address(pauline->lc, get_identity(marie)); + + LinphoneProxyConfig* proxy; + LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); + + linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed); + _linphone_core_add_callbacks(marie->lc, cbs,TRUE); + linphone_core_cbs_unref(cbs); + + linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL); + linphone_core_set_user_agent(marie->lc, "full-presence-support-bypass", NULL); + + proxy = linphone_core_get_default_proxy_config(marie->lc); + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_done(proxy); + + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1)); + + linphone_core_set_network_reachable(marie->lc, FALSE); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationNone,1)); + BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2,1000)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,1,int,"%i"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishError,0,int,"%i"); + + linphone_core_set_network_reachable(marie->lc, TRUE); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2)); + + + + linphone_core_manager_stop(marie); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,1,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/ + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,2,int,"%i"); + linphone_core_manager_destroy(marie); + + /*make sure there is no remaining publish caused by network failure*/ + linphone_core_set_user_agent(pauline->lc, "full-presence-support", NULL); + linphone_core_set_user_agent(pauline->lc, "full-presence-support-bypass", NULL); + linphone_core_add_friend(pauline->lc, marie_as_friend); + + BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePresenceActivityAway,1)); + linphone_friend_unref(marie_as_friend); + linphone_core_manager_destroy(pauline); + +} test_t presence_server_tests[] = { + TEST_NO_TAG("Simple Publish", simple_publish), + TEST_NO_TAG("Publish with 2 identities", publish_with_dual_identity), + TEST_NO_TAG("Simple Publish with expires", publish_with_expires), + TEST_ONE_TAG("Publish with network state changes", publish_with_network_state_changes, "presence"), TEST_NO_TAG("Simple", simple), TEST_NO_TAG("Fast activity change", fast_activity_change), TEST_NO_TAG("Forked subscribe with late publish", test_forked_subscribe_notify_publish), diff --git a/tester/presence_tester.c b/tester/presence_tester.c index e53db19ed..67a35c0be 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -142,101 +142,6 @@ void notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *l counters->number_of_NotifyPresenceReceivedForUriOrTel++; } -static void simple_publish_with_expire(int expires) { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneProxyConfig* proxy; - LinphonePresenceModel* presence; - LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); - - linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed); - _linphone_core_add_callbacks(marie->lc, cbs, TRUE); - linphone_core_cbs_unref(cbs); - - proxy = linphone_core_get_default_proxy_config(marie->lc); - linphone_proxy_config_edit(proxy); - if (expires > 0) { - linphone_proxy_config_set_publish_expires(proxy,expires); - } - linphone_proxy_config_enable_publish(proxy,TRUE); - linphone_proxy_config_done(proxy); - - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1)); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1)); - - presence = linphone_presence_model_new(); - linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed); - linphone_core_set_presence_model(marie->lc,presence); - linphone_presence_model_unref(presence); - - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2)); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2)); - - linphone_proxy_config_edit(proxy); - linphone_proxy_config_done(proxy); - /*make sure no publish is sent*/ - BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3,2000)); - - linphone_proxy_config_edit(proxy); - linphone_proxy_config_enable_publish(proxy,FALSE); - linphone_proxy_config_done(proxy); - - - /*fixme PUBLISH state machine is too simple, clear state should only be propagated at API level when 200ok is received*/ - /*BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));*/ - wait_for_until(marie->lc,marie->lc,NULL,0,2000); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishCleared,1)); - - linphone_proxy_config_edit(proxy); - linphone_proxy_config_enable_publish(proxy,TRUE); - linphone_proxy_config_done(proxy); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3)); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,3)); - - linphone_proxy_config_edit(proxy); - linphone_proxy_config_set_publish_expires(proxy, linphone_proxy_config_get_publish_expires(proxy)+1); - linphone_proxy_config_done(proxy); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,4)); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,4)); - - linphone_core_manager_stop(marie); - BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,3,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/ - BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,4,int,"%i"); - linphone_core_manager_destroy(marie); -} - -static void simple_publish(void) { - simple_publish_with_expire(-1); -} - -static void publish_with_expires(void) { - simple_publish_with_expire(2); -} - -static void publish_with_dual_identity(void) { - LinphoneCoreManager* pauline = linphone_core_manager_new("multi_account_rc"); - const bctbx_list_t* proxies; - LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); - - linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed); - _linphone_core_add_callbacks(pauline->lc, cbs, TRUE); - linphone_core_cbs_unref(cbs); - - for (proxies = linphone_core_get_proxy_config_list(pauline->lc); proxies!=NULL; proxies = proxies->next) { - LinphoneProxyConfig *proxy = (LinphoneProxyConfig *) proxies->data; - linphone_proxy_config_edit(proxy); - linphone_proxy_config_enable_publish(proxy,TRUE); - linphone_proxy_config_done(proxy); - } - - BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishProgress,4)); - BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishOk,4)); - - linphone_core_manager_stop(pauline); - BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishCleared,4,int,"%i"); - BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishOk,4,int,"%i"); - linphone_core_manager_destroy(pauline); - -} static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { stats initial_caller=caller_mgr->stat; stats initial_callee=callee_mgr->stat; @@ -640,14 +545,10 @@ test_t presence_tests[] = { TEST_ONE_TAG("Simple Subscribe", simple_subscribe,"presence"), TEST_ONE_TAG("Simple Subscribe with early NOTIFY", simple_subscribe_with_early_notify,"presence"), TEST_NO_TAG("Simple Subscribe with friend from rc", simple_subscribe_with_friend_from_rc), - TEST_NO_TAG("Simple Publish", simple_publish), - TEST_NO_TAG("Publish with 2 identities", publish_with_dual_identity), - TEST_NO_TAG("Simple Publish with expires", publish_with_expires), - TEST_ONE_TAG("Publish with network state changes", publish_with_network_state_changes, "presence"), /*TEST_ONE_TAG("Call with presence", call_with_presence, "LeaksMemory"),*/ TEST_NO_TAG("Unsubscribe while subscribing", unsubscribe_while_subscribing), TEST_NO_TAG("Presence information", presence_information), - TEST_NO_TAG("App managed presence failure", subscribe_failure_handle_by_app), + TEST_ONE_TAG("App managed presence failure", subscribe_failure_handle_by_app, "LeaksMemory"), TEST_NO_TAG("Presence SUBSCRIBE forked", subscribe_presence_forked), TEST_NO_TAG("Presence SUBSCRIBE expired", subscribe_presence_expired), }; From dc4f2a155b37174912070d7e60135ada60659317 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 14 Sep 2017 15:03:46 +0200 Subject: [PATCH 24/32] Switch sip transports used by multi call testers to full tcp in case of IPV6 --- tester/call_multi_tester.c | 44 +++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/tester/call_multi_tester.c b/tester/call_multi_tester.c index 1889a3683..da58f20eb 100644 --- a/tester/call_multi_tester.c +++ b/tester/call_multi_tester.c @@ -30,7 +30,17 @@ #define unlink _unlink #endif - +/* + * With IPV6, Flexisip automatically switches to TCP, so it's no more possible to really have Laure configured with UDP + * Anyway for IPV4, it's still a good opportunity to test UDP. + */ +static const char* get_laure_rc(void) { + if (liblinphone_tester_ipv6_available()) { + return "laure_tcp_rc"; + } else { + return "laure_rc_udp"; + } +} static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { bctbx_list_t *iterator; bctbx_list_t* lcs; @@ -45,7 +55,7 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { linphone_core_remove_supported_tag(pauline->lc,"gruu"); linphone_core_manager_start(pauline,TRUE); LinphoneCoreManager *laure = ms_new0(LinphoneCoreManager, 1); - linphone_core_manager_init(laure, "laure_rc_udp", NULL); + linphone_core_manager_init(laure, get_laure_rc(), NULL); linphone_core_remove_supported_tag(laure->lc,"gruu"); linphone_core_manager_start(laure, TRUE); LinphoneCallParams *laure_params=linphone_core_create_call_params(laure->lc, NULL); @@ -187,7 +197,7 @@ static void second_call_allowed_if_not_using_audio(void){ static void incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallState state) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); bctbx_list_t* lcs; LinphoneCallParams *laure_params=linphone_core_create_call_params(laure->lc, NULL); LinphoneCallParams *marie_params=linphone_core_create_call_params(marie->lc, NULL); @@ -385,7 +395,7 @@ end: static void simple_conference(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); simple_conference_base(marie,pauline,laure, NULL, FALSE); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -396,7 +406,7 @@ static void simple_conference(void) { static void simple_conference_from_scratch(void){ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); LinphoneConference *conf; LinphoneConferenceParams *conf_params; LinphoneCall *pauline_call, *laure_call; @@ -469,7 +479,7 @@ static void simple_conference_from_scratch(void){ static void simple_encrypted_conference_with_ice(LinphoneMediaEncryption mode) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); if (linphone_core_media_encryption_supported(marie->lc,mode)) { linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); @@ -504,7 +514,7 @@ static void simple_zrtp_conference_with_ice(void) { static void conference_hang_up_call_on_hold(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new("laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new(get_laure_rc()); simple_conference_base(marie, pauline, laure, NULL, TRUE); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -514,7 +524,7 @@ static void conference_hang_up_call_on_hold(void) { static void simple_call_transfer(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); LinphoneCall* pauline_called_by_marie; LinphoneCall *marie_calling_pauline; LinphoneCall *marie_calling_laure; @@ -579,7 +589,7 @@ end: static void unattended_call_transfer(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); LinphoneCall* pauline_called_by_marie; char* laure_identity=linphone_address_as_string(laure->identity); @@ -668,7 +678,7 @@ static void unattended_call_transfer_with_error(void) { static void call_transfer_existing_call(bool_t outgoing_call) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); LinphoneCall* marie_call_pauline; LinphoneCall* pauline_called_by_marie; LinphoneCall* marie_call_laure; @@ -768,7 +778,7 @@ static void call_transfer_existing_call_incoming_call(void) { static void call_transfer_existing_ringing_call(void) { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); - LinphoneCoreManager *laure = linphone_core_manager_new("laure_rc_udp"); + LinphoneCoreManager *laure = linphone_core_manager_new(get_laure_rc()); LinphoneCall *marie_call_pauline; LinphoneCall *pauline_called_by_marie; LinphoneCall *marie_call_laure; @@ -934,7 +944,7 @@ end: static void eject_from_3_participants_local_conference(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); eject_from_3_participants_conference(marie, pauline, laure, NULL); @@ -946,7 +956,7 @@ static void eject_from_3_participants_local_conference(void) { static void eject_from_4_participants_conference(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); LinphoneCoreManager* michelle = linphone_core_manager_new( "michelle_rc_udp"); int timeout_ms = 5000; stats initial_laure_stat; @@ -1038,7 +1048,7 @@ end: void simple_remote_conference(void) { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); - LinphoneCoreManager *laure = linphone_core_manager_new("laure_rc_udp"); + LinphoneCoreManager *laure = linphone_core_manager_new(get_laure_rc()); LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc", TRUE); LpConfig *marie_config = linphone_core_get_config(marie->lc); LinphoneProxyConfig *focus_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)focus)->lc); @@ -1064,7 +1074,7 @@ void simple_remote_conference(void) { void simple_remote_conference_shut_down_focus(void) { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); - LinphoneCoreManager *laure = linphone_core_manager_new("laure_rc_udp"); + LinphoneCoreManager *laure = linphone_core_manager_new(get_laure_rc()); LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc", FALSE); LpConfig *marie_config = linphone_core_get_config(marie->lc); LinphoneProxyConfig *focus_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)focus)->lc); @@ -1090,7 +1100,7 @@ void simple_remote_conference_shut_down_focus(void) { void eject_from_3_participants_remote_conference(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc", TRUE); LpConfig *marie_config = linphone_core_get_config(marie->lc); LinphoneProxyConfig *focus_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)focus)->lc); @@ -1116,7 +1126,7 @@ void eject_from_3_participants_remote_conference(void) { void do_not_stop_ringing_when_declining_one_of_two_incoming_calls(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp"); + LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc()); LinphoneCall* pauline_called_by_marie; LinphoneCall* pauline_called_by_laure; LinphoneCallParams *laure_params=linphone_core_create_call_params(laure->lc, NULL); From 11354f2cf6aab3640e584bf00cfea3192d787d62 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 14 Sep 2017 21:08:59 +0200 Subject: [PATCH 25/32] fix crash in linphonecsh --- console/shell.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/console/shell.c b/console/shell.c index f80a15378..8cf1d6c09 100644 --- a/console/shell.c +++ b/console/shell.c @@ -156,11 +156,11 @@ static char *argv_to_line(int argc, char *argv[]) { } #endif -#define MAX_ARGS 10 +#define MAX_ARGS 20 #ifndef _WIN32 static void spawn_linphonec(int argc, char *argv[]){ - char * args[MAX_ARGS]; + char * args[MAX_ARGS+1]; int i,j; pid_t pid; j=0; @@ -168,10 +168,10 @@ static void spawn_linphonec(int argc, char *argv[]){ args[j++]="--pipe"; args[j++]="-c"; args[j++]="/dev/null"; - for(i=0;i Date: Thu, 14 Sep 2017 21:16:05 +0200 Subject: [PATCH 26/32] fix crash in linphonec --- console/linphonec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/linphonec.c b/console/linphonec.c index ca556536b..b786288b4 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -975,7 +975,7 @@ linphonec_idle_call () linphone_core_iterate(opm); if (answer_call){ fprintf (stdout, "-------auto answering to call-------\n" ); - linphone_core_accept_call(opm,NULL); + linphone_core_accept_call(opm, linphone_core_get_current_call(opm)); answer_call=FALSE; } /* auto call handling */ From 533f47c7a9cb04651a24ce589566cac09ac8218c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 19 Mar 2018 16:24:20 +0100 Subject: [PATCH 27/32] Indicate mediastreamer2 a maximum output bitrate, so that rate control algorithm can use it. --- src/conference/session/media-session.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index c240343f7..d4a4c873f 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -2660,7 +2660,7 @@ void MediaSessionPrivate::startAudioStream (CallSession::State targetState, bool if (playcard) { ms_snd_card_set_stream_type(playcard, MS_SND_CARD_STREAM_VOICE); } - + media_stream_set_max_network_bitrate(&audioStream->ms, linphone_core_get_upload_bandwidth(q->getCore()->getCCore()) * 1000); bool useEc = captcard && linphone_core_echo_cancellation_enabled(q->getCore()->getCCore()); audio_stream_enable_echo_canceller(audioStream, useEc); if (playcard && (stream->max_rate > 0)) @@ -2899,6 +2899,7 @@ void MediaSessionPrivate::startVideoStream (CallSession::State targetState) { getCurrentParams()->getPrivate()->setUsedVideoCodec(rtp_profile_get_payload(videoProfile, usedPt)); getCurrentParams()->enableVideo(true); rtp_session_enable_rtcp_mux(videoStream->ms.sessions.rtp_session, vstream->rtcp_mux); + media_stream_set_max_network_bitrate(&videoStream->ms, linphone_core_get_upload_bandwidth(q->getCore()->getCCore()) * 1000); if (q->getCore()->getCCore()->video_conf.preview_vsize.width != 0) video_stream_set_preview_size(videoStream, q->getCore()->getCCore()->video_conf.preview_vsize); video_stream_set_fps(videoStream, linphone_core_get_preferred_framerate(q->getCore()->getCCore())); From 174f5f570a9bfd43d3b946c3379f851ad736b1ea Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 19 Mar 2018 16:35:05 +0100 Subject: [PATCH 28/32] fix compilation issue --- tester/presence_tester.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 67a35c0be..18a29902b 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -211,40 +211,6 @@ static void subscribe_failure_handle_by_app(void) { linphone_core_manager_destroy(pauline); } -static void publish_with_network_state_changes(void) { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneProxyConfig* proxy; - LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); - - linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed); - _linphone_core_add_callbacks(marie->lc, cbs,TRUE); - linphone_core_cbs_unref(cbs); - - proxy = linphone_core_get_default_proxy_config(marie->lc); - linphone_proxy_config_edit(proxy); - linphone_proxy_config_enable_publish(proxy,TRUE); - linphone_proxy_config_done(proxy); - - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1)); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1)); - - linphone_core_set_network_reachable(marie->lc, FALSE); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationNone,1)); - BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2,1000)); - BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,1,int,"%i"); - BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishError,0,int,"%i"); - - linphone_core_set_network_reachable(marie->lc, TRUE); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2)); - BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2)); - - - linphone_core_manager_stop(marie); - BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,1,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/ - BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,2,int,"%i"); - linphone_core_manager_destroy(marie); -} - static void simple_subscribe(void) { LinphoneCoreManager* marie = presence_linphone_core_manager_new("marie"); LinphoneCoreManager* pauline = presence_linphone_core_manager_new("pauline"); From 4eb83a7b82b6dc9d474ca2901c0b37f75cfe185a Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 19 Mar 2018 16:41:06 +0100 Subject: [PATCH 29/32] remove LeaksMemory from tester presence/App managed presence failure --- tester/presence_tester.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 18a29902b..2eb4c931d 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -514,7 +514,7 @@ test_t presence_tests[] = { /*TEST_ONE_TAG("Call with presence", call_with_presence, "LeaksMemory"),*/ TEST_NO_TAG("Unsubscribe while subscribing", unsubscribe_while_subscribing), TEST_NO_TAG("Presence information", presence_information), - TEST_ONE_TAG("App managed presence failure", subscribe_failure_handle_by_app, "LeaksMemory"), + TEST_ONE_TAG("App managed presence failure", subscribe_failure_handle_by_app,"presence"), TEST_NO_TAG("Presence SUBSCRIBE forked", subscribe_presence_forked), TEST_NO_TAG("Presence SUBSCRIBE expired", subscribe_presence_expired), }; From 29f9de93a30c6f7278ae4c0356fa7a4303832c2c Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Mon, 18 Sep 2017 10:47:59 +0200 Subject: [PATCH 30/32] Fix no break error in proxy.c --- coreapi/proxy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index e9a3641a4..03213da1e 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -20,6 +20,7 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) #include +#include #include "linphone/core_utils.h" #include "linphone/core.h" #include "linphone/lpconfig.h" @@ -1545,11 +1546,12 @@ void linphone_proxy_config_set_nat_policy(LinphoneProxyConfig *cfg, LinphoneNatP } void linphone_proxy_config_notify_publish_state_changed(LinphoneProxyConfig *cfg, LinphonePublishState state) { - + if (cfg->presence_publish_event != NULL) { switch (state) { case LinphonePublishCleared: linphone_proxy_config_set_etag(cfg,NULL); + BCTBX_NO_BREAK; case LinphonePublishError: linphone_event_unref(cfg->presence_publish_event); cfg->presence_publish_event = NULL; @@ -1559,7 +1561,7 @@ void linphone_proxy_config_notify_publish_state_changed(LinphoneProxyConfig *cfg break; default: break; - + } } } From c38a2e0c771fe7e88eb10aad954d93a1084e02c8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 19 Mar 2018 17:52:34 +0100 Subject: [PATCH 31/32] Fix crash when trying to cancel a non-existing INVITE transaction. --- src/conference/session/call-session.cpp | 10 ++++++---- src/sal/call-op.cpp | 10 +++++++++- src/sal/call-op.h | 4 ++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 2b6d0da8d..a11a4ed1d 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -821,8 +821,9 @@ void CallSessionPrivate::repairIfBroken () { case CallSession::State::Pausing: if (op->dialog_request_pending()) { // Need to cancel first re-INVITE as described in section 5.5 of RFC 6141 - op->cancel_invite(); - reinviteOnCancelResponseRequested = true; + if (op->cancel_invite() == 0){ + reinviteOnCancelResponseRequested = true; + } } break; case CallSession::State::StreamsRunning: @@ -840,8 +841,9 @@ void CallSessionPrivate::repairIfBroken () { break; case CallSession::State::OutgoingInit: case CallSession::State::OutgoingProgress: - op->cancel_invite(); - reinviteOnCancelResponseRequested = true; + if (op->cancel_invite() == 0){ + reinviteOnCancelResponseRequested = true; + } break; case CallSession::State::OutgoingEarlyMedia: case CallSession::State::OutgoingRinging: diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index a73c021ea..936eb983b 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -1120,9 +1120,15 @@ int SalCallOp::update(const char *subject, bool_t no_user_consent) { return -1; } -void SalCallOp::cancel_invite_with_info(const SalErrorInfo *info) { +int SalCallOp::cancel_invite_with_info(const SalErrorInfo *info) { belle_sip_request_t* cancel; ms_message("Cancelling INVITE request from [%s] to [%s] ",get_from(), get_to()); + + if (this->pending_client_trans == NULL){ + ms_warning("There is no transaction to cancel."); + return -1; + } + cancel = belle_sip_client_transaction_create_cancel(this->pending_client_trans); if (cancel){ if (info != NULL){ @@ -1130,6 +1136,7 @@ void SalCallOp::cancel_invite_with_info(const SalErrorInfo *info) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(cancel),BELLE_SIP_HEADER(reason)); } send_request(cancel); + return 0; }else if (this->dialog){ belle_sip_dialog_state_t state = belle_sip_dialog_get_state(this->dialog);; /*case where the response received is invalid (could not establish a dialog), but the transaction is not cancellable @@ -1145,6 +1152,7 @@ void SalCallOp::cancel_invite_with_info(const SalErrorInfo *info) { break; } } + return -1; } SalMediaDescription *SalCallOp::get_final_media_description() { diff --git a/src/sal/call-op.h b/src/sal/call-op.h index 414a808b6..fea958e6d 100644 --- a/src/sal/call-op.h +++ b/src/sal/call-op.h @@ -45,8 +45,8 @@ public: int decline(SalReason reason, const char *redirection /*optional*/); int decline_with_error_info(const SalErrorInfo *info, const SalAddress *redirectionAddr /*optional*/); int update(const char *subject, bool_t no_user_consent); - void cancel_invite() {cancel_invite_with_info(NULL);} - void cancel_invite_with_info(const SalErrorInfo *info); + int cancel_invite() { return cancel_invite_with_info(NULL);} + int cancel_invite_with_info(const SalErrorInfo *info); int refer(const char *refer_to_); int refer_with_replaces(SalCallOp *other_call_op); int set_referer(SalCallOp *refered_call); From be9a245657270e7f7208f8a10d67d684c13a8ba5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 18 Sep 2017 21:10:57 +0200 Subject: [PATCH 32/32] fix compilation with NDK > 14 (cherry-picked from master, commit f28d968 .) --- tester/log_collection_tester.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tester/log_collection_tester.c b/tester/log_collection_tester.c index 6027e7d13..b81d43449 100644 --- a/tester/log_collection_tester.c +++ b/tester/log_collection_tester.c @@ -28,9 +28,14 @@ #include #endif +#ifdef __ANDROID__ +#include "android/api-level.h" +#endif /*getline is POSIX 2008, not available on many systems.*/ -#if (defined(__ANDROID__) && !defined(__LP64__)) || defined(_WIN32) || defined(__QNX__) + +/*It is declared since NDK14 unified headers, that can be detected by the presence of __ANDROID_API_O__ define*/ +#if (defined(__ANDROID__) && __ANDROID_API__ <= 16) || defined(_WIN32) || defined(__QNX__) /* This code is public domain -- Will Hartung 4/9/09 */ static ssize_t getline(char **lineptr, size_t *n, FILE *stream) { char *bufptr = NULL;