From abe5a1943107edefad56882606100b5e48a80f90 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 6 Nov 2014 17:25:03 +0100 Subject: [PATCH] Do not crash if SDP could not be parsed and had some unit tests. - avoid crash if missing SDP in REINVITE ACK - resume previous media parametrs instead of aborting call in case of invalid SDP in REINVITE --- coreapi/bellesip_sal/sal_impl.c | 8 +- coreapi/bellesip_sal/sal_impl.h | 2 + coreapi/bellesip_sal/sal_op_call.c | 26 +++- coreapi/bellesip_sal/sal_op_impl.c | 6 +- coreapi/callbacks.c | 20 ++- coreapi/linphonecall.c | 5 +- include/sal/sal.h | 6 + tester/call_tester.c | 221 ++++++++++++++++++++++++----- tester/liblinphone_tester.h | 10 ++ 9 files changed, 255 insertions(+), 49 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 6c2e84483..875f09ad0 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -953,7 +953,7 @@ static void make_supported_header(Sal *sal){ char *alltags=NULL; size_t buflen=64; size_t written=0; - + if (sal->supported){ belle_sip_object_unref(sal->supported); sal->supported=NULL; @@ -1003,7 +1003,7 @@ void sal_add_supported_tag(Sal *ctx, const char* tag){ ctx->supported_tags=ms_list_append(ctx->supported_tags,ms_strdup(tag)); make_supported_header(ctx); } - + } void sal_remove_supported_tag(Sal *ctx, const char* tag){ @@ -1101,3 +1101,7 @@ void sal_enable_sip_update_method(Sal *ctx,bool_t value) { ctx->enable_sip_update=value; } +void sal_default_enable_sdp_removal(Sal *sal, bool_t enable) { + if (enable) ms_message("Enabling SDP removal feature by default for all new SalOp in Sal[%p]!", sal); + sal->default_sdp_removal = enable; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 07124feb3..ed19b19e3 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -53,6 +53,7 @@ struct Sal{ bool_t enable_test_features; bool_t no_initial_route; bool_t enable_sip_update; /*true by default*/ + bool_t default_sdp_removal; }; typedef enum SalOpState { @@ -107,6 +108,7 @@ struct SalOp{ bool_t call_released; bool_t manual_refresher; bool_t has_auth_pending; + bool_t sdp_removal; /* do not add SDP in outgoing INVITE and remove it from incoming INVITE */ int auth_requests; /*number of auth requested for this op*/ }; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 1530a0165..c2e9a4a64 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" #include "offeranswer.h" -static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error); +static int extract_sdp(SalOp* op,belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error); /*used for calls terminated before creation of a dialog*/ static void call_set_released(SalOp* op){ @@ -41,7 +41,12 @@ static void sdp_process(SalOp *h){ ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); if (h->result){ sal_media_description_unref(h->result); + h->result = NULL; } + + /* if SDP was invalid */ + if (h->base.remote_media == NULL) return; + h->result=sal_media_description_new(); if (h->sdp_offering){ offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result); @@ -162,13 +167,14 @@ static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { sal_media_description_unref(op->base.remote_media); op->base.remote_media=NULL; } - if (extract_sdp(BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) { + if (extract_sdp(op,BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) { if (sdp){ op->base.remote_media=sal_media_description_new(); sdp_to_media_description(sdp,op->base.remote_media); - if (op->base.local_media) sdp_process(op); }/*if no sdp in response, what can we do ?*/ } + /* process sdp in any case to reset result media description*/ + if (op->base.local_media) sdp_process(op); } static void cancelling_invite(SalOp* op ){ @@ -378,8 +384,16 @@ static void unsupported_method(belle_sip_server_transaction_t* server_transactio * If body was present is not a SDP or parsing of SDP failed, -1 is returned and SalReason is set appropriately. * **/ -static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) { +static int extract_sdp(SalOp *op, belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) { belle_sip_header_content_type_t* content_type=belle_sip_message_get_header_by_type(message,belle_sip_header_content_type_t); + + if (op&&op->sdp_removal){ + ms_error("Removed willingly SDP because sal_call_enable_sdp_removal was set to TRUE."); + *session_desc=NULL; + *error=SalReasonNotAcceptable; + return -1; + } + if (content_type){ if (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 && strcmp("sdp",belle_sip_header_content_type_get_subtype(content_type))==0) { @@ -409,7 +423,7 @@ static int process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { belle_sdp_session_description_t* sdp; int err=0; SalReason reason; - if (extract_sdp(BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) { + if (extract_sdp(op,BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) { if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); @@ -532,7 +546,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t if (strcmp("ACK",method)==0) { if (op->sdp_offering){ SalReason reason; - if (extract_sdp(BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){ + if (extract_sdp(op,BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){ if (sdp){ if (op->base.remote_media) sal_media_description_unref(op->base.remote_media); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index ed18f52d0..2be6ce4eb 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -18,7 +18,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sal_impl.h" - /*create an operation */ SalOp * sal_op_new(Sal *sal){ SalOp *op=ms_new0(SalOp,1); @@ -26,6 +25,7 @@ SalOp * sal_op_new(Sal *sal){ op->type=SalOpUnknown; op->privacy=SalPrivacyNone; op->manual_refresher=FALSE;/*tells that requests with expiry (SUBSCRIBE, PUBLISH) will be automatically refreshed*/ + op->sdp_removal=sal->default_sdp_removal; sal_op_ref(op); return op; } @@ -770,3 +770,7 @@ void sal_op_stop_refreshing(SalOp *op){ } } +void sal_call_enable_sdp_removal(SalOp *h, bool_t enable) { + if (enable) ms_message("Enabling SDP removal feature for SalOp[%p]!", h); + h->sdp_removal = enable; +} diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index bb6b5b9fb..2776a90ec 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -448,7 +448,7 @@ static void call_accepted(SalOp *op){ default: break; } - + if (md && !sal_media_description_empty(md) && !linphone_core_incompatible_security(lc,md)){ linphone_call_update_remote_session_id_and_ver(call); if (sal_media_description_has_dir(md,SalStreamSendOnly) || @@ -498,9 +498,21 @@ static void call_accepted(SalOp *op){ if (update_state) linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running"); } }else{ - /*send a bye*/ - ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); - linphone_core_abort_call(lc,call,_("Incompatible, check codecs or security settings...")); + switch (call->prevstate){ + /*send a bye only in case of outgoing state*/ + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + ms_error("Incompatible SDP offer received in 200 OK, need to abort the call"); + linphone_core_abort_call(lc,call,_("Incompatible, check codecs or security settings...")); + break; + /*otherwise we are able to resume previous state*/ + default: + ms_message("Incompatible SDP offer received in 200 OK, restoring previous state[%s]",linphone_call_state_to_string(call->prevstate)); + linphone_call_set_state(call,call->prevstate,_("Incompatible media parameters.")); + break; + } } } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 7608c47ba..98ab0b47d 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1879,11 +1879,14 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca OrtpRtcpXrConfiguration currentconfig; const SalStreamDescription *localstream; const SalStreamDescription *remotestream; + SalMediaDescription *remotedesc = sal_call_get_remote_media_description(call->op); + + if (!remotedesc) return; localstream = sal_media_description_find_best_stream(call->localdesc, type); if (!localstream) return; localconfig = &localstream->rtcp_xr; - remotestream = sal_media_description_find_best_stream(sal_call_get_remote_media_description(call->op), type); + remotestream = sal_media_description_find_best_stream(remotedesc, type); if (!remotestream) return; remoteconfig = &remotestream->rtcp_xr; diff --git a/include/sal/sal.h b/include/sal/sal.h index 8f81f320d..74f1780bf 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -639,6 +639,12 @@ bool_t sal_call_autoanswer_asked(SalOp *op); void sal_call_send_vfu_request(SalOp *h); int sal_call_is_offerer(const SalOp *h); int sal_call_notify_refer_state(SalOp *h, SalOp *newcall); +/* Call test API */ +/*willingly fails to parse SDP from received packets (INVITE and/or ACK) if value=true */ +/* First version: for all new SalOp created (eg. each incoming or outgoing call). Do not forget to reset previous value when you are done!*/ +void sal_default_enable_sdp_removal(Sal* h, bool_t enable) ; +/* Second version: for a specific call*/ +void sal_call_enable_sdp_removal(SalOp *h, bool_t enable) ; /*Registration*/ int sal_register(SalOp *op, const char *proxy, const char *from, int expires); diff --git a/tester/call_tester.c b/tester/call_tester.c index f1a92a07c..512768725 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -171,13 +171,21 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana bool_t call_with_params2(LinphoneCoreManager* caller_mgr ,LinphoneCoreManager* callee_mgr - , const LinphoneCallParams *caller_params - , const LinphoneCallParams *callee_params, bool_t build_callee_params) { + , const LinphoneCallTestParams *caller_test_params + , const LinphoneCallTestParams *callee_test_params + , bool_t build_callee_params) { int retry=0; stats initial_caller=caller_mgr->stat; stats initial_callee=callee_mgr->stat; bool_t result=FALSE; char hellopath[256]; + LinphoneCallParams *caller_params = caller_test_params->base; + LinphoneCallParams *callee_params = callee_test_params->base; + bool_t did_received_call; + + sal_default_enable_sdp_removal(caller_mgr->lc->sal, caller_test_params->sdp_removal); + sal_default_enable_sdp_removal(callee_mgr->lc->sal, callee_test_params->sdp_removal); + /*use playfile for callee to avoid locking on capture card*/ linphone_core_use_files (callee_mgr->lc,TRUE); snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); @@ -188,12 +196,21 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc,callee_mgr->identity,caller_params)); } + /*linphone_core_invite(caller_mgr->lc,"pauline");*/ - CU_ASSERT_TRUE(wait_for(callee_mgr->lc - ,caller_mgr->lc - ,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived - ,initial_callee.number_of_LinphoneCallIncomingReceived+1)); + did_received_call = wait_for(callee_mgr->lc + ,caller_mgr->lc + ,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived + ,initial_callee.number_of_LinphoneCallIncomingReceived+1); + CU_ASSERT_EQUAL(did_received_call, !callee_test_params->sdp_removal); + + sal_default_enable_sdp_removal(caller_mgr->lc->sal, FALSE); + sal_default_enable_sdp_removal(callee_mgr->lc->sal, FALSE); + + if (!did_received_call) return 0; + + 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); @@ -212,9 +229,9 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); - 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)) + 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 { + } else { LinphoneAddress* callee_from=linphone_address_clone(caller_mgr->identity); linphone_address_set_port(callee_from,0); /*remove port because port is never present in from header*/ @@ -264,9 +281,19 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr bool_t call_with_params(LinphoneCoreManager* caller_mgr ,LinphoneCoreManager* callee_mgr - , const LinphoneCallParams *caller_params - , const LinphoneCallParams *callee_params){ - return call_with_params2(caller_mgr,callee_mgr,caller_params,callee_params,FALSE); + ,const LinphoneCallParams *caller_params + ,const LinphoneCallParams *callee_params){ + LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; + caller_test_params.base = (LinphoneCallParams*)caller_params; + callee_test_params.base = (LinphoneCallParams*)caller_params; + return call_with_params2(caller_mgr,callee_mgr,&caller_test_params,&callee_test_params,FALSE); +} + +bool_t call_with_test_params(LinphoneCoreManager* caller_mgr + ,LinphoneCoreManager* callee_mgr + ,const LinphoneCallTestParams *caller_test_params + ,const LinphoneCallTestParams *callee_test_params){ + return call_with_params2(caller_mgr,callee_mgr,caller_test_params,callee_test_params,FALSE); } bool_t call_with_caller_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr, const LinphoneCallParams *params) { @@ -1137,12 +1164,10 @@ static void call_paused_resumed_from_callee(void) { } #ifdef VIDEO_ENABLED -static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) { +static LinphoneCall* setup_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) { LinphoneVideoPolicy caller_policy; LinphoneCallParams* callee_params; LinphoneCall* call_obj; - stats initial_caller_stat=caller->stat; - stats initial_callee_stat=callee->stat; if (!linphone_core_get_current_call(callee->lc) || linphone_call_get_state(linphone_core_get_current_call(callee->lc)) != LinphoneCallStreamsRunning || !linphone_core_get_current_call(caller->lc) || linphone_call_get_state(linphone_core_get_current_call(caller->lc)) != LinphoneCallStreamsRunning ) { @@ -1158,14 +1183,20 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) linphone_core_enable_video_display(caller->lc, FALSE); linphone_core_set_video_policy(caller->lc,&caller_policy); - - if ((call_obj = linphone_core_get_current_call(callee->lc))) { callee_params = linphone_call_params_copy(linphone_call_get_current_params(call_obj)); /*add video*/ linphone_call_params_enable_video(callee_params,TRUE); linphone_core_update_call(callee->lc,call_obj,callee_params); + } + return call_obj; +} +static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) { + stats initial_caller_stat=caller->stat; + stats initial_callee_stat=callee->stat; + LinphoneCall *call_obj; + if ((call_obj=setup_video(caller, callee))){ CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallUpdatedByRemote,initial_caller_stat.number_of_LinphoneCallUpdatedByRemote+1)); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); @@ -1320,11 +1351,10 @@ static void srtp_call_with_several_video_switches(void) { static void call_with_declined_video_base(bool_t using_policy) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCallParams* callee_params=NULL; - LinphoneCallParams* caller_params; LinphoneCall* marie_call; LinphoneCall* pauline_call; LinphoneVideoPolicy marie_policy, pauline_policy; + LinphoneCallTestParams caller_test_params, callee_test_params; linphone_core_enable_video_capture(marie->lc, TRUE); linphone_core_enable_video_display(marie->lc, TRUE); linphone_core_enable_video_capture(pauline->lc, TRUE); @@ -1340,19 +1370,19 @@ static void call_with_declined_video_base(bool_t using_policy) { linphone_core_set_video_policy(pauline->lc,&pauline_policy); } - caller_params=linphone_core_create_default_call_parameters(pauline->lc); + caller_test_params.base=linphone_core_create_default_call_parameters(pauline->lc); if (!using_policy) - linphone_call_params_enable_video(caller_params,TRUE); + linphone_call_params_enable_video(caller_test_params.base,TRUE); if (!using_policy){ - callee_params=linphone_core_create_default_call_parameters(marie->lc); - linphone_call_params_enable_video(callee_params,FALSE); + callee_test_params.base=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(callee_test_params.base,FALSE); } - CU_ASSERT_TRUE(call_with_params2(pauline,marie,caller_params,callee_params,using_policy)); + CU_ASSERT_TRUE(call_with_params2(pauline,marie,&caller_test_params,&callee_test_params,using_policy)); - linphone_call_params_destroy(caller_params); - if (callee_params) linphone_call_params_destroy(callee_params); + linphone_call_params_destroy(caller_test_params.base); + if (callee_test_params.base) linphone_call_params_destroy(callee_test_params.base); marie_call=linphone_core_get_current_call(marie->lc); pauline_call=linphone_core_get_current_call(pauline->lc); @@ -1375,8 +1405,7 @@ static void call_with_declined_video_using_policy(void) { } static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* marie, bool_t using_policy) { - LinphoneCallParams* callee_params=NULL; - LinphoneCallParams* caller_params; + LinphoneCallTestParams caller_test_params, callee_test_params; LinphoneCall* marie_call; LinphoneCall* pauline_call; LinphoneVideoPolicy marie_policy, pauline_policy; @@ -1395,21 +1424,21 @@ static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* ma linphone_core_set_video_policy(pauline->lc,&pauline_policy); } - caller_params=linphone_core_create_default_call_parameters(pauline->lc); + caller_test_params.base=linphone_core_create_default_call_parameters(pauline->lc); if (!using_policy) - linphone_call_params_enable_video(caller_params,TRUE); + linphone_call_params_enable_video(caller_test_params.base,TRUE); if (!using_policy){ - callee_params=linphone_core_create_default_call_parameters(marie->lc); - linphone_call_params_enable_video(callee_params,TRUE); + callee_test_params.base=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(callee_test_params.base,TRUE); } - CU_ASSERT_TRUE(call_with_params2(pauline,marie,caller_params,callee_params,using_policy)); + CU_ASSERT_TRUE(call_with_params2(pauline,marie,&caller_test_params,&callee_test_params,using_policy)); marie_call=linphone_core_get_current_call(marie->lc); pauline_call=linphone_core_get_current_call(pauline->lc); - linphone_call_params_destroy(caller_params); - if (callee_params) linphone_call_params_destroy(callee_params); + linphone_call_params_destroy(caller_test_params.base); + if (callee_test_params.base) linphone_call_params_destroy(callee_test_params.base); if (marie_call && pauline_call ) { CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); @@ -3198,6 +3227,124 @@ static void call_log_from_taken_from_p_asserted_id(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } + +static void incoming_invite_without_sdp() { + LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); + LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; + + callee_test_params.sdp_removal = TRUE; + CU_ASSERT_FALSE(call_with_params2(caller,callee,&caller_test_params, &callee_test_params, FALSE)); + + CU_ASSERT_PTR_NULL(linphone_core_get_current_call(callee->lc)); + CU_ASSERT_EQUAL(caller->stat.number_of_LinphoneCallError,1); + /*call will be drop before presented to the application, because it is invalid*/ + CU_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallIncomingReceived,0); + + linphone_core_manager_destroy(callee); + linphone_core_manager_destroy(caller); +} + +static void outgoing_invite_without_sdp() { + LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); + LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; + + caller_test_params.sdp_removal = TRUE; + CU_ASSERT_FALSE(call_with_params2(caller,callee,&caller_test_params, &callee_test_params, FALSE)); + + CU_ASSERT_PTR_NULL(linphone_core_get_current_call(callee->lc)); + CU_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallIncomingReceived,1); + CU_ASSERT_EQUAL(caller->stat.number_of_LinphoneCallError,1); + // actually callee does not receive error, because it just get a BYE from the other part + CU_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallError,0); + CU_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallEnd,1); + + linphone_core_manager_destroy(callee); + linphone_core_manager_destroy(caller); +} + +static void incoming_reinvite_without_ack_sdp() { +#ifdef VIDEO_ENABLED + LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); + LinphoneCall * inc_call; + CU_ASSERT_TRUE(call(caller,callee)); + inc_call = linphone_core_get_current_call(callee->lc); + + CU_ASSERT_PTR_NOT_NULL(inc_call); + if (inc_call) { + const LinphoneCallParams *caller_params; + stats initial_caller_stat=caller->stat; + stats initial_callee_stat=callee->stat; + sal_call_enable_sdp_removal(inc_call->op, TRUE); + CU_ASSERT_PTR_NOT_NULL(setup_video(caller, callee)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning)); + /*Basically the negotiation failed but since the call was already running, we expect it to restore to + the previous state so error stats should not be changed*/ + CU_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallError,initial_callee_stat.number_of_LinphoneCallError); + /*and remote should have received an update notification*/ + CU_ASSERT_EQUAL(caller->stat.number_of_LinphoneCallUpdatedByRemote,initial_caller_stat.number_of_LinphoneCallUpdatedByRemote+1); + + + CU_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); + caller_params = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,(int*)&caller_params->has_video,FALSE)); + + sal_call_enable_sdp_removal(inc_call->op, FALSE); + } + linphone_core_terminate_all_calls(caller->lc); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(callee); + linphone_core_manager_destroy(caller); +#else + ms_warning("not tested because video not available"); +#endif +} + +static void outgoing_reinvite_without_ack_sdp() { +#ifdef VIDEO_ENABLED + LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); + LinphoneCall * out_call; + CU_ASSERT_TRUE(call(caller,callee)); + out_call = linphone_core_get_current_call(caller->lc); + + CU_ASSERT_PTR_NOT_NULL(out_call); + if (out_call) { + stats initial_caller_stat=caller->stat; + stats initial_callee_stat=callee->stat; + sal_call_enable_sdp_removal(out_call->op, TRUE); + CU_ASSERT_PTR_NOT_NULL(setup_video(caller, callee)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning)); + /*Basically the negotiation failed but since the call was already running, we expect it to restore to + the previous state so error stats should not be changed*/ + CU_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallError,initial_callee_stat.number_of_LinphoneCallError); + /*and remote should not have received any update notification*/ + CU_ASSERT_EQUAL(caller->stat.number_of_LinphoneCallUpdatedByRemote,initial_caller_stat.number_of_LinphoneCallUpdatedByRemote); + + CU_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); + CU_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); + + sal_call_enable_sdp_removal(out_call->op, FALSE); + } + linphone_core_terminate_all_calls(caller->lc); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(callee); + linphone_core_manager_destroy(caller); +#else + ms_warning("not tested because video not available"); +#endif +} + test_t call_tests[] = { { "Early declined call", early_declined_call }, { "Call declined", call_declined }, @@ -3298,7 +3445,11 @@ test_t call_tests[] = { { "Call with in-dialog codec change", call_with_in_dialog_codec_change }, { "Call with in-dialog codec change no sdp", call_with_in_dialog_codec_change_no_sdp }, { "Call with custom supported tags", call_with_custom_supported_tags }, - { "Call log from taken from asserted id",call_log_from_taken_from_p_asserted_id} + { "Call log from taken from asserted id",call_log_from_taken_from_p_asserted_id}, + { "Incoming INVITE without SDP",incoming_invite_without_sdp}, + { "Outgoing INVITE without SDP",outgoing_invite_without_sdp}, + { "Incoming REINVITE without SDP in ACK",incoming_reinvite_without_ack_sdp}, + { "Outgoing REINVITE without SDP in ACK",outgoing_reinvite_without_ack_sdp}, }; test_suite_t call_test_suite = { diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index a1ad60ec0..d8ecb1987 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -212,6 +212,11 @@ typedef struct _LinphoneCoreManager { bool_t decline_subscribe; } LinphoneCoreManager; +typedef struct _LinphoneCallTestParams { + LinphoneCallParams *base; + bool_t sdp_removal; +} LinphoneCallTestParams; + LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies); LinphoneCoreManager* linphone_core_manager_new(const char* rc_file); void linphone_core_manager_stop(LinphoneCoreManager *mgr); @@ -246,6 +251,11 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr ,LinphoneCoreManager* callee_mgr , const LinphoneCallParams *caller_params , const LinphoneCallParams *callee_params); +bool_t call_with_test_params(LinphoneCoreManager* caller_mgr + ,LinphoneCoreManager* callee_mgr + ,const LinphoneCallTestParams *caller_test_params + ,const LinphoneCallTestParams *callee_test_params); + bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr); void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2); stats * get_stats(LinphoneCore *lc);