diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 836d2b8a8..0143be751 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -245,18 +245,6 @@ static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const L return FALSE; } -static bool_t already_an_outgoing_call_pending(LinphoneCore *lc){ - MSList *elem; - for(elem=lc->calls;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall*)elem->data; - if (call->state==LinphoneCallOutgoingInit - || call->state==LinphoneCallOutgoingProgress - || call->state==LinphoneCallOutgoingRinging){ - return TRUE; - } - } - return FALSE; -} static void call_received(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); @@ -264,9 +252,9 @@ static void call_received(SalOp *h){ char *alt_contact; LinphoneAddress *from_addr=NULL; LinphoneAddress *to_addr=NULL; - /*this mode is deprcated because probably useless*/ - bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",FALSE); + LinphoneAddress *from_address_to_search_if_me=NULL; /*address used to know if I'm the caller*/ SalMediaDescription *md; + const char * p_asserted_id; /* first check if we can answer successfully to this invite */ if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) { @@ -300,9 +288,9 @@ static void call_received(SalOp *h){ sal_op_release(h); return; } + p_asserted_id = sal_custom_header_find(sal_op_get_recv_custom_header(h),"P-Asserted-Identity"); /*in some situation, better to trust the network rather than the UAC*/ if (lp_config_get_int(lc->config,"sip","call_logs_use_asserted_id_instead_of_from",0)) { - const char * p_asserted_id = sal_custom_header_find(sal_op_get_recv_custom_header(h),"P-Asserted-Identity"); LinphoneAddress *p_asserted_id_addr; if (!p_asserted_id) { ms_warning("No P-Asserted-Identity header found so cannot use it for op [%p] instead of from",h); @@ -321,13 +309,26 @@ static void call_received(SalOp *h){ from_addr=linphone_address_new(sal_op_get_from(h)); to_addr=linphone_address_new(sal_op_get_to(h)); - if ((already_a_call_with_remote_address(lc,from_addr) && prevent_colliding_calls) || already_an_outgoing_call_pending(lc)){ - ms_warning("Receiving a call while one is initiated, refusing this one with busy message."); + if (sal_op_get_privacy(h) == SalPrivacyNone) { + from_address_to_search_if_me=linphone_address_clone(from_addr); + } else if (p_asserted_id) { + from_address_to_search_if_me = linphone_address_new(p_asserted_id); + } else { + ms_warning ("Hidden from identity, don't know if it's me"); + } + + if (from_address_to_search_if_me && already_a_call_with_remote_address(lc,from_address_to_search_if_me)){ + char *addr = linphone_address_as_string(from_addr); + ms_warning("Receiving a call while one with same address [%s] is initiated, refusing this one with busy message.",addr); sal_call_decline(h,SalReasonBusy,NULL); sal_op_release(h); linphone_address_destroy(from_addr); linphone_address_destroy(to_addr); + linphone_address_destroy(from_address_to_search_if_me); + ms_free(addr); return; + } else if (from_address_to_search_if_me) { + linphone_address_destroy(from_address_to_search_if_me); } call=linphone_call_new_incoming(lc,from_addr,to_addr,h); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 89c62000f..2d3efb6f0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3721,6 +3721,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, SalOp *replaced; SalMediaDescription *new_md; bool_t was_ringing=FALSE; + MSList * iterator; if (call==NULL){ //if just one call is present answer the only one ... @@ -3741,6 +3742,28 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, break; } + + for (iterator=ms_list_copy(linphone_core_get_calls(lc));iterator!=NULL;iterator=iterator->next) { + LinphoneCall *a_call=(LinphoneCall*)iterator->data; + if (a_call==call) continue; + switch(a_call->state){ + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + + ms_message("Already existing call [%p] in state [%s], canceling it before accepting new call [%p]" ,a_call + ,linphone_call_state_to_string(a_call->state) + ,call); + linphone_core_terminate_call(lc,a_call); + break; + default: + break; /*nothing to do*/ + } + + } + if (iterator) ms_list_free(iterator); + /* check if this call is supposed to replace an already running one*/ replaced=sal_call_get_replaces(call->op); if (replaced){ @@ -4138,9 +4161,17 @@ static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *rad * @ingroup call_control */ LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address){ + LinphoneCall *call=NULL; LinphoneAddress *raddr=linphone_address_new(remote_address); + if (raddr) { + call=linphone_core_get_call_by_remote_address2(lc, raddr); + linphone_address_unref(raddr); + } + return call; +} +LinphoneCall *linphone_core_get_call_by_remote_address2(LinphoneCore *lc, LinphoneAddress *raddr){ MSList *elem=ms_list_find_custom(lc->calls,(int (*)(const void*,const void *))remote_address_compare,raddr); - linphone_address_unref(raddr); + if (elem) return (LinphoneCall*) elem->data; return NULL; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index cfeb48e7e..22788939a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2237,6 +2237,17 @@ LINPHONE_PUBLIC LinphoneCallParams *linphone_core_create_call_params(LinphoneCor LINPHONE_PUBLIC LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address); +/** + * Get the call with the remote_address specified + * @param lc + * @param remote_address + * @return the LinphoneCall of the call if found + * + * @ingroup call_control + */ +LINPHONE_PUBLIC LinphoneCall *linphone_core_get_call_by_remote_address2(LinphoneCore *lc, LinphoneAddress *remote_address); + + /** * Send the specified dtmf. * diff --git a/tester/call_tester.c b/tester/call_tester.c index c1e234e4c..6b9fd035b 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -207,6 +207,7 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr LinphoneCallParams *caller_params = caller_test_params->base; LinphoneCallParams *callee_params = callee_test_params->base; bool_t did_receive_call; + LinphoneCall *callee_call=NULL; setup_sdp_handling(caller_test_params, caller_mgr); setup_sdp_handling(callee_test_params, callee_mgr); @@ -229,7 +230,8 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr if (!did_receive_call) return 0; - CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); + if (linphone_core_get_calls_nb(callee_mgr->lc)<=1) + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,initial_caller.number_of_LinphoneCallOutgoingProgress+1); @@ -247,6 +249,8 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); + callee_call=linphone_core_get_call_by_remote_address2(callee_mgr->lc,caller_mgr->identity); + if(!linphone_core_get_current_call(caller_mgr->lc) || !linphone_core_get_current_call(callee_mgr->lc) || !linphone_core_get_current_call_remote_address(callee_mgr->lc)) { return 0; } else if (caller_mgr->identity){ @@ -256,21 +260,23 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr if (linphone_call_params_get_privacy(linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc))) == LinphonePrivacyNone) { /*don't check in case of p asserted id*/ if (!lp_config_get_int(callee_mgr->lc->config,"sip","call_logs_use_asserted_id_instead_of_from",0)) - CU_ASSERT_TRUE(linphone_address_weak_equal(callee_from,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + CU_ASSERT_TRUE(linphone_address_weak_equal(callee_from,linphone_call_get_remote_address(callee_call))); } else { - CU_ASSERT_FALSE(linphone_address_weak_equal(callee_from,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + CU_ASSERT_FALSE(linphone_address_weak_equal(callee_from,linphone_call_get_remote_address(linphone_core_get_current_call(callee_mgr->lc)))); } linphone_address_destroy(callee_from); } + + if (callee_params){ - linphone_core_accept_call_with_params(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc),callee_params); + linphone_core_accept_call_with_params(callee_mgr->lc,callee_call,callee_params); }else if (build_callee_params){ - LinphoneCallParams *default_params=linphone_core_create_call_params(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); + LinphoneCallParams *default_params=linphone_core_create_call_params(callee_mgr->lc,callee_call); ms_message("Created default call params with video=%i", linphone_call_params_video_enabled(default_params)); - linphone_core_accept_call_with_params(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc),default_params); + linphone_core_accept_call_with_params(callee_mgr->lc,callee_call,default_params); linphone_call_params_destroy(default_params); }else{ - linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); + linphone_core_accept_call(callee_mgr->lc,callee_call); } CU_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); @@ -291,7 +297,7 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr || (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionDTLS) /*also take care of caller policy*/ ) wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_callee.number_of_LinphoneCallEncryptedOn+1); { - const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee_mgr->lc)); + const LinphoneCallParams* call_param = linphone_call_get_current_params(callee_call); CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc)); call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc)); CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc)); @@ -902,6 +908,21 @@ static void early_declined_call(void) { linphone_core_manager_destroy(pauline); } +static void call_busy_when_calling_self(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCall *out_call=linphone_core_invite_address(marie->lc,marie->identity); + linphone_call_ref(out_call); + + /*wait until flexisip transfers the busy...*/ + CU_ASSERT_TRUE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCallError,1,33000)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); + + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonBusy); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); +} + + static void call_declined(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -4040,6 +4061,7 @@ test_t call_tests[] = { { "Early cancelled call", early_cancelled_call}, { "Call with DNS timeout", call_with_dns_time_out }, { "Cancelled ringing call", cancelled_ringing_call }, + { "Call busy when calling self", call_busy_when_calling_self}, { "Simple call", simple_call }, { "Call with timeouted bye", call_with_timeouted_bye }, { "Direct call over IPv6", direct_call_over_ipv6}, diff --git a/tester/multi_call.c b/tester/multi_call.c index 14f0db9d1..5f580118c 100644 --- a/tester/multi_call.c +++ b/tester/multi_call.c @@ -115,6 +115,70 @@ static void call_waiting_indication_with_privacy(void) { call_waiting_indication_with_param(TRUE); } +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_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + MSList* lcs; + LinphoneCallParams *laure_params=linphone_core_create_default_call_parameters(laure->lc); + LinphoneCallParams *marie_params=linphone_core_create_default_call_parameters(marie->lc); + + lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + + if (state==LinphoneCallOutgoingRinging || state==LinphoneCallOutgoingEarlyMedia) { + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(marie->lc,pauline->identity,marie_params)); + + CU_ASSERT_TRUE(wait_for(marie->lc + ,pauline->lc + ,&pauline->stat.number_of_LinphoneCallIncomingReceived + ,1)); + + if (state==LinphoneCallOutgoingEarlyMedia) + linphone_core_accept_early_media(pauline->lc,linphone_core_get_current_call(pauline->lc)); + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE(wait_for(marie->lc + ,pauline->lc + ,state==LinphoneCallOutgoingEarlyMedia?&marie->stat.number_of_LinphoneCallOutgoingEarlyMedia:&marie->stat.number_of_LinphoneCallOutgoingRinging + ,1)); + } else if (state==LinphoneCallOutgoingProgress) { + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(marie->lc,pauline->identity)); + } else { + ms_error("Unsupported state"); + return; + } + + CU_ASSERT_TRUE(call_with_caller_params(laure,marie,laure_params)); + + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000)); + + + linphone_core_terminate_all_calls(marie->lc); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000)); + + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} +static void incoming_call_accepted_when_outgoing_call_in_progress(void) { + incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallOutgoingProgress); +} +static void incoming_call_accepted_when_outgoing_call_in_outgoing_ringing(void) { + incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallOutgoingRinging); +} +static void incoming_call_accepted_when_outgoing_call_in_outgoing_ringing_early_media(void) { + incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallOutgoingEarlyMedia); +} + static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, LinphoneCoreManager* laure) { stats initial_marie_stat; @@ -437,7 +501,10 @@ test_t multi_call_tests[] = { { "Simple call transfer", simple_call_transfer }, { "Unattended call transfer", unattended_call_transfer }, { "Unattended call transfer with error", unattended_call_transfer_with_error }, - { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call } + { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }, + { "Incoming call accepted when outgoing call in progress",incoming_call_accepted_when_outgoing_call_in_progress}, + { "Incoming call accepted when outgoing call in outgoing ringing",incoming_call_accepted_when_outgoing_call_in_outgoing_ringing}, + { "Incoming call accepted when outgoing call in outgoing ringing early media",incoming_call_accepted_when_outgoing_call_in_outgoing_ringing_early_media}, }; test_suite_t multi_call_test_suite = {